@uniformdev/canvas 20.70.1-alpha.10 → 20.71.1

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.esm.js CHANGED
@@ -49,6 +49,51 @@ function createLimitPolicy({
49
49
  }
50
50
  var nullLimitPolicy = async (func) => await func();
51
51
 
52
+ // src/projection/types.ts
53
+ var SELECT_QUERY_PREFIX = "select.";
54
+
55
+ // src/projection/projectionToQuery.ts
56
+ function appendCsv(out, key, values) {
57
+ if (values === void 0) {
58
+ return;
59
+ }
60
+ out[key] = values.join(",");
61
+ }
62
+ function projectionToQuery(spec) {
63
+ const out = {};
64
+ if (!spec) {
65
+ return out;
66
+ }
67
+ const { fields, fieldTypes, slots } = spec;
68
+ const p = SELECT_QUERY_PREFIX;
69
+ if (fields) {
70
+ appendCsv(out, `${p}fields[only]`, fields.only);
71
+ appendCsv(out, `${p}fields[except]`, fields.except);
72
+ appendCsv(out, `${p}fields[locales]`, fields.locales);
73
+ }
74
+ if (fieldTypes) {
75
+ appendCsv(out, `${p}fieldTypes[only]`, fieldTypes.only);
76
+ appendCsv(out, `${p}fieldTypes[except]`, fieldTypes.except);
77
+ }
78
+ if (slots) {
79
+ appendCsv(out, `${p}slots[only]`, slots.only);
80
+ appendCsv(out, `${p}slots[except]`, slots.except);
81
+ if (typeof slots.depth === "number") {
82
+ out[`${p}slots[depth]`] = String(slots.depth);
83
+ }
84
+ if (slots.named) {
85
+ const slotNames = Object.keys(slots.named).sort();
86
+ for (const slotName of slotNames) {
87
+ const named = slots.named[slotName];
88
+ if (named && typeof named.depth === "number") {
89
+ out[`${p}slots.${slotName}[depth]`] = String(named.depth);
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return out;
95
+ }
96
+
52
97
  // src/CanvasClient.ts
53
98
  var CANVAS_URL = "/api/v1/canvas";
54
99
  var CanvasClient = class extends ApiClient {
@@ -64,17 +109,24 @@ var CanvasClient = class extends ApiClient {
64
109
  /** Fetches lists of Canvas compositions, optionally by type */
65
110
  async getCompositionList(params = {}) {
66
111
  const { projectId } = this.options;
67
- const { resolveData, filters, ...originParams } = params;
112
+ const { resolveData, filters, select, ...originParams } = params;
68
113
  const rewrittenFilters = rewriteFiltersForApi(filters);
114
+ const rewrittenSelect = projectionToQuery(select);
69
115
  if (!resolveData) {
70
- const fetchUri = this.createUrl(CANVAS_URL, { ...originParams, projectId, ...rewrittenFilters });
116
+ const fetchUri = this.createUrl(CANVAS_URL, {
117
+ ...originParams,
118
+ projectId,
119
+ ...rewrittenFilters,
120
+ ...rewrittenSelect
121
+ });
71
122
  return this.apiClient(fetchUri);
72
123
  }
73
124
  const edgeParams = {
74
125
  ...originParams,
75
126
  projectId,
76
127
  diagnostics: typeof params.diagnostics === "boolean" ? params.diagnostics : params.diagnostics === "no-data" ? "no-data" : void 0,
77
- ...rewrittenFilters
128
+ ...rewrittenFilters,
129
+ ...rewrittenSelect
78
130
  };
79
131
  const edgeUrl = this.createUrl("/api/v1/compositions", edgeParams, this.edgeApiHost);
80
132
  return this.apiClient(edgeUrl, this.edgeApiRequestInit);
@@ -234,15 +286,21 @@ var _ContentClient = class _ContentClient extends ApiClient3 {
234
286
  }
235
287
  getEntries(options) {
236
288
  const { projectId } = this.options;
237
- const { skipDataResolution, filters, ...params } = options;
289
+ const { skipDataResolution, filters, select, ...params } = options;
238
290
  const rewrittenFilters = rewriteFiltersForApi2(filters);
291
+ const rewrittenSelect = projectionToQuery(select);
239
292
  if (skipDataResolution) {
240
- const url = this.createUrl(__privateGet(_ContentClient, _entriesUrl), { ...params, ...rewrittenFilters, projectId });
293
+ const url = this.createUrl(__privateGet(_ContentClient, _entriesUrl), {
294
+ ...params,
295
+ ...rewrittenFilters,
296
+ ...rewrittenSelect,
297
+ projectId
298
+ });
241
299
  return this.apiClient(url);
242
300
  }
243
301
  const edgeUrl = this.createUrl(
244
302
  __privateGet(_ContentClient, _entriesUrl),
245
- { ...this.getEdgeOptions(params), ...rewrittenFilters },
303
+ { ...this.getEdgeOptions(params), ...rewrittenFilters, ...rewrittenSelect },
246
304
  this.edgeApiHost
247
305
  );
248
306
  return this.apiClient(
@@ -1871,8 +1929,7 @@ function extractLocales({ component }) {
1871
1929
  return variations;
1872
1930
  }
1873
1931
  function localize(options) {
1874
- const nodes = options.nodes;
1875
- const locale = options.locale;
1932
+ const { nodes, locale, keepLocalesFor } = options;
1876
1933
  if (!locale) {
1877
1934
  return;
1878
1935
  }
@@ -1880,7 +1937,7 @@ function localize(options) {
1880
1937
  walkNodeTree(nodes, (context) => {
1881
1938
  const { type, node, actions } = context;
1882
1939
  if (type !== "component") {
1883
- localizeProperties(node, locale, vizControlLocaleRule);
1940
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
1884
1941
  return;
1885
1942
  }
1886
1943
  const result = evaluateWalkTreeNodeVisibility({
@@ -1901,7 +1958,7 @@ function localize(options) {
1901
1958
  if (replaceComponent == null ? void 0 : replaceComponent.length) {
1902
1959
  replaceComponent.forEach((component) => {
1903
1960
  removeLocaleProperty(component);
1904
- localizeProperties(component, locale, vizControlLocaleRule);
1961
+ localizeProperties(component, locale, vizControlLocaleRule, keepLocalesFor);
1905
1962
  });
1906
1963
  const [first, ...rest] = replaceComponent;
1907
1964
  actions.replace(first);
@@ -1912,7 +1969,7 @@ function localize(options) {
1912
1969
  actions.remove();
1913
1970
  }
1914
1971
  } else {
1915
- localizeProperties(node, locale, vizControlLocaleRule);
1972
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
1916
1973
  }
1917
1974
  });
1918
1975
  }
@@ -1931,7 +1988,7 @@ function removeLocaleProperty(component) {
1931
1988
  }
1932
1989
  }
1933
1990
  }
1934
- function localizeProperties(node, locale, rules) {
1991
+ function localizeProperties(node, locale, rules, keepLocalesFor) {
1935
1992
  const properties = getPropertiesValue(node);
1936
1993
  if (!properties) {
1937
1994
  return void 0;
@@ -1950,10 +2007,16 @@ function localizeProperties(node, locale, rules) {
1950
2007
  if (currentLocaleConditionalValues !== void 0) {
1951
2008
  propertyValue.conditions = currentLocaleConditionalValues;
1952
2009
  }
1953
- delete propertyValue.locales;
1954
- delete propertyValue.localesConditions;
2010
+ const preserveLocales = (keepLocalesFor == null ? void 0 : keepLocalesFor(propertyId)) === true;
2011
+ if (!preserveLocales) {
2012
+ delete propertyValue.locales;
2013
+ delete propertyValue.localesConditions;
2014
+ }
1955
2015
  if (propertyValue.value === void 0 && propertyValue.conditions === void 0) {
1956
- delete properties[propertyId];
2016
+ const hasLocales = preserveLocales && (propertyValue.locales || propertyValue.localesConditions);
2017
+ if (!hasLocales) {
2018
+ delete properties[propertyId];
2019
+ }
1957
2020
  }
1958
2021
  });
1959
2022
  evaluateWalkTreePropertyCriteria({
@@ -2632,6 +2695,173 @@ __privateAdd(_ProjectClient, _url2, "/api/v1/project");
2632
2695
  __privateAdd(_ProjectClient, _projectsUrl, "/api/v1/projects");
2633
2696
  var ProjectClient = _ProjectClient;
2634
2697
 
2698
+ // src/projection/matchesProjectionPattern.ts
2699
+ var DISALLOWED_PATTERN_CHARS = /[,&=?#[\]\s]/;
2700
+ var REGEX_METACHAR = /[\\^$.|?*+()[\]{}]/g;
2701
+ function isValidProjectionPattern(pattern) {
2702
+ if (typeof pattern !== "string" || pattern.length === 0) {
2703
+ return false;
2704
+ }
2705
+ if (DISALLOWED_PATTERN_CHARS.test(pattern)) {
2706
+ return false;
2707
+ }
2708
+ return true;
2709
+ }
2710
+ function compilePattern(pattern) {
2711
+ let regexSource = "^";
2712
+ for (const ch of pattern) {
2713
+ if (ch === "*") {
2714
+ regexSource += ".*";
2715
+ } else {
2716
+ regexSource += ch.replace(REGEX_METACHAR, "\\$&");
2717
+ }
2718
+ }
2719
+ regexSource += "$";
2720
+ return new RegExp(regexSource);
2721
+ }
2722
+ var PATTERN_CACHE_MAX = 1024;
2723
+ var patternRegexCache = /* @__PURE__ */ new Map();
2724
+ function matchesProjectionPattern(pattern, value) {
2725
+ let re = patternRegexCache.get(pattern);
2726
+ if (re === void 0) {
2727
+ if (!isValidProjectionPattern(pattern)) {
2728
+ throw new Error(`Invalid projection pattern: ${JSON.stringify(pattern)}`);
2729
+ }
2730
+ re = compilePattern(pattern);
2731
+ if (patternRegexCache.size >= PATTERN_CACHE_MAX) {
2732
+ const oldest = patternRegexCache.keys().next().value;
2733
+ if (oldest !== void 0) patternRegexCache.delete(oldest);
2734
+ }
2735
+ patternRegexCache.set(pattern, re);
2736
+ }
2737
+ return re.test(value);
2738
+ }
2739
+
2740
+ // src/projection/queryToProjection.ts
2741
+ var TOP_LEVEL_OPERATOR_KEY = /^(fields|fieldTypes|slots)\[([A-Za-z]+)\]$/;
2742
+ var SLOTS_NAMED_KEY = /^slots\.([A-Za-z0-9_-]+)\[([A-Za-z]+)\]$/;
2743
+ function toStringValue2(value) {
2744
+ if (Array.isArray(value)) {
2745
+ return value.join(",");
2746
+ }
2747
+ return value;
2748
+ }
2749
+ function parseCsv(value) {
2750
+ const str = toStringValue2(value);
2751
+ if (!str) {
2752
+ return [];
2753
+ }
2754
+ return str.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
2755
+ }
2756
+ function parseDepth(value, key) {
2757
+ const str = toStringValue2(value);
2758
+ if (str === void 0 || str === "") {
2759
+ throw new Error(`Invalid select projection: '${key}' requires a non-negative integer value`);
2760
+ }
2761
+ if (!/^\d+$/.test(str)) {
2762
+ throw new Error(
2763
+ `Invalid select projection: '${key}' must be a non-negative integer (got ${JSON.stringify(str)})`
2764
+ );
2765
+ }
2766
+ return Number(str);
2767
+ }
2768
+ function extractSelectKeys(source) {
2769
+ if (source instanceof URLSearchParams) {
2770
+ let out2;
2771
+ for (const [key, value] of source.entries()) {
2772
+ if (!key.startsWith(SELECT_QUERY_PREFIX)) continue;
2773
+ out2 != null ? out2 : out2 = {};
2774
+ out2[key] = out2[key] === void 0 ? value : `${out2[key]},${value}`;
2775
+ }
2776
+ return out2;
2777
+ }
2778
+ let out;
2779
+ for (const key in source) {
2780
+ if (!key.startsWith(SELECT_QUERY_PREFIX)) continue;
2781
+ out != null ? out : out = {};
2782
+ out[key] = source[key];
2783
+ }
2784
+ return out;
2785
+ }
2786
+ function queryToProjection(source) {
2787
+ var _a, _b, _c, _d, _e;
2788
+ if (!source) {
2789
+ return void 0;
2790
+ }
2791
+ const query = extractSelectKeys(source);
2792
+ if (!query) {
2793
+ return void 0;
2794
+ }
2795
+ const spec = {};
2796
+ for (const [rawKey, value] of Object.entries(query)) {
2797
+ const key = rawKey.slice(SELECT_QUERY_PREFIX.length);
2798
+ const namedMatch = SLOTS_NAMED_KEY.exec(key);
2799
+ if (namedMatch) {
2800
+ const [, slotName, operator2] = namedMatch;
2801
+ if (operator2 !== "depth") {
2802
+ throw new Error(
2803
+ `Invalid select projection: unsupported operator '${operator2}' for slots.${slotName}`
2804
+ );
2805
+ }
2806
+ const slots = (_a = spec.slots) != null ? _a : spec.slots = {};
2807
+ const named = (_b = slots.named) != null ? _b : slots.named = {};
2808
+ named[slotName] = { ...named[slotName], depth: parseDepth(value, rawKey) };
2809
+ continue;
2810
+ }
2811
+ const topMatch = TOP_LEVEL_OPERATOR_KEY.exec(key);
2812
+ if (!topMatch) {
2813
+ throw new Error(`Invalid select projection key: ${JSON.stringify(rawKey)}`);
2814
+ }
2815
+ const [, bucket, operator] = topMatch;
2816
+ if (bucket === "fields") {
2817
+ const fields = (_c = spec.fields) != null ? _c : spec.fields = {};
2818
+ switch (operator) {
2819
+ case "only":
2820
+ fields.only = parseCsv(value);
2821
+ break;
2822
+ case "except":
2823
+ fields.except = parseCsv(value);
2824
+ break;
2825
+ case "locales":
2826
+ fields.locales = parseCsv(value);
2827
+ break;
2828
+ default:
2829
+ throw new Error(`Invalid select projection: unsupported operator 'fields[${operator}]'`);
2830
+ }
2831
+ } else if (bucket === "fieldTypes") {
2832
+ const fieldTypes = (_d = spec.fieldTypes) != null ? _d : spec.fieldTypes = {};
2833
+ switch (operator) {
2834
+ case "only":
2835
+ fieldTypes.only = parseCsv(value);
2836
+ break;
2837
+ case "except":
2838
+ fieldTypes.except = parseCsv(value);
2839
+ break;
2840
+ default:
2841
+ throw new Error(`Invalid select projection: unsupported operator 'fieldTypes[${operator}]'`);
2842
+ }
2843
+ } else if (bucket === "slots") {
2844
+ const slots = (_e = spec.slots) != null ? _e : spec.slots = {};
2845
+ switch (operator) {
2846
+ case "only":
2847
+ slots.only = parseCsv(value);
2848
+ break;
2849
+ case "except":
2850
+ slots.except = parseCsv(value);
2851
+ break;
2852
+ case "depth":
2853
+ slots.depth = parseDepth(value, rawKey);
2854
+ break;
2855
+ default:
2856
+ throw new Error(`Invalid select projection: unsupported operator 'slots[${operator}]'`);
2857
+ }
2858
+ } else {
2859
+ throw new Error(`Invalid select projection key: ${JSON.stringify(rawKey)}`);
2860
+ }
2861
+ }
2862
+ return spec;
2863
+ }
2864
+
2635
2865
  // src/PromptClient.ts
2636
2866
  import { ApiClient as ApiClient12 } from "@uniformdev/context/api";
2637
2867
  var PromptsUrl = "/api/v1/prompts";
@@ -2760,7 +2990,9 @@ var RouteClient = class extends ApiClient16 {
2760
2990
  /** Fetches lists of Canvas compositions, optionally by type */
2761
2991
  async getRoute(options) {
2762
2992
  const { projectId } = this.options;
2763
- const fetchUri = this.createUrl(ROUTE_URL, { ...options, projectId }, this.edgeApiHost);
2993
+ const { select, ...rest } = options != null ? options : {};
2994
+ const rewrittenSelect = projectionToQuery(select);
2995
+ const fetchUri = this.createUrl(ROUTE_URL, { ...rest, projectId, ...rewrittenSelect }, this.edgeApiHost);
2764
2996
  return await this.apiClient(
2765
2997
  fetchUri,
2766
2998
  this.options.disableSWR ? { headers: { "x-disable-swr": "true" } } : void 0
@@ -3123,7 +3355,7 @@ function handleRichTextNodeBinding(object, options) {
3123
3355
  import { ApiClientError as ApiClientError2 } from "@uniformdev/context/api";
3124
3356
 
3125
3357
  // src/.version.ts
3126
- var version = "20.70.0";
3358
+ var version = "20.71.1";
3127
3359
 
3128
3360
  // src/WorkflowClient.ts
3129
3361
  import { ApiClient as ApiClient17 } from "@uniformdev/context/api";
@@ -3244,6 +3476,7 @@ export {
3244
3476
  ReleaseContentsClient,
3245
3477
  RouteClient,
3246
3478
  SECRET_QUERY_STRING_PARAM,
3479
+ SELECT_QUERY_PREFIX,
3247
3480
  UncachedCanvasClient,
3248
3481
  UncachedCategoryClient,
3249
3482
  UncachedContentClient,
@@ -3325,10 +3558,13 @@ export {
3325
3558
  localize,
3326
3559
  mapSlotToPersonalizedVariations,
3327
3560
  mapSlotToTestVariations,
3561
+ matchesProjectionPattern,
3328
3562
  mergeAssetConfigWithDefaults,
3329
3563
  nullLimitPolicy,
3330
3564
  parseComponentPlaceholderId,
3331
3565
  parseVariableExpression,
3566
+ projectionToQuery,
3567
+ queryToProjection,
3332
3568
  version,
3333
3569
  walkNodeTree,
3334
3570
  walkPropertyValues