@uniformdev/canvas 19.68.1-alpha.27 → 19.71.1-alpha.103

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
@@ -717,12 +717,13 @@ var _ContentClient = class _ContentClient extends ApiClient4 {
717
717
  });
718
718
  return this.apiClient(historyUrl);
719
719
  }
720
- async upsertContentType(body) {
720
+ async upsertContentType(body, opts = {}) {
721
721
  const fetchUri = this.createUrl(__privateGet(_ContentClient, _contentTypesUrl));
722
722
  await this.apiClient(fetchUri, {
723
723
  method: "PUT",
724
724
  body: JSON.stringify({ ...body, projectId: this.options.projectId }),
725
- expectNoContent: true
725
+ expectNoContent: true,
726
+ headers: opts.autogenerateDataTypes ? { "x-uniform-autogenerate-data-types": "true" } : {}
726
727
  });
727
728
  }
728
729
  async upsertEntry(body) {
@@ -999,25 +1000,60 @@ var EDGE_MIN_CACHE_TTL = 10;
999
1000
  var EDGE_MAX_CACHE_TTL = 24 * 60 * 60;
1000
1001
  var EDGE_DEFAULT_CACHE_TTL = 30;
1001
1002
  var EDGE_CACHE_DISABLED = -1;
1003
+ var ASSET_PARAMETER_TYPE = "asset";
1004
+ var ASSETS_SOURCE_UNIFORM = "uniform-assets";
1005
+ var ASSETS_SOURCE_CUSTOM_URL = "custom-url";
1002
1006
 
1003
- // src/utils/entryConverter.ts
1004
- function convertEntryToPutEntry(entry) {
1005
- return {
1006
- entry: {
1007
- type: entry.entry.type,
1008
- _dataResources: entry.entry._dataResources,
1009
- _id: entry.entry._id,
1010
- _name: entry.entry._name,
1011
- _slug: entry.entry._slug,
1012
- fields: entry.entry.fields
1013
- },
1014
- state: entry.state,
1015
- projectId: entry.projectId
1016
- };
1007
+ // src/utils/guards.ts
1008
+ function isRootEntryReference(root) {
1009
+ return root.type === "root" && isEntryData(root.node);
1010
+ }
1011
+ function isEntryData(entryData) {
1012
+ return Boolean(entryData && typeof entryData === "object" && "fields" in entryData);
1013
+ }
1014
+ function isAssetParamValue(value) {
1015
+ return Array.isArray(value) && (value.length > 0 ? isAssetParamValueItem(value[0]) : true);
1017
1016
  }
1017
+ function isAssetParamValueItem(item) {
1018
+ return Boolean(
1019
+ item instanceof Object && "_source" in item && "fields" in item && item.fields instanceof Object && "url" in item.fields && item.fields.url instanceof Object
1020
+ );
1021
+ }
1022
+
1023
+ // src/utils/properties.ts
1018
1024
  function getPropertiesValue(entity) {
1019
1025
  return "parameters" in entity && entity.parameters ? entity.parameters : "fields" in entity && entity.fields ? entity.fields : void 0;
1020
1026
  }
1027
+ function getPropertyValue(parameter) {
1028
+ return parameter ? parameter.value : parameter;
1029
+ }
1030
+ function flattenValues(data, options = {}) {
1031
+ if (!data) {
1032
+ return data;
1033
+ } else if (Array.isArray(data) && options.toSingle) {
1034
+ return data.length > 0 ? flattenSingleNodeValues(data[0]) : void 0;
1035
+ } else if (Array.isArray(data)) {
1036
+ return data.map((node) => flattenSingleNodeValues(node, options));
1037
+ } else {
1038
+ return flattenSingleNodeValues(data, options);
1039
+ }
1040
+ }
1041
+ function flattenSingleNodeValues(data, options = {}) {
1042
+ const { levels = 1 } = options;
1043
+ const properties = getPropertiesValue(data);
1044
+ return properties ? Object.fromEntries(
1045
+ Object.entries(properties).map(([id, parameter]) => {
1046
+ const value = getPropertyValue(parameter);
1047
+ if (levels > 0 && Array.isArray(value) && // In the future ASSET_PARAMETER_TYPE will be a nested data type
1048
+ (isNestedNodeType(parameter.type) || parameter.type === ASSET_PARAMETER_TYPE)) {
1049
+ const nestedOptions = { ...options, levels: levels - 1 };
1050
+ return [id, value.map((item) => flattenValues(item, nestedOptions))];
1051
+ } else {
1052
+ return [id, value];
1053
+ }
1054
+ })
1055
+ ) : properties;
1056
+ }
1021
1057
 
1022
1058
  // src/enhancement/walkNodeTree.ts
1023
1059
  function walkNodeTree(node, visitor, options) {
@@ -1037,7 +1073,83 @@ function walkNodeTree(node, visitor, options) {
1037
1073
  let visitDescendants = true;
1038
1074
  let descendantContext = (_a = childContexts.get(currentComponent.node)) != null ? _a : currentQueueEntry.context;
1039
1075
  let visitorInfo;
1040
- if (currentComponent.type === "root" || currentComponent.type === "slot") {
1076
+ if (currentComponent.type === "root" && isRootEntryReference(currentComponent) || currentComponent.type === "block") {
1077
+ visitorInfo = {
1078
+ type: "entry",
1079
+ node: currentComponent.node,
1080
+ ancestorsAndSelf: currentQueueEntry.ancestorsAndSelf,
1081
+ actions: {
1082
+ replace: (replacementNode) => {
1083
+ Object.assign(currentComponent.node, replacementNode);
1084
+ const propertiesToCheck = ["fields", "_dataResources", "_author"];
1085
+ propertiesToCheck.forEach((property) => {
1086
+ if (!replacementNode[property]) {
1087
+ delete currentComponent.node[property];
1088
+ }
1089
+ });
1090
+ },
1091
+ remove: () => {
1092
+ const currentComponentLocation = currentQueueEntry.ancestorsAndSelf[0];
1093
+ const parentComponent = currentQueueEntry.ancestorsAndSelf[1];
1094
+ if (currentComponentLocation.type === "block") {
1095
+ const { fieldName, blockIndex } = currentComponentLocation;
1096
+ const blockValue = getBlockValue(parentComponent.node, fieldName);
1097
+ blockValue.splice(blockIndex, 1);
1098
+ if (blockValue.length === 0) {
1099
+ const properties2 = getPropertiesValue(parentComponent.node);
1100
+ delete properties2[fieldName];
1101
+ }
1102
+ } else {
1103
+ throw new Error("Unknown node type");
1104
+ }
1105
+ },
1106
+ insertAfter: (nodes) => {
1107
+ const currentNodeInfo = currentQueueEntry.ancestorsAndSelf[0];
1108
+ if (currentNodeInfo.type !== "block") {
1109
+ throw new Error("Unknown type");
1110
+ }
1111
+ const { fieldName, blockIndex } = currentNodeInfo;
1112
+ const parentComponent = currentQueueEntry.ancestorsAndSelf[1];
1113
+ const nodesToInsert = Array.isArray(nodes) ? nodes : [nodes];
1114
+ if (fieldName && typeof blockIndex !== "undefined") {
1115
+ getPropertiesValue(parentComponent.node)[fieldName].value.splice(
1116
+ blockIndex + 1,
1117
+ 0,
1118
+ ...nodesToInsert
1119
+ );
1120
+ componentQueue.unshift(
1121
+ ...nodesToInsert.map((enqueueingComponent) => ({
1122
+ ancestorsAndSelf: [
1123
+ {
1124
+ type: "block",
1125
+ node: enqueueingComponent,
1126
+ fieldName,
1127
+ get blockIndex() {
1128
+ const parentArray = getPropertiesValue(parentComponent.node)[fieldName].value;
1129
+ return parentArray.findIndex((x) => x === enqueueingComponent);
1130
+ }
1131
+ },
1132
+ // slice removes 'self' since we are inserting a peer of self
1133
+ ...currentQueueEntry.ancestorsAndSelf.slice(1)
1134
+ ],
1135
+ context: descendantContext
1136
+ }))
1137
+ );
1138
+ }
1139
+ },
1140
+ stopProcessingDescendants() {
1141
+ visitDescendants = false;
1142
+ },
1143
+ setDescendantsContext(context) {
1144
+ descendantContext = context;
1145
+ },
1146
+ setChildContext(child, context) {
1147
+ childContexts.set(child, context);
1148
+ }
1149
+ },
1150
+ context: descendantContext
1151
+ };
1152
+ } else {
1041
1153
  visitorInfo = {
1042
1154
  type: "component",
1043
1155
  node: currentComponent.node,
@@ -1128,82 +1240,6 @@ function walkNodeTree(node, visitor, options) {
1128
1240
  },
1129
1241
  context: descendantContext
1130
1242
  };
1131
- } else {
1132
- visitorInfo = {
1133
- type: "entry",
1134
- node: currentComponent.node,
1135
- ancestorsAndSelf: currentQueueEntry.ancestorsAndSelf,
1136
- actions: {
1137
- replace: (replacementNode) => {
1138
- Object.assign(currentComponent.node, replacementNode);
1139
- const propertiesToCheck = ["fields", "_dataResources", "_author"];
1140
- propertiesToCheck.forEach((property) => {
1141
- if (!replacementNode[property]) {
1142
- delete currentComponent.node[property];
1143
- }
1144
- });
1145
- },
1146
- remove: () => {
1147
- const currentComponentLocation = currentQueueEntry.ancestorsAndSelf[0];
1148
- const parentComponent = currentQueueEntry.ancestorsAndSelf[1];
1149
- if (currentComponentLocation.type === "block") {
1150
- const { fieldName, blockIndex } = currentComponentLocation;
1151
- const blockValue = getBlockValue(parentComponent.node, fieldName);
1152
- blockValue.splice(blockIndex, 1);
1153
- if (blockValue.length === 0) {
1154
- const properties2 = getPropertiesValue(parentComponent.node);
1155
- delete properties2[fieldName];
1156
- }
1157
- } else {
1158
- throw new Error("Unknown node type");
1159
- }
1160
- },
1161
- insertAfter: (nodes) => {
1162
- const currentNodeInfo = currentQueueEntry.ancestorsAndSelf[0];
1163
- if (currentNodeInfo.type !== "block") {
1164
- throw new Error("Unknown type");
1165
- }
1166
- const { fieldName, blockIndex } = currentNodeInfo;
1167
- const parentComponent = currentQueueEntry.ancestorsAndSelf[1];
1168
- const nodesToInsert = Array.isArray(nodes) ? nodes : [nodes];
1169
- if (fieldName && typeof blockIndex !== "undefined") {
1170
- getPropertiesValue(parentComponent.node)[fieldName].value.splice(
1171
- blockIndex + 1,
1172
- 0,
1173
- ...nodesToInsert
1174
- );
1175
- componentQueue.unshift(
1176
- ...nodesToInsert.map((enqueueingComponent) => ({
1177
- ancestorsAndSelf: [
1178
- {
1179
- type: "block",
1180
- node: enqueueingComponent,
1181
- fieldName,
1182
- get blockIndex() {
1183
- const parentArray = getPropertiesValue(parentComponent.node)[fieldName].value;
1184
- return parentArray.findIndex((x) => x === enqueueingComponent);
1185
- }
1186
- },
1187
- // slice removes 'self' since we are inserting a peer of self
1188
- ...currentQueueEntry.ancestorsAndSelf.slice(1)
1189
- ],
1190
- context: descendantContext
1191
- }))
1192
- );
1193
- }
1194
- },
1195
- stopProcessingDescendants() {
1196
- visitDescendants = false;
1197
- },
1198
- setDescendantsContext(context) {
1199
- descendantContext = context;
1200
- },
1201
- setChildContext(child, context) {
1202
- childContexts.set(child, context);
1203
- }
1204
- },
1205
- context: descendantContext
1206
- };
1207
1243
  }
1208
1244
  visitor(visitorInfo);
1209
1245
  if (!visitDescendants) {
@@ -1241,7 +1277,7 @@ function walkNodeTree(node, visitor, options) {
1241
1277
  const propertyEntries = Object.entries(properties);
1242
1278
  for (let propIndex = propertyEntries.length - 1; propIndex >= 0; propIndex--) {
1243
1279
  const [propKey, propObject] = propertyEntries[propIndex];
1244
- if (propObject.type !== CANVAS_BLOCK_PARAM_TYPE)
1280
+ if (!isNestedNodeType(propObject.type))
1245
1281
  continue;
1246
1282
  const blocks = (_b = propObject.value) != null ? _b : [];
1247
1283
  for (let blockIndex = blocks.length - 1; blockIndex >= 0; blockIndex--) {
@@ -1267,6 +1303,9 @@ function walkNodeTree(node, visitor, options) {
1267
1303
  }
1268
1304
  } while (componentQueue.length > 0);
1269
1305
  }
1306
+ function isNestedNodeType(type) {
1307
+ return type === CANVAS_BLOCK_PARAM_TYPE;
1308
+ }
1270
1309
  function getBlockValue(component, parameterName) {
1271
1310
  var _a;
1272
1311
  const parameter = (_a = getPropertiesValue(component)) == null ? void 0 : _a[parameterName];
@@ -1535,7 +1574,7 @@ function getComponentJsonPointer(ancestorsAndSelf) {
1535
1574
  if (currentLocation.type === "block") {
1536
1575
  const { fieldName: parameterName, blockIndex } = currentLocation;
1537
1576
  if (parameterName && blockIndex !== void 0) {
1538
- const noun = parentLocation && "type" in parentLocation && parentLocation.type === "block" ? "fields" : "parameters";
1577
+ const noun = getNounForLocation(parentLocation);
1539
1578
  path.push(`${noun}/${parameterName}/value/${blockIndex}`);
1540
1579
  }
1541
1580
  } else {
@@ -1549,6 +1588,40 @@ function getComponentJsonPointer(ancestorsAndSelf) {
1549
1588
  }
1550
1589
  return `/${path.join("/")}`;
1551
1590
  }
1591
+ function getNounForLocation(parentLocation) {
1592
+ let noun = "parameters";
1593
+ if (parentLocation && "type" in parentLocation) {
1594
+ if (parentLocation.type === "block" || isRootEntryReference(parentLocation)) {
1595
+ noun = "fields";
1596
+ }
1597
+ }
1598
+ return noun;
1599
+ }
1600
+ function getNounForNode(node) {
1601
+ let noun = "parameters";
1602
+ if (isEntryData(node)) {
1603
+ noun = "fields";
1604
+ }
1605
+ return noun;
1606
+ }
1607
+
1608
+ // src/enhancement/findInNodeTree.ts
1609
+ function findParameterInNodeTree(data, predicate) {
1610
+ const results = [];
1611
+ walkNodeTree(data, ({ node, ancestorsAndSelf }) => {
1612
+ const parameters = getPropertiesValue(node);
1613
+ if (parameters) {
1614
+ Object.entries(parameters).filter(([key, field]) => predicate(field, key, node)).forEach(([key, field]) => {
1615
+ results.push({
1616
+ key,
1617
+ pointer: (ancestorsAndSelf.length === 1 ? "" : getComponentJsonPointer(ancestorsAndSelf)) + `/${getNounForNode(node)}/${key}`,
1618
+ parameter: field
1619
+ });
1620
+ });
1621
+ }
1622
+ });
1623
+ return results;
1624
+ }
1552
1625
 
1553
1626
  // src/enhancement/localize.ts
1554
1627
  function extractLocales({ component }) {
@@ -1565,18 +1638,22 @@ function extractLocales({ component }) {
1565
1638
  });
1566
1639
  return variations;
1567
1640
  }
1568
- function localize({
1569
- composition,
1570
- locale
1571
- }) {
1572
- walkNodeTree(composition, ({ type, node, actions }) => {
1641
+ function localize(options) {
1642
+ const nodes = "nodes" in options ? options.nodes : options.composition;
1643
+ const locale = options.locale;
1644
+ walkNodeTree(nodes, ({ type, node, actions }) => {
1573
1645
  if (type !== "component") {
1574
- actions.stopProcessingDescendants();
1646
+ if (typeof locale === "string") {
1647
+ localizeProperties(node.fields, locale);
1648
+ }
1575
1649
  return;
1576
1650
  }
1651
+ if (typeof locale === "string") {
1652
+ localizeProperties(getPropertiesValue(node), locale);
1653
+ }
1577
1654
  if (node.type === CANVAS_LOCALIZATION_TYPE) {
1578
1655
  const locales = extractLocales({ component: node });
1579
- const resolvedLocale = typeof locale === "string" ? locale : locale({ component: node, locales });
1656
+ const resolvedLocale = typeof locale === "string" ? locale : locale == null ? void 0 : locale({ component: node, locales });
1580
1657
  let replaceComponent;
1581
1658
  if (resolvedLocale) {
1582
1659
  replaceComponent = locales[resolvedLocale];
@@ -1593,6 +1670,25 @@ function localize({
1593
1670
  }
1594
1671
  });
1595
1672
  }
1673
+ function localizeProperties(properties, locale) {
1674
+ if (!properties) {
1675
+ return void 0;
1676
+ }
1677
+ Object.entries(properties).forEach(([key, property]) => {
1678
+ var _a;
1679
+ if (!locale) {
1680
+ delete property.locales;
1681
+ }
1682
+ const currentLocaleValue = locale ? (_a = property.locales) == null ? void 0 : _a[locale] : void 0;
1683
+ if (currentLocaleValue !== void 0) {
1684
+ property.value = currentLocaleValue;
1685
+ }
1686
+ delete property.locales;
1687
+ if (property.value === void 0) {
1688
+ delete properties[key];
1689
+ }
1690
+ });
1691
+ }
1596
1692
 
1597
1693
  // src/enhancement/UniqueBatchEntries.ts
1598
1694
  var UniqueBatchEntries = class {
@@ -1739,6 +1835,39 @@ function walkComponentTree(component, visitor, initialContext) {
1739
1835
  } while (componentQueue.length > 0);
1740
1836
  }
1741
1837
 
1838
+ // src/LocaleClient.ts
1839
+ import { ApiClient as ApiClient7 } from "@uniformdev/context/api";
1840
+ var localesUrl = "/api/v1/locales";
1841
+ var LocaleClient = class extends ApiClient7 {
1842
+ constructor(options) {
1843
+ super(options);
1844
+ }
1845
+ /** Fetches all locales for a project */
1846
+ async get(options) {
1847
+ const { projectId } = this.options;
1848
+ const fetchUri = this.createUrl(localesUrl, { ...options, projectId });
1849
+ return await this.apiClient(fetchUri);
1850
+ }
1851
+ /** Updates or creates (based on id) a locale */
1852
+ async upsert(body) {
1853
+ const fetchUri = this.createUrl(localesUrl);
1854
+ await this.apiClient(fetchUri, {
1855
+ method: "PUT",
1856
+ body: JSON.stringify({ ...body, projectId: this.options.projectId }),
1857
+ expectNoContent: true
1858
+ });
1859
+ }
1860
+ /** Deletes a locale */
1861
+ async remove(body) {
1862
+ const fetchUri = this.createUrl(localesUrl);
1863
+ await this.apiClient(fetchUri, {
1864
+ method: "DELETE",
1865
+ body: JSON.stringify({ ...body, projectId: this.options.projectId }),
1866
+ expectNoContent: true
1867
+ });
1868
+ }
1869
+ };
1870
+
1742
1871
  // src/utils/hash.ts
1743
1872
  var generateHash = ({
1744
1873
  composition,
@@ -1826,7 +1955,7 @@ var createCanvasChannel = ({
1826
1955
  };
1827
1956
  postMessage(message);
1828
1957
  };
1829
- const ready = () => {
1958
+ const ready = (options) => {
1830
1959
  var _a, _b;
1831
1960
  if (typeof window === "undefined") {
1832
1961
  return;
@@ -1836,7 +1965,8 @@ var createCanvasChannel = ({
1836
1965
  const message = {
1837
1966
  type: "ready",
1838
1967
  framework,
1839
- version
1968
+ version,
1969
+ rsc: options == null ? void 0 : options.rsc
1840
1970
  };
1841
1971
  postMessage(message);
1842
1972
  };
@@ -2095,28 +2225,21 @@ function subscribeToComposition({
2095
2225
  }
2096
2226
 
2097
2227
  // src/PromptClient.ts
2098
- import { ApiClient as ApiClient7 } from "@uniformdev/context/api";
2099
- var PromptUrl = "/api/v1/prompt";
2228
+ import { ApiClient as ApiClient8 } from "@uniformdev/context/api";
2100
2229
  var PromptsUrl = "/api/v1/prompts";
2101
- var PromptClient = class extends ApiClient7 {
2230
+ var PromptClient = class extends ApiClient8 {
2102
2231
  constructor(options) {
2103
2232
  super(options);
2104
2233
  }
2105
- /** Fetches all Prompts for a project */
2234
+ /** Fetches Prompts for a project */
2106
2235
  async get(options) {
2107
- const { projectId } = this.options;
2108
- const fetchUri = this.createUrl(PromptUrl, { ...options, projectId });
2109
- return await this.apiClient(fetchUri);
2110
- }
2111
- /** Fetches all Prompts for a project */
2112
- async getList(options) {
2113
2236
  const { projectId } = this.options;
2114
2237
  const fetchUri = this.createUrl(PromptsUrl, { ...options, projectId });
2115
2238
  return await this.apiClient(fetchUri);
2116
2239
  }
2117
2240
  /** Updates or creates (based on id) a Prompt */
2118
2241
  async upsert(body) {
2119
- const fetchUri = this.createUrl(PromptUrl);
2242
+ const fetchUri = this.createUrl(PromptsUrl);
2120
2243
  await this.apiClient(fetchUri, {
2121
2244
  method: "PUT",
2122
2245
  body: JSON.stringify({ ...body, projectId: this.options.projectId }),
@@ -2125,7 +2248,7 @@ var PromptClient = class extends ApiClient7 {
2125
2248
  }
2126
2249
  /** Deletes a Prompt */
2127
2250
  async remove(body) {
2128
- const fetchUri = this.createUrl(PromptUrl);
2251
+ const fetchUri = this.createUrl(PromptsUrl);
2129
2252
  await this.apiClient(fetchUri, {
2130
2253
  method: "DELETE",
2131
2254
  body: JSON.stringify({ ...body, projectId: this.options.projectId }),
@@ -2135,9 +2258,9 @@ var PromptClient = class extends ApiClient7 {
2135
2258
  };
2136
2259
 
2137
2260
  // src/RouteClient.ts
2138
- import { ApiClient as ApiClient8 } from "@uniformdev/context/api";
2261
+ import { ApiClient as ApiClient9 } from "@uniformdev/context/api";
2139
2262
  var ROUTE_URL = "/api/v1/route";
2140
- var RouteClient = class extends ApiClient8 {
2263
+ var RouteClient = class extends ApiClient9 {
2141
2264
  constructor(options) {
2142
2265
  var _a;
2143
2266
  if (!options.limitPolicy) {
@@ -2154,6 +2277,9 @@ var RouteClient = class extends ApiClient8 {
2154
2277
  }
2155
2278
  };
2156
2279
 
2280
+ // src/types/locales.ts
2281
+ var LOCALE_DYNAMIC_INPUT_NAME = "locale";
2282
+
2157
2283
  // src/utils/createApiEnhancer.ts
2158
2284
  var createUniformApiEnhancer = ({ apiUrl }) => {
2159
2285
  return async (message) => {
@@ -2176,6 +2302,23 @@ var createUniformApiEnhancer = ({ apiUrl }) => {
2176
2302
  };
2177
2303
  };
2178
2304
 
2305
+ // src/utils/entryConverter.ts
2306
+ function convertEntryToPutEntry(entry) {
2307
+ return {
2308
+ entry: {
2309
+ type: entry.entry.type,
2310
+ _dataResources: entry.entry._dataResources,
2311
+ _id: entry.entry._id,
2312
+ _name: entry.entry._name,
2313
+ _slug: entry.entry._slug,
2314
+ fields: entry.entry.fields,
2315
+ _locales: entry.entry._locales
2316
+ },
2317
+ state: entry.state,
2318
+ projectId: entry.projectId
2319
+ };
2320
+ }
2321
+
2179
2322
  // src/utils/getParameterAttributes.ts
2180
2323
  var ATTRIBUTE_COMPONENT_ID = "data-uniform-component-id";
2181
2324
  var ATTRIBUTE_PARAMETER_ID = "data-uniform-parameter-id";
@@ -2253,6 +2396,9 @@ var isComponentPlaceholderId = (id) => {
2253
2396
  if (id === PLACEHOLDER_ID) {
2254
2397
  return true;
2255
2398
  }
2399
+ if (typeof id !== "string") {
2400
+ return false;
2401
+ }
2256
2402
  return id == null ? void 0 : id.startsWith(PLACEHOLDER_ID);
2257
2403
  };
2258
2404
  var generateComponentPlaceholderId = (randomId, sdkVersion) => {
@@ -2302,9 +2448,14 @@ function parseVariableExpression(serialized, onToken) {
2302
2448
  continue;
2303
2449
  }
2304
2450
  if (char === variableSuffix && state === "variable") {
2451
+ if (serialized[index - 1] === escapeCharacter) {
2452
+ bufferEndIndex++;
2453
+ continue;
2454
+ }
2305
2455
  state = "text";
2306
2456
  if (bufferEndIndex > bufferStartIndex) {
2307
- if (handleToken(serialized.substring(bufferStartIndex, bufferEndIndex), "variable") === false) {
2457
+ const unescapedVariableName = serialized.substring(bufferStartIndex, bufferEndIndex).replace(/\\([${}])/g, "$1");
2458
+ if (handleToken(unescapedVariableName, "variable") === false) {
2308
2459
  return tokenCount;
2309
2460
  }
2310
2461
  bufferStartIndex = bufferEndIndex + variableSuffix.length;
@@ -2364,7 +2515,7 @@ import { produce } from "immer";
2364
2515
 
2365
2516
  // src/utils/variables/createVariableReference.ts
2366
2517
  function createVariableReference(variableName) {
2367
- return `\${${variableName}}`;
2518
+ return `\${${variableName.replace(/([${}])/g, "\\$1")}}`;
2368
2519
  }
2369
2520
 
2370
2521
  // src/utils/variables/bindVariablesToObject.ts
@@ -2448,6 +2599,9 @@ function handleRichTextNodeBinding(object, options) {
2448
2599
  import { ApiClientError as ApiClientError2 } from "@uniformdev/context/api";
2449
2600
  var CanvasClientError = ApiClientError2;
2450
2601
  export {
2602
+ ASSETS_SOURCE_CUSTOM_URL,
2603
+ ASSETS_SOURCE_UNIFORM,
2604
+ ASSET_PARAMETER_TYPE,
2451
2605
  ATTRIBUTE_COMPONENT_ID,
2452
2606
  ATTRIBUTE_MULTILINE,
2453
2607
  ATTRIBUTE_PARAMETER_ID,
@@ -2491,6 +2645,8 @@ export {
2491
2645
  IN_CONTEXT_EDITOR_PLAYGROUND_QUERY_STRING_PARAM,
2492
2646
  IN_CONTEXT_EDITOR_QUERY_STRING_PARAM,
2493
2647
  IS_RENDERED_BY_UNIFORM_ATTRIBUTE,
2648
+ LOCALE_DYNAMIC_INPUT_NAME,
2649
+ LocaleClient,
2494
2650
  PLACEHOLDER_ID,
2495
2651
  PromptClient,
2496
2652
  RouteClient,
@@ -2511,23 +2667,33 @@ export {
2511
2667
  createVariableReference,
2512
2668
  enhance,
2513
2669
  extractLocales,
2670
+ findParameterInNodeTree,
2671
+ flattenValues,
2514
2672
  generateComponentPlaceholderId,
2515
2673
  generateHash,
2516
2674
  getBlockValue,
2517
2675
  getChannelName,
2518
2676
  getComponentJsonPointer,
2519
2677
  getComponentPath,
2678
+ getNounForLocation,
2679
+ getNounForNode,
2520
2680
  getParameterAttributes,
2521
2681
  getPropertiesValue,
2682
+ getPropertyValue,
2522
2683
  isAddComponentMessage,
2523
2684
  isAllowedReferrer,
2685
+ isAssetParamValue,
2686
+ isAssetParamValueItem,
2524
2687
  isComponentActionMessage,
2525
2688
  isComponentPlaceholderId,
2526
2689
  isDismissPlaceholderMessage,
2690
+ isEntryData,
2527
2691
  isMovingComponentMessage,
2692
+ isNestedNodeType,
2528
2693
  isOpenParameterEditorMessage,
2529
2694
  isReadyMessage,
2530
2695
  isReportRenderedCompositionsMessage,
2696
+ isRootEntryReference,
2531
2697
  isSelectComponentMessage,
2532
2698
  isSelectParameterMessage,
2533
2699
  isSystemComponentDefinition,