@uniformdev/canvas 20.71.0 → 20.71.2-alpha.10

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
@@ -119,6 +119,7 @@ __export(index_exports, {
119
119
  ReleaseContentsClient: () => ReleaseContentsClient,
120
120
  RouteClient: () => RouteClient,
121
121
  SECRET_QUERY_STRING_PARAM: () => SECRET_QUERY_STRING_PARAM,
122
+ SELECT_QUERY_PREFIX: () => SELECT_QUERY_PREFIX,
122
123
  UncachedCanvasClient: () => UncachedCanvasClient,
123
124
  UncachedCategoryClient: () => UncachedCategoryClient,
124
125
  UncachedContentClient: () => UncachedContentClient,
@@ -200,10 +201,13 @@ __export(index_exports, {
200
201
  localize: () => localize,
201
202
  mapSlotToPersonalizedVariations: () => mapSlotToPersonalizedVariations,
202
203
  mapSlotToTestVariations: () => mapSlotToTestVariations,
204
+ matchesProjectionPattern: () => matchesProjectionPattern,
203
205
  mergeAssetConfigWithDefaults: () => mergeAssetConfigWithDefaults,
204
206
  nullLimitPolicy: () => nullLimitPolicy,
205
207
  parseComponentPlaceholderId: () => parseComponentPlaceholderId,
206
208
  parseVariableExpression: () => parseVariableExpression,
209
+ projectionToQuery: () => projectionToQuery,
210
+ queryToProjection: () => queryToProjection,
207
211
  version: () => version,
208
212
  walkNodeTree: () => walkNodeTree,
209
213
  walkPropertyValues: () => walkPropertyValues
@@ -254,6 +258,51 @@ function createLimitPolicy({
254
258
  }
255
259
  var nullLimitPolicy = async (func) => await func();
256
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
+
257
306
  // src/CanvasClient.ts
258
307
  var CANVAS_URL = "/api/v1/canvas";
259
308
  var CanvasClient = class extends import_api2.ApiClient {
@@ -269,17 +318,24 @@ var CanvasClient = class extends import_api2.ApiClient {
269
318
  /** Fetches lists of Canvas compositions, optionally by type */
270
319
  async getCompositionList(params = {}) {
271
320
  const { projectId } = this.options;
272
- const { resolveData, filters, ...originParams } = params;
321
+ const { resolveData, filters, select, ...originParams } = params;
273
322
  const rewrittenFilters = (0, import_api2.rewriteFiltersForApi)(filters);
323
+ const rewrittenSelect = projectionToQuery(select);
274
324
  if (!resolveData) {
275
- 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
+ });
276
331
  return this.apiClient(fetchUri);
277
332
  }
278
333
  const edgeParams = {
279
334
  ...originParams,
280
335
  projectId,
281
336
  diagnostics: typeof params.diagnostics === "boolean" ? params.diagnostics : params.diagnostics === "no-data" ? "no-data" : void 0,
282
- ...rewrittenFilters
337
+ ...rewrittenFilters,
338
+ ...rewrittenSelect
283
339
  };
284
340
  const edgeUrl = this.createUrl("/api/v1/compositions", edgeParams, this.edgeApiHost);
285
341
  return this.apiClient(edgeUrl, this.edgeApiRequestInit);
@@ -439,15 +495,21 @@ var _ContentClient = class _ContentClient extends import_api4.ApiClient {
439
495
  }
440
496
  getEntries(options) {
441
497
  const { projectId } = this.options;
442
- const { skipDataResolution, filters, ...params } = options;
498
+ const { skipDataResolution, filters, select, ...params } = options;
443
499
  const rewrittenFilters = (0, import_api4.rewriteFiltersForApi)(filters);
500
+ const rewrittenSelect = projectionToQuery(select);
444
501
  if (skipDataResolution) {
445
- 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
+ });
446
508
  return this.apiClient(url);
447
509
  }
448
510
  const edgeUrl = this.createUrl(
449
511
  __privateGet(_ContentClient, _entriesUrl),
450
- { ...this.getEdgeOptions(params), ...rewrittenFilters },
512
+ { ...this.getEdgeOptions(params), ...rewrittenFilters, ...rewrittenSelect },
451
513
  this.edgeApiHost
452
514
  );
453
515
  return this.apiClient(
@@ -2076,8 +2138,7 @@ function extractLocales({ component }) {
2076
2138
  return variations;
2077
2139
  }
2078
2140
  function localize(options) {
2079
- const nodes = options.nodes;
2080
- const locale = options.locale;
2141
+ const { nodes, locale, keepLocalesFor } = options;
2081
2142
  if (!locale) {
2082
2143
  return;
2083
2144
  }
@@ -2085,7 +2146,7 @@ function localize(options) {
2085
2146
  walkNodeTree(nodes, (context) => {
2086
2147
  const { type, node, actions } = context;
2087
2148
  if (type !== "component") {
2088
- localizeProperties(node, locale, vizControlLocaleRule);
2149
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
2089
2150
  return;
2090
2151
  }
2091
2152
  const result = evaluateWalkTreeNodeVisibility({
@@ -2106,7 +2167,7 @@ function localize(options) {
2106
2167
  if (replaceComponent == null ? void 0 : replaceComponent.length) {
2107
2168
  replaceComponent.forEach((component) => {
2108
2169
  removeLocaleProperty(component);
2109
- localizeProperties(component, locale, vizControlLocaleRule);
2170
+ localizeProperties(component, locale, vizControlLocaleRule, keepLocalesFor);
2110
2171
  });
2111
2172
  const [first, ...rest] = replaceComponent;
2112
2173
  actions.replace(first);
@@ -2117,7 +2178,7 @@ function localize(options) {
2117
2178
  actions.remove();
2118
2179
  }
2119
2180
  } else {
2120
- localizeProperties(node, locale, vizControlLocaleRule);
2181
+ localizeProperties(node, locale, vizControlLocaleRule, keepLocalesFor);
2121
2182
  }
2122
2183
  });
2123
2184
  }
@@ -2136,7 +2197,7 @@ function removeLocaleProperty(component) {
2136
2197
  }
2137
2198
  }
2138
2199
  }
2139
- function localizeProperties(node, locale, rules) {
2200
+ function localizeProperties(node, locale, rules, keepLocalesFor) {
2140
2201
  const properties = getPropertiesValue(node);
2141
2202
  if (!properties) {
2142
2203
  return void 0;
@@ -2155,10 +2216,16 @@ function localizeProperties(node, locale, rules) {
2155
2216
  if (currentLocaleConditionalValues !== void 0) {
2156
2217
  propertyValue.conditions = currentLocaleConditionalValues;
2157
2218
  }
2158
- delete propertyValue.locales;
2159
- 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
+ }
2160
2224
  if (propertyValue.value === void 0 && propertyValue.conditions === void 0) {
2161
- delete properties[propertyId];
2225
+ const hasLocales = preserveLocales && (propertyValue.locales || propertyValue.localesConditions);
2226
+ if (!hasLocales) {
2227
+ delete properties[propertyId];
2228
+ }
2162
2229
  }
2163
2230
  });
2164
2231
  evaluateWalkTreePropertyCriteria({
@@ -2837,6 +2904,173 @@ __privateAdd(_ProjectClient, _url2, "/api/v1/project");
2837
2904
  __privateAdd(_ProjectClient, _projectsUrl, "/api/v1/projects");
2838
2905
  var ProjectClient = _ProjectClient;
2839
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
+
2840
3074
  // src/PromptClient.ts
2841
3075
  var import_api13 = require("@uniformdev/context/api");
2842
3076
  var PromptsUrl = "/api/v1/prompts";
@@ -2965,7 +3199,9 @@ var RouteClient = class extends import_api17.ApiClient {
2965
3199
  /** Fetches lists of Canvas compositions, optionally by type */
2966
3200
  async getRoute(options) {
2967
3201
  const { projectId } = this.options;
2968
- 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);
2969
3205
  return await this.apiClient(
2970
3206
  fetchUri,
2971
3207
  this.options.disableSWR ? { headers: { "x-disable-swr": "true" } } : void 0
@@ -3328,7 +3564,7 @@ function handleRichTextNodeBinding(object, options) {
3328
3564
  var import_api19 = require("@uniformdev/context/api");
3329
3565
 
3330
3566
  // src/.version.ts
3331
- var version = "20.71.0";
3567
+ var version = "20.71.1";
3332
3568
 
3333
3569
  // src/WorkflowClient.ts
3334
3570
  var import_api18 = require("@uniformdev/context/api");
@@ -3450,6 +3686,7 @@ var CanvasClientError = import_api19.ApiClientError;
3450
3686
  ReleaseContentsClient,
3451
3687
  RouteClient,
3452
3688
  SECRET_QUERY_STRING_PARAM,
3689
+ SELECT_QUERY_PREFIX,
3453
3690
  UncachedCanvasClient,
3454
3691
  UncachedCategoryClient,
3455
3692
  UncachedContentClient,
@@ -3531,10 +3768,13 @@ var CanvasClientError = import_api19.ApiClientError;
3531
3768
  localize,
3532
3769
  mapSlotToPersonalizedVariations,
3533
3770
  mapSlotToTestVariations,
3771
+ matchesProjectionPattern,
3534
3772
  mergeAssetConfigWithDefaults,
3535
3773
  nullLimitPolicy,
3536
3774
  parseComponentPlaceholderId,
3537
3775
  parseVariableExpression,
3776
+ projectionToQuery,
3777
+ queryToProjection,
3538
3778
  version,
3539
3779
  walkNodeTree,
3540
3780
  walkPropertyValues