@uniformdev/canvas 20.50.2-alpha.149 → 20.50.2-alpha.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,9 +8,6 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __typeError = (msg) => {
9
9
  throw TypeError(msg);
10
10
  };
11
- var __commonJS = (cb, mod) => function __require() {
12
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
- };
14
11
  var __export = (target, all) => {
15
12
  for (var name in all)
16
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -36,358 +33,9 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
36
33
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
37
34
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
38
35
 
39
- // ../../node_modules/.pnpm/yocto-queue@0.1.0/node_modules/yocto-queue/index.js
40
- var require_yocto_queue = __commonJS({
41
- "../../node_modules/.pnpm/yocto-queue@0.1.0/node_modules/yocto-queue/index.js"(exports2, module2) {
42
- "use strict";
43
- var Node = class {
44
- /// value;
45
- /// next;
46
- constructor(value) {
47
- this.value = value;
48
- this.next = void 0;
49
- }
50
- };
51
- var Queue = class {
52
- // TODO: Use private class fields when targeting Node.js 12.
53
- // #_head;
54
- // #_tail;
55
- // #_size;
56
- constructor() {
57
- this.clear();
58
- }
59
- enqueue(value) {
60
- const node = new Node(value);
61
- if (this._head) {
62
- this._tail.next = node;
63
- this._tail = node;
64
- } else {
65
- this._head = node;
66
- this._tail = node;
67
- }
68
- this._size++;
69
- }
70
- dequeue() {
71
- const current = this._head;
72
- if (!current) {
73
- return;
74
- }
75
- this._head = this._head.next;
76
- this._size--;
77
- return current.value;
78
- }
79
- clear() {
80
- this._head = void 0;
81
- this._tail = void 0;
82
- this._size = 0;
83
- }
84
- get size() {
85
- return this._size;
86
- }
87
- *[Symbol.iterator]() {
88
- let current = this._head;
89
- while (current) {
90
- yield current.value;
91
- current = current.next;
92
- }
93
- }
94
- };
95
- module2.exports = Queue;
96
- }
97
- });
98
-
99
- // ../../node_modules/.pnpm/p-limit@3.1.0/node_modules/p-limit/index.js
100
- var require_p_limit = __commonJS({
101
- "../../node_modules/.pnpm/p-limit@3.1.0/node_modules/p-limit/index.js"(exports2, module2) {
102
- "use strict";
103
- var Queue = require_yocto_queue();
104
- var pLimit2 = (concurrency) => {
105
- if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
106
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
107
- }
108
- const queue = new Queue();
109
- let activeCount = 0;
110
- const next = () => {
111
- activeCount--;
112
- if (queue.size > 0) {
113
- queue.dequeue()();
114
- }
115
- };
116
- const run = async (fn, resolve, ...args) => {
117
- activeCount++;
118
- const result = (async () => fn(...args))();
119
- resolve(result);
120
- try {
121
- await result;
122
- } catch (e) {
123
- }
124
- next();
125
- };
126
- const enqueue = (fn, resolve, ...args) => {
127
- queue.enqueue(run.bind(null, fn, resolve, ...args));
128
- (async () => {
129
- await Promise.resolve();
130
- if (activeCount < concurrency && queue.size > 0) {
131
- queue.dequeue()();
132
- }
133
- })();
134
- };
135
- const generator = (fn, ...args) => new Promise((resolve) => {
136
- enqueue(fn, resolve, ...args);
137
- });
138
- Object.defineProperties(generator, {
139
- activeCount: {
140
- get: () => activeCount
141
- },
142
- pendingCount: {
143
- get: () => queue.size
144
- },
145
- clearQueue: {
146
- value: () => {
147
- queue.clear();
148
- }
149
- }
150
- });
151
- return generator;
152
- };
153
- module2.exports = pLimit2;
154
- }
155
- });
156
-
157
- // ../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/lib/retry_operation.js
158
- var require_retry_operation = __commonJS({
159
- "../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/lib/retry_operation.js"(exports2, module2) {
160
- "use strict";
161
- function RetryOperation(timeouts, options) {
162
- if (typeof options === "boolean") {
163
- options = { forever: options };
164
- }
165
- this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
166
- this._timeouts = timeouts;
167
- this._options = options || {};
168
- this._maxRetryTime = options && options.maxRetryTime || Infinity;
169
- this._fn = null;
170
- this._errors = [];
171
- this._attempts = 1;
172
- this._operationTimeout = null;
173
- this._operationTimeoutCb = null;
174
- this._timeout = null;
175
- this._operationStart = null;
176
- this._timer = null;
177
- if (this._options.forever) {
178
- this._cachedTimeouts = this._timeouts.slice(0);
179
- }
180
- }
181
- module2.exports = RetryOperation;
182
- RetryOperation.prototype.reset = function() {
183
- this._attempts = 1;
184
- this._timeouts = this._originalTimeouts.slice(0);
185
- };
186
- RetryOperation.prototype.stop = function() {
187
- if (this._timeout) {
188
- clearTimeout(this._timeout);
189
- }
190
- if (this._timer) {
191
- clearTimeout(this._timer);
192
- }
193
- this._timeouts = [];
194
- this._cachedTimeouts = null;
195
- };
196
- RetryOperation.prototype.retry = function(err) {
197
- if (this._timeout) {
198
- clearTimeout(this._timeout);
199
- }
200
- if (!err) {
201
- return false;
202
- }
203
- var currentTime = (/* @__PURE__ */ new Date()).getTime();
204
- if (err && currentTime - this._operationStart >= this._maxRetryTime) {
205
- this._errors.push(err);
206
- this._errors.unshift(new Error("RetryOperation timeout occurred"));
207
- return false;
208
- }
209
- this._errors.push(err);
210
- var timeout = this._timeouts.shift();
211
- if (timeout === void 0) {
212
- if (this._cachedTimeouts) {
213
- this._errors.splice(0, this._errors.length - 1);
214
- timeout = this._cachedTimeouts.slice(-1);
215
- } else {
216
- return false;
217
- }
218
- }
219
- var self = this;
220
- this._timer = setTimeout(function() {
221
- self._attempts++;
222
- if (self._operationTimeoutCb) {
223
- self._timeout = setTimeout(function() {
224
- self._operationTimeoutCb(self._attempts);
225
- }, self._operationTimeout);
226
- if (self._options.unref) {
227
- self._timeout.unref();
228
- }
229
- }
230
- self._fn(self._attempts);
231
- }, timeout);
232
- if (this._options.unref) {
233
- this._timer.unref();
234
- }
235
- return true;
236
- };
237
- RetryOperation.prototype.attempt = function(fn, timeoutOps) {
238
- this._fn = fn;
239
- if (timeoutOps) {
240
- if (timeoutOps.timeout) {
241
- this._operationTimeout = timeoutOps.timeout;
242
- }
243
- if (timeoutOps.cb) {
244
- this._operationTimeoutCb = timeoutOps.cb;
245
- }
246
- }
247
- var self = this;
248
- if (this._operationTimeoutCb) {
249
- this._timeout = setTimeout(function() {
250
- self._operationTimeoutCb();
251
- }, self._operationTimeout);
252
- }
253
- this._operationStart = (/* @__PURE__ */ new Date()).getTime();
254
- this._fn(this._attempts);
255
- };
256
- RetryOperation.prototype.try = function(fn) {
257
- console.log("Using RetryOperation.try() is deprecated");
258
- this.attempt(fn);
259
- };
260
- RetryOperation.prototype.start = function(fn) {
261
- console.log("Using RetryOperation.start() is deprecated");
262
- this.attempt(fn);
263
- };
264
- RetryOperation.prototype.start = RetryOperation.prototype.try;
265
- RetryOperation.prototype.errors = function() {
266
- return this._errors;
267
- };
268
- RetryOperation.prototype.attempts = function() {
269
- return this._attempts;
270
- };
271
- RetryOperation.prototype.mainError = function() {
272
- if (this._errors.length === 0) {
273
- return null;
274
- }
275
- var counts = {};
276
- var mainError = null;
277
- var mainErrorCount = 0;
278
- for (var i = 0; i < this._errors.length; i++) {
279
- var error = this._errors[i];
280
- var message = error.message;
281
- var count = (counts[message] || 0) + 1;
282
- counts[message] = count;
283
- if (count >= mainErrorCount) {
284
- mainError = error;
285
- mainErrorCount = count;
286
- }
287
- }
288
- return mainError;
289
- };
290
- }
291
- });
292
-
293
- // ../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/lib/retry.js
294
- var require_retry = __commonJS({
295
- "../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/lib/retry.js"(exports2) {
296
- "use strict";
297
- var RetryOperation = require_retry_operation();
298
- exports2.operation = function(options) {
299
- var timeouts = exports2.timeouts(options);
300
- return new RetryOperation(timeouts, {
301
- forever: options && (options.forever || options.retries === Infinity),
302
- unref: options && options.unref,
303
- maxRetryTime: options && options.maxRetryTime
304
- });
305
- };
306
- exports2.timeouts = function(options) {
307
- if (options instanceof Array) {
308
- return [].concat(options);
309
- }
310
- var opts = {
311
- retries: 10,
312
- factor: 2,
313
- minTimeout: 1 * 1e3,
314
- maxTimeout: Infinity,
315
- randomize: false
316
- };
317
- for (var key in options) {
318
- opts[key] = options[key];
319
- }
320
- if (opts.minTimeout > opts.maxTimeout) {
321
- throw new Error("minTimeout is greater than maxTimeout");
322
- }
323
- var timeouts = [];
324
- for (var i = 0; i < opts.retries; i++) {
325
- timeouts.push(this.createTimeout(i, opts));
326
- }
327
- if (options && options.forever && !timeouts.length) {
328
- timeouts.push(this.createTimeout(i, opts));
329
- }
330
- timeouts.sort(function(a, b) {
331
- return a - b;
332
- });
333
- return timeouts;
334
- };
335
- exports2.createTimeout = function(attempt, opts) {
336
- var random = opts.randomize ? Math.random() + 1 : 1;
337
- var timeout = Math.round(random * Math.max(opts.minTimeout, 1) * Math.pow(opts.factor, attempt));
338
- timeout = Math.min(timeout, opts.maxTimeout);
339
- return timeout;
340
- };
341
- exports2.wrap = function(obj, options, methods) {
342
- if (options instanceof Array) {
343
- methods = options;
344
- options = null;
345
- }
346
- if (!methods) {
347
- methods = [];
348
- for (var key in obj) {
349
- if (typeof obj[key] === "function") {
350
- methods.push(key);
351
- }
352
- }
353
- }
354
- for (var i = 0; i < methods.length; i++) {
355
- var method = methods[i];
356
- var original = obj[method];
357
- obj[method] = function retryWrapper(original2) {
358
- var op = exports2.operation(options);
359
- var args = Array.prototype.slice.call(arguments, 1);
360
- var callback = args.pop();
361
- args.push(function(err) {
362
- if (op.retry(err)) {
363
- return;
364
- }
365
- if (err) {
366
- arguments[0] = op.mainError();
367
- }
368
- callback.apply(this, arguments);
369
- });
370
- op.attempt(function() {
371
- original2.apply(obj, args);
372
- });
373
- }.bind(obj, original);
374
- obj[method].options = options;
375
- }
376
- };
377
- }
378
- });
379
-
380
- // ../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/index.js
381
- var require_retry2 = __commonJS({
382
- "../../node_modules/.pnpm/retry@0.13.1/node_modules/retry/index.js"(exports2, module2) {
383
- "use strict";
384
- module2.exports = require_retry();
385
- }
386
- });
387
-
388
36
  // src/index.ts
389
- var src_exports = {};
390
- __export(src_exports, {
37
+ var index_exports = {};
38
+ __export(index_exports, {
391
39
  ASSETS_SOURCE_CUSTOM_URL: () => ASSETS_SOURCE_CUSTOM_URL,
392
40
  ASSETS_SOURCE_UNIFORM: () => ASSETS_SOURCE_UNIFORM,
393
41
  ASSET_PARAMETER_TYPE: () => ASSET_PARAMETER_TYPE,
@@ -471,6 +119,7 @@ __export(src_exports, {
471
119
  ReleaseContentsClient: () => ReleaseContentsClient,
472
120
  RouteClient: () => RouteClient,
473
121
  SECRET_QUERY_STRING_PARAM: () => SECRET_QUERY_STRING_PARAM,
122
+ SELECT_QUERY_PREFIX: () => SELECT_QUERY_PREFIX,
474
123
  UncachedCanvasClient: () => UncachedCanvasClient,
475
124
  UncachedCategoryClient: () => UncachedCategoryClient,
476
125
  UncachedContentClient: () => UncachedContentClient,
@@ -552,191 +201,33 @@ __export(src_exports, {
552
201
  localize: () => localize,
553
202
  mapSlotToPersonalizedVariations: () => mapSlotToPersonalizedVariations,
554
203
  mapSlotToTestVariations: () => mapSlotToTestVariations,
204
+ matchesProjectionPattern: () => matchesProjectionPattern,
555
205
  mergeAssetConfigWithDefaults: () => mergeAssetConfigWithDefaults,
556
206
  nullLimitPolicy: () => nullLimitPolicy,
557
207
  parseComponentPlaceholderId: () => parseComponentPlaceholderId,
558
208
  parseVariableExpression: () => parseVariableExpression,
209
+ projectionToQuery: () => projectionToQuery,
210
+ queryToProjection: () => queryToProjection,
559
211
  version: () => version,
560
212
  walkNodeTree: () => walkNodeTree,
561
213
  walkPropertyValues: () => walkPropertyValues
562
214
  });
563
- module.exports = __toCommonJS(src_exports);
215
+ module.exports = __toCommonJS(index_exports);
564
216
 
565
217
  // src/CanvasClient.ts
566
218
  var import_api2 = require("@uniformdev/context/api");
567
219
 
568
220
  // src/enhancement/createLimitPolicy.ts
569
221
  var import_api = require("@uniformdev/context/api");
570
- var import_p_limit = __toESM(require_p_limit());
571
-
572
- // ../../node_modules/.pnpm/p-retry@5.1.2/node_modules/p-retry/index.js
573
- var import_retry = __toESM(require_retry2(), 1);
574
- var networkErrorMsgs = /* @__PURE__ */ new Set([
575
- "Failed to fetch",
576
- // Chrome
577
- "NetworkError when attempting to fetch resource.",
578
- // Firefox
579
- "The Internet connection appears to be offline.",
580
- // Safari
581
- "Network request failed",
582
- // `cross-fetch`
583
- "fetch failed"
584
- // Undici (Node.js)
585
- ]);
586
- var AbortError = class extends Error {
587
- constructor(message) {
588
- super();
589
- if (message instanceof Error) {
590
- this.originalError = message;
591
- ({ message } = message);
592
- } else {
593
- this.originalError = new Error(message);
594
- this.originalError.stack = this.stack;
595
- }
596
- this.name = "AbortError";
597
- this.message = message;
598
- }
599
- };
600
- var decorateErrorWithCounts = (error, attemptNumber, options) => {
601
- const retriesLeft = options.retries - (attemptNumber - 1);
602
- error.attemptNumber = attemptNumber;
603
- error.retriesLeft = retriesLeft;
604
- return error;
605
- };
606
- var isNetworkError = (errorMessage) => networkErrorMsgs.has(errorMessage);
607
- var getDOMException = (errorMessage) => globalThis.DOMException === void 0 ? new Error(errorMessage) : new DOMException(errorMessage);
608
- async function pRetry(input, options) {
609
- return new Promise((resolve, reject) => {
610
- options = {
611
- onFailedAttempt() {
612
- },
613
- retries: 10,
614
- ...options
615
- };
616
- const operation = import_retry.default.operation(options);
617
- operation.attempt(async (attemptNumber) => {
618
- try {
619
- resolve(await input(attemptNumber));
620
- } catch (error) {
621
- if (!(error instanceof Error)) {
622
- reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
623
- return;
624
- }
625
- if (error instanceof AbortError) {
626
- operation.stop();
627
- reject(error.originalError);
628
- } else if (error instanceof TypeError && !isNetworkError(error.message)) {
629
- operation.stop();
630
- reject(error);
631
- } else {
632
- decorateErrorWithCounts(error, attemptNumber, options);
633
- try {
634
- await options.onFailedAttempt(error);
635
- } catch (error2) {
636
- reject(error2);
637
- return;
638
- }
639
- if (!operation.retry(error)) {
640
- reject(operation.mainError());
641
- }
642
- }
643
- }
644
- });
645
- if (options.signal && !options.signal.aborted) {
646
- options.signal.addEventListener("abort", () => {
647
- operation.stop();
648
- const reason = options.signal.reason === void 0 ? getDOMException("The operation was aborted.") : options.signal.reason;
649
- reject(reason instanceof Error ? reason : getDOMException(reason));
650
- }, {
651
- once: true
652
- });
653
- }
654
- });
655
- }
656
-
657
- // ../../node_modules/.pnpm/p-throttle@5.0.0/node_modules/p-throttle/index.js
658
- var AbortError2 = class extends Error {
659
- constructor() {
660
- super("Throttled function aborted");
661
- this.name = "AbortError";
662
- }
663
- };
664
- function pThrottle({ limit, interval, strict }) {
665
- if (!Number.isFinite(limit)) {
666
- throw new TypeError("Expected `limit` to be a finite number");
667
- }
668
- if (!Number.isFinite(interval)) {
669
- throw new TypeError("Expected `interval` to be a finite number");
670
- }
671
- const queue = /* @__PURE__ */ new Map();
672
- let currentTick = 0;
673
- let activeCount = 0;
674
- function windowedDelay() {
675
- const now = Date.now();
676
- if (now - currentTick > interval) {
677
- activeCount = 1;
678
- currentTick = now;
679
- return 0;
680
- }
681
- if (activeCount < limit) {
682
- activeCount++;
683
- } else {
684
- currentTick += interval;
685
- activeCount = 1;
686
- }
687
- return currentTick - now;
688
- }
689
- const strictTicks = [];
690
- function strictDelay() {
691
- const now = Date.now();
692
- if (strictTicks.length < limit) {
693
- strictTicks.push(now);
694
- return 0;
695
- }
696
- const earliestTime = strictTicks.shift() + interval;
697
- if (now >= earliestTime) {
698
- strictTicks.push(now);
699
- return 0;
700
- }
701
- strictTicks.push(earliestTime);
702
- return earliestTime - now;
703
- }
704
- const getDelay = strict ? strictDelay : windowedDelay;
705
- return (function_) => {
706
- const throttled = function(...args) {
707
- if (!throttled.isEnabled) {
708
- return (async () => function_.apply(this, args))();
709
- }
710
- let timeout;
711
- return new Promise((resolve, reject) => {
712
- const execute = () => {
713
- resolve(function_.apply(this, args));
714
- queue.delete(timeout);
715
- };
716
- timeout = setTimeout(execute, getDelay());
717
- queue.set(timeout, reject);
718
- });
719
- };
720
- throttled.abort = () => {
721
- for (const timeout of queue.keys()) {
722
- clearTimeout(timeout);
723
- queue.get(timeout)(new AbortError2());
724
- }
725
- queue.clear();
726
- strictTicks.splice(0, strictTicks.length);
727
- };
728
- throttled.isEnabled = true;
729
- return throttled;
730
- };
731
- }
732
-
733
- // src/enhancement/createLimitPolicy.ts
222
+ var import_p_limit = __toESM(require("p-limit"));
223
+ var import_p_retry = __toESM(require("p-retry"));
224
+ var import_p_throttle = __toESM(require("p-throttle"));
734
225
  function createLimitPolicy({
735
226
  throttle = { interval: 1e3, limit: 10 },
736
- retry: retry2 = { retries: 1, factor: 1.66 },
227
+ retry = { retries: 1, factor: 1.66 },
737
228
  limit = 10
738
229
  }) {
739
- const throttler = throttle ? pThrottle(throttle) : null;
230
+ const throttler = throttle ? (0, import_p_throttle.default)(throttle) : null;
740
231
  const limiter = limit ? (0, import_p_limit.default)(limit) : null;
741
232
  return function limitPolicy(func) {
742
233
  let currentFunc = async () => await func();
@@ -748,13 +239,13 @@ function createLimitPolicy({
748
239
  const limitFunc = currentFunc;
749
240
  currentFunc = () => limiter(limitFunc);
750
241
  }
751
- if (retry2) {
242
+ if (retry) {
752
243
  const retryFunc = currentFunc;
753
- currentFunc = () => pRetry(retryFunc, {
754
- ...retry2,
244
+ currentFunc = () => (0, import_p_retry.default)(retryFunc, {
245
+ ...retry,
755
246
  onFailedAttempt: async (error) => {
756
- if (retry2.onFailedAttempt) {
757
- await retry2.onFailedAttempt(error);
247
+ if (retry.onFailedAttempt) {
248
+ await retry.onFailedAttempt(error);
758
249
  }
759
250
  if (error instanceof import_api.ApiClientError && typeof error.statusCode === "number" && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429 && error.statusCode !== 408) {
760
251
  throw error;
@@ -767,6 +258,51 @@ function createLimitPolicy({
767
258
  }
768
259
  var nullLimitPolicy = async (func) => await func();
769
260
 
261
+ // src/projection/types.ts
262
+ var SELECT_QUERY_PREFIX = "select.";
263
+
264
+ // src/projection/projectionToQuery.ts
265
+ function appendCsv(out, key, values) {
266
+ if (values === void 0) {
267
+ return;
268
+ }
269
+ out[key] = values.join(",");
270
+ }
271
+ function projectionToQuery(spec) {
272
+ const out = {};
273
+ if (!spec) {
274
+ return out;
275
+ }
276
+ const { fields, fieldTypes, slots } = spec;
277
+ const p = SELECT_QUERY_PREFIX;
278
+ if (fields) {
279
+ appendCsv(out, `${p}fields[only]`, fields.only);
280
+ appendCsv(out, `${p}fields[except]`, fields.except);
281
+ appendCsv(out, `${p}fields[locales]`, fields.locales);
282
+ }
283
+ if (fieldTypes) {
284
+ appendCsv(out, `${p}fieldTypes[only]`, fieldTypes.only);
285
+ appendCsv(out, `${p}fieldTypes[except]`, fieldTypes.except);
286
+ }
287
+ if (slots) {
288
+ appendCsv(out, `${p}slots[only]`, slots.only);
289
+ appendCsv(out, `${p}slots[except]`, slots.except);
290
+ if (typeof slots.depth === "number") {
291
+ out[`${p}slots[depth]`] = String(slots.depth);
292
+ }
293
+ if (slots.named) {
294
+ const slotNames = Object.keys(slots.named).sort();
295
+ for (const slotName of slotNames) {
296
+ const named = slots.named[slotName];
297
+ if (named && typeof named.depth === "number") {
298
+ out[`${p}slots.${slotName}[depth]`] = String(named.depth);
299
+ }
300
+ }
301
+ }
302
+ }
303
+ return out;
304
+ }
305
+
770
306
  // src/CanvasClient.ts
771
307
  var CANVAS_URL = "/api/v1/canvas";
772
308
  var CanvasClient = class extends import_api2.ApiClient {
@@ -782,17 +318,24 @@ var CanvasClient = class extends import_api2.ApiClient {
782
318
  /** Fetches lists of Canvas compositions, optionally by type */
783
319
  async getCompositionList(params = {}) {
784
320
  const { projectId } = this.options;
785
- const { resolveData, filters, ...originParams } = params;
321
+ const { resolveData, filters, select, ...originParams } = params;
786
322
  const rewrittenFilters = (0, import_api2.rewriteFiltersForApi)(filters);
323
+ const rewrittenSelect = projectionToQuery(select);
787
324
  if (!resolveData) {
788
- const fetchUri = this.createUrl(CANVAS_URL, { ...originParams, projectId, ...rewrittenFilters });
325
+ const fetchUri = this.createUrl(CANVAS_URL, {
326
+ ...originParams,
327
+ projectId,
328
+ ...rewrittenFilters,
329
+ ...rewrittenSelect
330
+ });
789
331
  return this.apiClient(fetchUri);
790
332
  }
791
333
  const edgeParams = {
792
334
  ...originParams,
793
335
  projectId,
794
336
  diagnostics: typeof params.diagnostics === "boolean" ? params.diagnostics : params.diagnostics === "no-data" ? "no-data" : void 0,
795
- ...rewrittenFilters
337
+ ...rewrittenFilters,
338
+ ...rewrittenSelect
796
339
  };
797
340
  const edgeUrl = this.createUrl("/api/v1/compositions", edgeParams, this.edgeApiHost);
798
341
  return this.apiClient(edgeUrl, this.edgeApiRequestInit);
@@ -952,15 +495,21 @@ var _ContentClient = class _ContentClient extends import_api4.ApiClient {
952
495
  }
953
496
  getEntries(options) {
954
497
  const { projectId } = this.options;
955
- const { skipDataResolution, filters, ...params } = options;
498
+ const { skipDataResolution, filters, select, ...params } = options;
956
499
  const rewrittenFilters = (0, import_api4.rewriteFiltersForApi)(filters);
500
+ const rewrittenSelect = projectionToQuery(select);
957
501
  if (skipDataResolution) {
958
- const url = this.createUrl(__privateGet(_ContentClient, _entriesUrl), { ...params, ...rewrittenFilters, projectId });
502
+ const url = this.createUrl(__privateGet(_ContentClient, _entriesUrl), {
503
+ ...params,
504
+ ...rewrittenFilters,
505
+ ...rewrittenSelect,
506
+ projectId
507
+ });
959
508
  return this.apiClient(url);
960
509
  }
961
510
  const edgeUrl = this.createUrl(
962
511
  __privateGet(_ContentClient, _entriesUrl),
963
- { ...this.getEdgeOptions(params), ...rewrittenFilters },
512
+ { ...this.getEdgeOptions(params), ...rewrittenFilters, ...rewrittenSelect },
964
513
  this.edgeApiHost
965
514
  );
966
515
  return this.apiClient(
@@ -2589,8 +2138,7 @@ function extractLocales({ component }) {
2589
2138
  return variations;
2590
2139
  }
2591
2140
  function localize(options) {
2592
- const nodes = options.nodes;
2593
- const locale = options.locale;
2141
+ const { nodes, locale, keepLocalesFor } = options;
2594
2142
  if (!locale) {
2595
2143
  return;
2596
2144
  }
@@ -2598,7 +2146,7 @@ function localize(options) {
2598
2146
  walkNodeTree(nodes, (context) => {
2599
2147
  const { type, node, actions } = context;
2600
2148
  if (type !== "component") {
2601
- localizeProperties(node, locale, vizControlLocaleRule);
2149
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
2602
2150
  return;
2603
2151
  }
2604
2152
  const result = evaluateWalkTreeNodeVisibility({
@@ -2619,7 +2167,7 @@ function localize(options) {
2619
2167
  if (replaceComponent == null ? void 0 : replaceComponent.length) {
2620
2168
  replaceComponent.forEach((component) => {
2621
2169
  removeLocaleProperty(component);
2622
- localizeProperties(component, locale, vizControlLocaleRule);
2170
+ localizeProperties(component, locale, vizControlLocaleRule, keepLocalesFor);
2623
2171
  });
2624
2172
  const [first, ...rest] = replaceComponent;
2625
2173
  actions.replace(first);
@@ -2630,7 +2178,7 @@ function localize(options) {
2630
2178
  actions.remove();
2631
2179
  }
2632
2180
  } else {
2633
- localizeProperties(node, locale, vizControlLocaleRule);
2181
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
2634
2182
  }
2635
2183
  });
2636
2184
  }
@@ -2649,7 +2197,7 @@ function removeLocaleProperty(component) {
2649
2197
  }
2650
2198
  }
2651
2199
  }
2652
- function localizeProperties(node, locale, rules) {
2200
+ function localizeProperties(node, locale, rules, keepLocalesFor) {
2653
2201
  const properties = getPropertiesValue(node);
2654
2202
  if (!properties) {
2655
2203
  return void 0;
@@ -2668,10 +2216,16 @@ function localizeProperties(node, locale, rules) {
2668
2216
  if (currentLocaleConditionalValues !== void 0) {
2669
2217
  propertyValue.conditions = currentLocaleConditionalValues;
2670
2218
  }
2671
- delete propertyValue.locales;
2672
- delete propertyValue.localesConditions;
2219
+ const preserveLocales = (keepLocalesFor == null ? void 0 : keepLocalesFor(propertyId)) === true;
2220
+ if (!preserveLocales) {
2221
+ delete propertyValue.locales;
2222
+ delete propertyValue.localesConditions;
2223
+ }
2673
2224
  if (propertyValue.value === void 0 && propertyValue.conditions === void 0) {
2674
- delete properties[propertyId];
2225
+ const hasLocales = preserveLocales && (propertyValue.locales || propertyValue.localesConditions);
2226
+ if (!hasLocales) {
2227
+ delete properties[propertyId];
2228
+ }
2675
2229
  }
2676
2230
  });
2677
2231
  evaluateWalkTreePropertyCriteria({
@@ -3350,6 +2904,173 @@ __privateAdd(_ProjectClient, _url2, "/api/v1/project");
3350
2904
  __privateAdd(_ProjectClient, _projectsUrl, "/api/v1/projects");
3351
2905
  var ProjectClient = _ProjectClient;
3352
2906
 
2907
+ // src/projection/matchesProjectionPattern.ts
2908
+ var DISALLOWED_PATTERN_CHARS = /[,&=?#[\]\s]/;
2909
+ var REGEX_METACHAR = /[\\^$.|?*+()[\]{}]/g;
2910
+ function isValidProjectionPattern(pattern) {
2911
+ if (typeof pattern !== "string" || pattern.length === 0) {
2912
+ return false;
2913
+ }
2914
+ if (DISALLOWED_PATTERN_CHARS.test(pattern)) {
2915
+ return false;
2916
+ }
2917
+ return true;
2918
+ }
2919
+ function compilePattern(pattern) {
2920
+ let regexSource = "^";
2921
+ for (const ch of pattern) {
2922
+ if (ch === "*") {
2923
+ regexSource += ".*";
2924
+ } else {
2925
+ regexSource += ch.replace(REGEX_METACHAR, "\\$&");
2926
+ }
2927
+ }
2928
+ regexSource += "$";
2929
+ return new RegExp(regexSource);
2930
+ }
2931
+ var PATTERN_CACHE_MAX = 1024;
2932
+ var patternRegexCache = /* @__PURE__ */ new Map();
2933
+ function matchesProjectionPattern(pattern, value) {
2934
+ let re = patternRegexCache.get(pattern);
2935
+ if (re === void 0) {
2936
+ if (!isValidProjectionPattern(pattern)) {
2937
+ throw new Error(`Invalid projection pattern: ${JSON.stringify(pattern)}`);
2938
+ }
2939
+ re = compilePattern(pattern);
2940
+ if (patternRegexCache.size >= PATTERN_CACHE_MAX) {
2941
+ const oldest = patternRegexCache.keys().next().value;
2942
+ if (oldest !== void 0) patternRegexCache.delete(oldest);
2943
+ }
2944
+ patternRegexCache.set(pattern, re);
2945
+ }
2946
+ return re.test(value);
2947
+ }
2948
+
2949
+ // src/projection/queryToProjection.ts
2950
+ var TOP_LEVEL_OPERATOR_KEY = /^(fields|fieldTypes|slots)\[([A-Za-z]+)\]$/;
2951
+ var SLOTS_NAMED_KEY = /^slots\.([A-Za-z0-9_-]+)\[([A-Za-z]+)\]$/;
2952
+ function toStringValue2(value) {
2953
+ if (Array.isArray(value)) {
2954
+ return value.join(",");
2955
+ }
2956
+ return value;
2957
+ }
2958
+ function parseCsv(value) {
2959
+ const str = toStringValue2(value);
2960
+ if (!str) {
2961
+ return [];
2962
+ }
2963
+ return str.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
2964
+ }
2965
+ function parseDepth(value, key) {
2966
+ const str = toStringValue2(value);
2967
+ if (str === void 0 || str === "") {
2968
+ throw new Error(`Invalid select projection: '${key}' requires a non-negative integer value`);
2969
+ }
2970
+ if (!/^\d+$/.test(str)) {
2971
+ throw new Error(
2972
+ `Invalid select projection: '${key}' must be a non-negative integer (got ${JSON.stringify(str)})`
2973
+ );
2974
+ }
2975
+ return Number(str);
2976
+ }
2977
+ function extractSelectKeys(source) {
2978
+ if (source instanceof URLSearchParams) {
2979
+ let out2;
2980
+ for (const [key, value] of source.entries()) {
2981
+ if (!key.startsWith(SELECT_QUERY_PREFIX)) continue;
2982
+ out2 != null ? out2 : out2 = {};
2983
+ out2[key] = out2[key] === void 0 ? value : `${out2[key]},${value}`;
2984
+ }
2985
+ return out2;
2986
+ }
2987
+ let out;
2988
+ for (const key in source) {
2989
+ if (!key.startsWith(SELECT_QUERY_PREFIX)) continue;
2990
+ out != null ? out : out = {};
2991
+ out[key] = source[key];
2992
+ }
2993
+ return out;
2994
+ }
2995
+ function queryToProjection(source) {
2996
+ var _a, _b, _c, _d, _e;
2997
+ if (!source) {
2998
+ return void 0;
2999
+ }
3000
+ const query = extractSelectKeys(source);
3001
+ if (!query) {
3002
+ return void 0;
3003
+ }
3004
+ const spec = {};
3005
+ for (const [rawKey, value] of Object.entries(query)) {
3006
+ const key = rawKey.slice(SELECT_QUERY_PREFIX.length);
3007
+ const namedMatch = SLOTS_NAMED_KEY.exec(key);
3008
+ if (namedMatch) {
3009
+ const [, slotName, operator2] = namedMatch;
3010
+ if (operator2 !== "depth") {
3011
+ throw new Error(
3012
+ `Invalid select projection: unsupported operator '${operator2}' for slots.${slotName}`
3013
+ );
3014
+ }
3015
+ const slots = (_a = spec.slots) != null ? _a : spec.slots = {};
3016
+ const named = (_b = slots.named) != null ? _b : slots.named = {};
3017
+ named[slotName] = { ...named[slotName], depth: parseDepth(value, rawKey) };
3018
+ continue;
3019
+ }
3020
+ const topMatch = TOP_LEVEL_OPERATOR_KEY.exec(key);
3021
+ if (!topMatch) {
3022
+ throw new Error(`Invalid select projection key: ${JSON.stringify(rawKey)}`);
3023
+ }
3024
+ const [, bucket, operator] = topMatch;
3025
+ if (bucket === "fields") {
3026
+ const fields = (_c = spec.fields) != null ? _c : spec.fields = {};
3027
+ switch (operator) {
3028
+ case "only":
3029
+ fields.only = parseCsv(value);
3030
+ break;
3031
+ case "except":
3032
+ fields.except = parseCsv(value);
3033
+ break;
3034
+ case "locales":
3035
+ fields.locales = parseCsv(value);
3036
+ break;
3037
+ default:
3038
+ throw new Error(`Invalid select projection: unsupported operator 'fields[${operator}]'`);
3039
+ }
3040
+ } else if (bucket === "fieldTypes") {
3041
+ const fieldTypes = (_d = spec.fieldTypes) != null ? _d : spec.fieldTypes = {};
3042
+ switch (operator) {
3043
+ case "only":
3044
+ fieldTypes.only = parseCsv(value);
3045
+ break;
3046
+ case "except":
3047
+ fieldTypes.except = parseCsv(value);
3048
+ break;
3049
+ default:
3050
+ throw new Error(`Invalid select projection: unsupported operator 'fieldTypes[${operator}]'`);
3051
+ }
3052
+ } else if (bucket === "slots") {
3053
+ const slots = (_e = spec.slots) != null ? _e : spec.slots = {};
3054
+ switch (operator) {
3055
+ case "only":
3056
+ slots.only = parseCsv(value);
3057
+ break;
3058
+ case "except":
3059
+ slots.except = parseCsv(value);
3060
+ break;
3061
+ case "depth":
3062
+ slots.depth = parseDepth(value, rawKey);
3063
+ break;
3064
+ default:
3065
+ throw new Error(`Invalid select projection: unsupported operator 'slots[${operator}]'`);
3066
+ }
3067
+ } else {
3068
+ throw new Error(`Invalid select projection key: ${JSON.stringify(rawKey)}`);
3069
+ }
3070
+ }
3071
+ return spec;
3072
+ }
3073
+
3353
3074
  // src/PromptClient.ts
3354
3075
  var import_api13 = require("@uniformdev/context/api");
3355
3076
  var PromptsUrl = "/api/v1/prompts";
@@ -3478,7 +3199,9 @@ var RouteClient = class extends import_api17.ApiClient {
3478
3199
  /** Fetches lists of Canvas compositions, optionally by type */
3479
3200
  async getRoute(options) {
3480
3201
  const { projectId } = this.options;
3481
- const fetchUri = this.createUrl(ROUTE_URL, { ...options, projectId }, this.edgeApiHost);
3202
+ const { select, ...rest } = options != null ? options : {};
3203
+ const rewrittenSelect = projectionToQuery(select);
3204
+ const fetchUri = this.createUrl(ROUTE_URL, { ...rest, projectId, ...rewrittenSelect }, this.edgeApiHost);
3482
3205
  return await this.apiClient(
3483
3206
  fetchUri,
3484
3207
  this.options.disableSWR ? { headers: { "x-disable-swr": "true" } } : void 0
@@ -3841,7 +3564,7 @@ function handleRichTextNodeBinding(object, options) {
3841
3564
  var import_api19 = require("@uniformdev/context/api");
3842
3565
 
3843
3566
  // src/.version.ts
3844
- var version = "20.68.0";
3567
+ var version = "20.71.1";
3845
3568
 
3846
3569
  // src/WorkflowClient.ts
3847
3570
  var import_api18 = require("@uniformdev/context/api");
@@ -3963,6 +3686,7 @@ var CanvasClientError = import_api19.ApiClientError;
3963
3686
  ReleaseContentsClient,
3964
3687
  RouteClient,
3965
3688
  SECRET_QUERY_STRING_PARAM,
3689
+ SELECT_QUERY_PREFIX,
3966
3690
  UncachedCanvasClient,
3967
3691
  UncachedCategoryClient,
3968
3692
  UncachedContentClient,
@@ -4044,10 +3768,13 @@ var CanvasClientError = import_api19.ApiClientError;
4044
3768
  localize,
4045
3769
  mapSlotToPersonalizedVariations,
4046
3770
  mapSlotToTestVariations,
3771
+ matchesProjectionPattern,
4047
3772
  mergeAssetConfigWithDefaults,
4048
3773
  nullLimitPolicy,
4049
3774
  parseComponentPlaceholderId,
4050
3775
  parseVariableExpression,
3776
+ projectionToQuery,
3777
+ queryToProjection,
4051
3778
  version,
4052
3779
  walkNodeTree,
4053
3780
  walkPropertyValues