@uniformdev/next-app-router-shared 20.54.0 → 20.55.0

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.d.mts CHANGED
@@ -79,9 +79,8 @@ declare const resolveRuleFromPageState: ({ pageState, rule, }: {
79
79
  pageState: PageState;
80
80
  rule: VisibilityParameterValue;
81
81
  }) => boolean | undefined;
82
- declare const serializeEvaluationResult: ({ payload, encode, }: {
82
+ declare const serializeEvaluationResult: ({ payload }: {
83
83
  payload: PageState;
84
- encode?: boolean;
85
84
  }) => string;
86
85
  declare const deserializeEvaluationResult: ({ input: providedInput, decode, }: {
87
86
  input: string;
package/dist/index.d.ts CHANGED
@@ -79,9 +79,8 @@ declare const resolveRuleFromPageState: ({ pageState, rule, }: {
79
79
  pageState: PageState;
80
80
  rule: VisibilityParameterValue;
81
81
  }) => boolean | undefined;
82
- declare const serializeEvaluationResult: ({ payload, encode, }: {
82
+ declare const serializeEvaluationResult: ({ payload }: {
83
83
  payload: PageState;
84
- encode?: boolean;
85
84
  }) => string;
86
85
  declare const deserializeEvaluationResult: ({ input: providedInput, decode, }: {
87
86
  input: string;
package/dist/index.esm.js CHANGED
@@ -160,23 +160,11 @@ var resolveRuleFromPageState = ({
160
160
  }
161
161
  return value;
162
162
  };
163
- var replaceReservedCharacters = (value) => {
164
- return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
165
- return acc.replaceAll(char.character, char.replacement);
166
- }, value);
167
- };
168
163
  var unreplaceReservedCharacters = (value) => {
169
164
  return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
170
165
  return acc.replaceAll(char.replacement, char.character);
171
166
  }, value);
172
167
  };
173
- var encodeWithReplacements = (value) => {
174
- return replaceReservedCharacters(btoa(value));
175
- };
176
- var decodeWithReplacements = (value) => {
177
- const urlDecoded = decodeURIComponent(value);
178
- return atob(unreplaceReservedCharacters(urlDecoded));
179
- };
180
168
  var compressIds = (ids) => {
181
169
  const uuidV4Length = 36;
182
170
  let compressedRegistry;
@@ -206,22 +194,58 @@ var compressIds = (ids) => {
206
194
  );
207
195
  };
208
196
  var NAMESPACE_UUID = "00000000-0000-0000-0000-000000000000";
209
- var serializeEvaluationResult = ({
210
- payload,
211
- encode = true
212
- }) => {
213
- const compressedPageState = {
214
- cs: payload.compositionState,
215
- r: payload.routePath,
216
- c: {},
217
- k: payload.keys,
218
- ri: payload.releaseId,
219
- dc: typeof payload.defaultConsent !== "undefined" ? payload.defaultConsent ? 1 : 0 : void 0,
220
- pm: payload.previewMode === "editor" ? "e" : payload.previewMode === "preview" ? "p" : void 0,
221
- rl: void 0,
222
- l: payload.locale,
223
- pf: payload.isPrefetch ? 1 : void 0
197
+ var V2_FIELD_SEP = "~";
198
+ var V2_ENTRY_SEP = ".";
199
+ var V2_KV_SEP = ":";
200
+ var V2_INDEX_SEP = ",";
201
+ var toBase64Url = (value) => {
202
+ const bytes = new TextEncoder().encode(value);
203
+ const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("");
204
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
205
+ };
206
+ var fromBase64Url = (value) => {
207
+ let base64 = value.replace(/-/g, "+").replace(/_/g, "/");
208
+ const pad = base64.length % 4;
209
+ if (pad === 2) {
210
+ base64 += "==";
211
+ } else if (pad === 3) {
212
+ base64 += "=";
213
+ }
214
+ const binary = atob(base64);
215
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
216
+ return new TextDecoder().decode(bytes);
217
+ };
218
+ var encodeFlags = (payload) => {
219
+ let flags = 0;
220
+ if (typeof payload.defaultConsent !== "undefined") {
221
+ flags |= 1;
222
+ if (payload.defaultConsent) {
223
+ flags |= 2;
224
+ }
225
+ }
226
+ if (payload.previewMode === "editor") {
227
+ flags |= 4;
228
+ }
229
+ if (payload.previewMode === "preview") {
230
+ flags |= 8;
231
+ }
232
+ if (payload.isPrefetch) {
233
+ flags |= 16;
234
+ }
235
+ return flags.toString(16);
236
+ };
237
+ var decodeFlags = (hex) => {
238
+ const flags = parseInt(hex, 16) || 0;
239
+ return {
240
+ defaultConsent: flags & 1 ? Boolean(flags & 2) : void 0,
241
+ previewMode: flags & 4 ? "editor" : flags & 8 ? "preview" : void 0,
242
+ isPrefetch: flags & 16 ? true : void 0
224
243
  };
244
+ };
245
+ var serializeV2 = (payload) => {
246
+ const parts = ["2"];
247
+ parts.push(String(payload.compositionState));
248
+ parts.push(toBase64Url(payload.routePath));
225
249
  const componentKeys = Object.keys(payload.components);
226
250
  const sortedKeys = componentKeys.sort();
227
251
  const sortedComponents = sortedKeys.map((key) => ({
@@ -229,39 +253,146 @@ var serializeEvaluationResult = ({
229
253
  ...payload.components[key]
230
254
  }));
231
255
  const compressedComponentIds = compressIds(sortedComponents.map((c) => c._id));
256
+ const componentById = new Map(sortedComponents.map((c) => [c._id, c]));
257
+ const componentEntries = [];
232
258
  Object.keys(compressedComponentIds).forEach((compressedId) => {
233
259
  var _a;
234
260
  const originalId = compressedComponentIds[compressedId];
235
- const component = sortedComponents.find((c) => c._id === originalId);
261
+ const component = componentById.get(originalId);
236
262
  if (!component) {
237
263
  throw new Error(`Component ${originalId} not found`);
238
264
  }
239
- compressedPageState.c[compressedId] = {
240
- i: ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0
241
- };
265
+ const indexes = ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0;
266
+ if (indexes) {
267
+ componentEntries.push(`${compressedId}${V2_KV_SEP}${indexes.join(V2_INDEX_SEP)}`);
268
+ } else {
269
+ componentEntries.push(compressedId);
270
+ }
242
271
  });
272
+ parts.push(componentEntries.join(V2_ENTRY_SEP));
273
+ let rulesStr = "";
243
274
  if (typeof payload.rules !== "undefined") {
244
275
  const ruleKeys = Object.keys(payload.rules);
245
276
  if (ruleKeys.length !== 0) {
246
- compressedPageState.rl = {};
247
277
  const sortedRuleKeys = ruleKeys.sort();
248
278
  const compressedRuleKeys = compressIds(sortedRuleKeys);
279
+ const ruleEntries = [];
249
280
  Object.keys(compressedRuleKeys).forEach((compressedId) => {
250
281
  const originalId = compressedRuleKeys[compressedId];
251
- compressedPageState.rl[compressedId] = payload.rules[originalId] ? 1 : 0;
282
+ ruleEntries.push(`${compressedId}${V2_KV_SEP}${payload.rules[originalId] ? 1 : 0}`);
252
283
  });
284
+ rulesStr = ruleEntries.join(V2_ENTRY_SEP);
253
285
  }
254
286
  }
255
- const result = JSON.stringify(compressedPageState);
256
- return encode ? encodeWithReplacements(result) : result;
287
+ parts.push(rulesStr);
288
+ let keysStr = "";
289
+ if (payload.keys) {
290
+ const keyEntries = Object.entries(payload.keys).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${toBase64Url(k)}${V2_KV_SEP}${toBase64Url(v)}`);
291
+ keysStr = keyEntries.join(V2_ENTRY_SEP);
292
+ }
293
+ parts.push(keysStr);
294
+ parts.push(encodeFlags(payload));
295
+ parts.push(payload.releaseId ? toBase64Url(payload.releaseId) : "");
296
+ parts.push(payload.locale ? toBase64Url(payload.locale) : "");
297
+ return parts.join(V2_FIELD_SEP);
298
+ };
299
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
300
+ var isUnsafeKey = (key) => UNSAFE_KEYS.has(key);
301
+ var deserializeV2 = (input) => {
302
+ var _a, _b, _c, _d;
303
+ const fields = input.split(V2_FIELD_SEP);
304
+ if (fields.length < 3) {
305
+ throw new Error(`Invalid serialized PageState: expected at least 3 fields but got ${fields.length}`);
306
+ }
307
+ const compositionStateRaw = fields[1];
308
+ const compositionState = Number.parseInt(compositionStateRaw, 10);
309
+ if (Number.isNaN(compositionState)) {
310
+ throw new Error(
311
+ `Invalid serialized PageState: compositionState '${compositionStateRaw}' is not a valid number`
312
+ );
313
+ }
314
+ const routePath = fromBase64Url(fields[2]);
315
+ const components = /* @__PURE__ */ Object.create(null);
316
+ const componentsStr = (_a = fields[3]) != null ? _a : "";
317
+ if (componentsStr) {
318
+ componentsStr.split(V2_ENTRY_SEP).forEach((entry) => {
319
+ const sepIdx = entry.indexOf(V2_KV_SEP);
320
+ if (sepIdx === -1) {
321
+ const id = entry;
322
+ if (isUnsafeKey(id)) {
323
+ return;
324
+ }
325
+ components[id] = {};
326
+ } else {
327
+ const id = entry.slice(0, sepIdx);
328
+ if (isUnsafeKey(id)) {
329
+ return;
330
+ }
331
+ const indexes = entry.slice(sepIdx + 1).split(V2_INDEX_SEP).map(Number);
332
+ components[id] = { indexes };
333
+ }
334
+ });
335
+ }
336
+ const rulesStr = (_b = fields[4]) != null ? _b : "";
337
+ let rules;
338
+ if (rulesStr) {
339
+ rules = /* @__PURE__ */ Object.create(null);
340
+ rulesStr.split(V2_ENTRY_SEP).forEach((entry) => {
341
+ const sepIdx = entry.indexOf(V2_KV_SEP);
342
+ if (sepIdx !== -1) {
343
+ const id = entry.slice(0, sepIdx);
344
+ if (isUnsafeKey(id)) {
345
+ return;
346
+ }
347
+ rules[id] = entry.slice(sepIdx + 1) === "1";
348
+ }
349
+ });
350
+ }
351
+ const keysStr = (_c = fields[5]) != null ? _c : "";
352
+ const keys = /* @__PURE__ */ Object.create(null);
353
+ if (keysStr) {
354
+ keysStr.split(V2_ENTRY_SEP).forEach((entry) => {
355
+ const sepIdx = entry.indexOf(V2_KV_SEP);
356
+ if (sepIdx !== -1) {
357
+ const k = fromBase64Url(entry.slice(0, sepIdx));
358
+ if (isUnsafeKey(k)) {
359
+ return;
360
+ }
361
+ const v = fromBase64Url(entry.slice(sepIdx + 1));
362
+ keys[k] = v;
363
+ }
364
+ });
365
+ }
366
+ const { defaultConsent, previewMode, isPrefetch } = decodeFlags((_d = fields[6]) != null ? _d : "0");
367
+ const releaseId = fields[7] ? fromBase64Url(fields[7]) : void 0;
368
+ const locale = fields[8] ? fromBase64Url(fields[8]) : void 0;
369
+ return {
370
+ compositionState,
371
+ routePath,
372
+ components,
373
+ rules,
374
+ keys,
375
+ releaseId,
376
+ defaultConsent,
377
+ previewMode,
378
+ locale,
379
+ isPrefetch
380
+ };
381
+ };
382
+ var serializeEvaluationResult = ({ payload }) => {
383
+ return serializeV2(payload);
257
384
  };
258
385
  var deserializeEvaluationResult = ({
259
386
  input: providedInput,
260
387
  decode = true
261
388
  }) => {
262
389
  var _a, _b, _c;
263
- const input = decode ? decodeWithReplacements(providedInput) : providedInput;
264
- const parsed = JSON.parse(input);
390
+ const input = decode ? decodeURIComponent(providedInput) : providedInput;
391
+ if (input.startsWith("2~")) {
392
+ return deserializeV2(input);
393
+ }
394
+ const jsonInput = decode ? atob(unreplaceReservedCharacters(input)) : input;
395
+ const parsed = JSON.parse(jsonInput);
265
396
  const pageState = {
266
397
  compositionState: parsed.cs,
267
398
  routePath: parsed.r,
package/dist/index.js CHANGED
@@ -195,23 +195,11 @@ var resolveRuleFromPageState = ({
195
195
  }
196
196
  return value;
197
197
  };
198
- var replaceReservedCharacters = (value) => {
199
- return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
200
- return acc.replaceAll(char.character, char.replacement);
201
- }, value);
202
- };
203
198
  var unreplaceReservedCharacters = (value) => {
204
199
  return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
205
200
  return acc.replaceAll(char.replacement, char.character);
206
201
  }, value);
207
202
  };
208
- var encodeWithReplacements = (value) => {
209
- return replaceReservedCharacters(btoa(value));
210
- };
211
- var decodeWithReplacements = (value) => {
212
- const urlDecoded = decodeURIComponent(value);
213
- return atob(unreplaceReservedCharacters(urlDecoded));
214
- };
215
203
  var compressIds = (ids) => {
216
204
  const uuidV4Length = 36;
217
205
  let compressedRegistry;
@@ -241,22 +229,58 @@ var compressIds = (ids) => {
241
229
  );
242
230
  };
243
231
  var NAMESPACE_UUID = "00000000-0000-0000-0000-000000000000";
244
- var serializeEvaluationResult = ({
245
- payload,
246
- encode = true
247
- }) => {
248
- const compressedPageState = {
249
- cs: payload.compositionState,
250
- r: payload.routePath,
251
- c: {},
252
- k: payload.keys,
253
- ri: payload.releaseId,
254
- dc: typeof payload.defaultConsent !== "undefined" ? payload.defaultConsent ? 1 : 0 : void 0,
255
- pm: payload.previewMode === "editor" ? "e" : payload.previewMode === "preview" ? "p" : void 0,
256
- rl: void 0,
257
- l: payload.locale,
258
- pf: payload.isPrefetch ? 1 : void 0
232
+ var V2_FIELD_SEP = "~";
233
+ var V2_ENTRY_SEP = ".";
234
+ var V2_KV_SEP = ":";
235
+ var V2_INDEX_SEP = ",";
236
+ var toBase64Url = (value) => {
237
+ const bytes = new TextEncoder().encode(value);
238
+ const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("");
239
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
240
+ };
241
+ var fromBase64Url = (value) => {
242
+ let base64 = value.replace(/-/g, "+").replace(/_/g, "/");
243
+ const pad = base64.length % 4;
244
+ if (pad === 2) {
245
+ base64 += "==";
246
+ } else if (pad === 3) {
247
+ base64 += "=";
248
+ }
249
+ const binary = atob(base64);
250
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
251
+ return new TextDecoder().decode(bytes);
252
+ };
253
+ var encodeFlags = (payload) => {
254
+ let flags = 0;
255
+ if (typeof payload.defaultConsent !== "undefined") {
256
+ flags |= 1;
257
+ if (payload.defaultConsent) {
258
+ flags |= 2;
259
+ }
260
+ }
261
+ if (payload.previewMode === "editor") {
262
+ flags |= 4;
263
+ }
264
+ if (payload.previewMode === "preview") {
265
+ flags |= 8;
266
+ }
267
+ if (payload.isPrefetch) {
268
+ flags |= 16;
269
+ }
270
+ return flags.toString(16);
271
+ };
272
+ var decodeFlags = (hex) => {
273
+ const flags = parseInt(hex, 16) || 0;
274
+ return {
275
+ defaultConsent: flags & 1 ? Boolean(flags & 2) : void 0,
276
+ previewMode: flags & 4 ? "editor" : flags & 8 ? "preview" : void 0,
277
+ isPrefetch: flags & 16 ? true : void 0
259
278
  };
279
+ };
280
+ var serializeV2 = (payload) => {
281
+ const parts = ["2"];
282
+ parts.push(String(payload.compositionState));
283
+ parts.push(toBase64Url(payload.routePath));
260
284
  const componentKeys = Object.keys(payload.components);
261
285
  const sortedKeys = componentKeys.sort();
262
286
  const sortedComponents = sortedKeys.map((key) => ({
@@ -264,39 +288,146 @@ var serializeEvaluationResult = ({
264
288
  ...payload.components[key]
265
289
  }));
266
290
  const compressedComponentIds = compressIds(sortedComponents.map((c) => c._id));
291
+ const componentById = new Map(sortedComponents.map((c) => [c._id, c]));
292
+ const componentEntries = [];
267
293
  Object.keys(compressedComponentIds).forEach((compressedId) => {
268
294
  var _a;
269
295
  const originalId = compressedComponentIds[compressedId];
270
- const component = sortedComponents.find((c) => c._id === originalId);
296
+ const component = componentById.get(originalId);
271
297
  if (!component) {
272
298
  throw new Error(`Component ${originalId} not found`);
273
299
  }
274
- compressedPageState.c[compressedId] = {
275
- i: ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0
276
- };
300
+ const indexes = ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0;
301
+ if (indexes) {
302
+ componentEntries.push(`${compressedId}${V2_KV_SEP}${indexes.join(V2_INDEX_SEP)}`);
303
+ } else {
304
+ componentEntries.push(compressedId);
305
+ }
277
306
  });
307
+ parts.push(componentEntries.join(V2_ENTRY_SEP));
308
+ let rulesStr = "";
278
309
  if (typeof payload.rules !== "undefined") {
279
310
  const ruleKeys = Object.keys(payload.rules);
280
311
  if (ruleKeys.length !== 0) {
281
- compressedPageState.rl = {};
282
312
  const sortedRuleKeys = ruleKeys.sort();
283
313
  const compressedRuleKeys = compressIds(sortedRuleKeys);
314
+ const ruleEntries = [];
284
315
  Object.keys(compressedRuleKeys).forEach((compressedId) => {
285
316
  const originalId = compressedRuleKeys[compressedId];
286
- compressedPageState.rl[compressedId] = payload.rules[originalId] ? 1 : 0;
317
+ ruleEntries.push(`${compressedId}${V2_KV_SEP}${payload.rules[originalId] ? 1 : 0}`);
287
318
  });
319
+ rulesStr = ruleEntries.join(V2_ENTRY_SEP);
288
320
  }
289
321
  }
290
- const result = JSON.stringify(compressedPageState);
291
- return encode ? encodeWithReplacements(result) : result;
322
+ parts.push(rulesStr);
323
+ let keysStr = "";
324
+ if (payload.keys) {
325
+ const keyEntries = Object.entries(payload.keys).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${toBase64Url(k)}${V2_KV_SEP}${toBase64Url(v)}`);
326
+ keysStr = keyEntries.join(V2_ENTRY_SEP);
327
+ }
328
+ parts.push(keysStr);
329
+ parts.push(encodeFlags(payload));
330
+ parts.push(payload.releaseId ? toBase64Url(payload.releaseId) : "");
331
+ parts.push(payload.locale ? toBase64Url(payload.locale) : "");
332
+ return parts.join(V2_FIELD_SEP);
333
+ };
334
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
335
+ var isUnsafeKey = (key) => UNSAFE_KEYS.has(key);
336
+ var deserializeV2 = (input) => {
337
+ var _a, _b, _c, _d;
338
+ const fields = input.split(V2_FIELD_SEP);
339
+ if (fields.length < 3) {
340
+ throw new Error(`Invalid serialized PageState: expected at least 3 fields but got ${fields.length}`);
341
+ }
342
+ const compositionStateRaw = fields[1];
343
+ const compositionState = Number.parseInt(compositionStateRaw, 10);
344
+ if (Number.isNaN(compositionState)) {
345
+ throw new Error(
346
+ `Invalid serialized PageState: compositionState '${compositionStateRaw}' is not a valid number`
347
+ );
348
+ }
349
+ const routePath = fromBase64Url(fields[2]);
350
+ const components = /* @__PURE__ */ Object.create(null);
351
+ const componentsStr = (_a = fields[3]) != null ? _a : "";
352
+ if (componentsStr) {
353
+ componentsStr.split(V2_ENTRY_SEP).forEach((entry) => {
354
+ const sepIdx = entry.indexOf(V2_KV_SEP);
355
+ if (sepIdx === -1) {
356
+ const id = entry;
357
+ if (isUnsafeKey(id)) {
358
+ return;
359
+ }
360
+ components[id] = {};
361
+ } else {
362
+ const id = entry.slice(0, sepIdx);
363
+ if (isUnsafeKey(id)) {
364
+ return;
365
+ }
366
+ const indexes = entry.slice(sepIdx + 1).split(V2_INDEX_SEP).map(Number);
367
+ components[id] = { indexes };
368
+ }
369
+ });
370
+ }
371
+ const rulesStr = (_b = fields[4]) != null ? _b : "";
372
+ let rules;
373
+ if (rulesStr) {
374
+ rules = /* @__PURE__ */ Object.create(null);
375
+ rulesStr.split(V2_ENTRY_SEP).forEach((entry) => {
376
+ const sepIdx = entry.indexOf(V2_KV_SEP);
377
+ if (sepIdx !== -1) {
378
+ const id = entry.slice(0, sepIdx);
379
+ if (isUnsafeKey(id)) {
380
+ return;
381
+ }
382
+ rules[id] = entry.slice(sepIdx + 1) === "1";
383
+ }
384
+ });
385
+ }
386
+ const keysStr = (_c = fields[5]) != null ? _c : "";
387
+ const keys = /* @__PURE__ */ Object.create(null);
388
+ if (keysStr) {
389
+ keysStr.split(V2_ENTRY_SEP).forEach((entry) => {
390
+ const sepIdx = entry.indexOf(V2_KV_SEP);
391
+ if (sepIdx !== -1) {
392
+ const k = fromBase64Url(entry.slice(0, sepIdx));
393
+ if (isUnsafeKey(k)) {
394
+ return;
395
+ }
396
+ const v = fromBase64Url(entry.slice(sepIdx + 1));
397
+ keys[k] = v;
398
+ }
399
+ });
400
+ }
401
+ const { defaultConsent, previewMode, isPrefetch } = decodeFlags((_d = fields[6]) != null ? _d : "0");
402
+ const releaseId = fields[7] ? fromBase64Url(fields[7]) : void 0;
403
+ const locale = fields[8] ? fromBase64Url(fields[8]) : void 0;
404
+ return {
405
+ compositionState,
406
+ routePath,
407
+ components,
408
+ rules,
409
+ keys,
410
+ releaseId,
411
+ defaultConsent,
412
+ previewMode,
413
+ locale,
414
+ isPrefetch
415
+ };
416
+ };
417
+ var serializeEvaluationResult = ({ payload }) => {
418
+ return serializeV2(payload);
292
419
  };
293
420
  var deserializeEvaluationResult = ({
294
421
  input: providedInput,
295
422
  decode = true
296
423
  }) => {
297
424
  var _a, _b, _c;
298
- const input = decode ? decodeWithReplacements(providedInput) : providedInput;
299
- const parsed = JSON.parse(input);
425
+ const input = decode ? decodeURIComponent(providedInput) : providedInput;
426
+ if (input.startsWith("2~")) {
427
+ return deserializeV2(input);
428
+ }
429
+ const jsonInput = decode ? atob(unreplaceReservedCharacters(input)) : input;
430
+ const parsed = JSON.parse(jsonInput);
300
431
  const pageState = {
301
432
  compositionState: parsed.cs,
302
433
  routePath: parsed.r,
package/dist/index.mjs CHANGED
@@ -160,23 +160,11 @@ var resolveRuleFromPageState = ({
160
160
  }
161
161
  return value;
162
162
  };
163
- var replaceReservedCharacters = (value) => {
164
- return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
165
- return acc.replaceAll(char.character, char.replacement);
166
- }, value);
167
- };
168
163
  var unreplaceReservedCharacters = (value) => {
169
164
  return ENCODED_RESERVED_CHARACTERS.reduce((acc, char) => {
170
165
  return acc.replaceAll(char.replacement, char.character);
171
166
  }, value);
172
167
  };
173
- var encodeWithReplacements = (value) => {
174
- return replaceReservedCharacters(btoa(value));
175
- };
176
- var decodeWithReplacements = (value) => {
177
- const urlDecoded = decodeURIComponent(value);
178
- return atob(unreplaceReservedCharacters(urlDecoded));
179
- };
180
168
  var compressIds = (ids) => {
181
169
  const uuidV4Length = 36;
182
170
  let compressedRegistry;
@@ -206,22 +194,58 @@ var compressIds = (ids) => {
206
194
  );
207
195
  };
208
196
  var NAMESPACE_UUID = "00000000-0000-0000-0000-000000000000";
209
- var serializeEvaluationResult = ({
210
- payload,
211
- encode = true
212
- }) => {
213
- const compressedPageState = {
214
- cs: payload.compositionState,
215
- r: payload.routePath,
216
- c: {},
217
- k: payload.keys,
218
- ri: payload.releaseId,
219
- dc: typeof payload.defaultConsent !== "undefined" ? payload.defaultConsent ? 1 : 0 : void 0,
220
- pm: payload.previewMode === "editor" ? "e" : payload.previewMode === "preview" ? "p" : void 0,
221
- rl: void 0,
222
- l: payload.locale,
223
- pf: payload.isPrefetch ? 1 : void 0
197
+ var V2_FIELD_SEP = "~";
198
+ var V2_ENTRY_SEP = ".";
199
+ var V2_KV_SEP = ":";
200
+ var V2_INDEX_SEP = ",";
201
+ var toBase64Url = (value) => {
202
+ const bytes = new TextEncoder().encode(value);
203
+ const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("");
204
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
205
+ };
206
+ var fromBase64Url = (value) => {
207
+ let base64 = value.replace(/-/g, "+").replace(/_/g, "/");
208
+ const pad = base64.length % 4;
209
+ if (pad === 2) {
210
+ base64 += "==";
211
+ } else if (pad === 3) {
212
+ base64 += "=";
213
+ }
214
+ const binary = atob(base64);
215
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
216
+ return new TextDecoder().decode(bytes);
217
+ };
218
+ var encodeFlags = (payload) => {
219
+ let flags = 0;
220
+ if (typeof payload.defaultConsent !== "undefined") {
221
+ flags |= 1;
222
+ if (payload.defaultConsent) {
223
+ flags |= 2;
224
+ }
225
+ }
226
+ if (payload.previewMode === "editor") {
227
+ flags |= 4;
228
+ }
229
+ if (payload.previewMode === "preview") {
230
+ flags |= 8;
231
+ }
232
+ if (payload.isPrefetch) {
233
+ flags |= 16;
234
+ }
235
+ return flags.toString(16);
236
+ };
237
+ var decodeFlags = (hex) => {
238
+ const flags = parseInt(hex, 16) || 0;
239
+ return {
240
+ defaultConsent: flags & 1 ? Boolean(flags & 2) : void 0,
241
+ previewMode: flags & 4 ? "editor" : flags & 8 ? "preview" : void 0,
242
+ isPrefetch: flags & 16 ? true : void 0
224
243
  };
244
+ };
245
+ var serializeV2 = (payload) => {
246
+ const parts = ["2"];
247
+ parts.push(String(payload.compositionState));
248
+ parts.push(toBase64Url(payload.routePath));
225
249
  const componentKeys = Object.keys(payload.components);
226
250
  const sortedKeys = componentKeys.sort();
227
251
  const sortedComponents = sortedKeys.map((key) => ({
@@ -229,39 +253,146 @@ var serializeEvaluationResult = ({
229
253
  ...payload.components[key]
230
254
  }));
231
255
  const compressedComponentIds = compressIds(sortedComponents.map((c) => c._id));
256
+ const componentById = new Map(sortedComponents.map((c) => [c._id, c]));
257
+ const componentEntries = [];
232
258
  Object.keys(compressedComponentIds).forEach((compressedId) => {
233
259
  var _a;
234
260
  const originalId = compressedComponentIds[compressedId];
235
- const component = sortedComponents.find((c) => c._id === originalId);
261
+ const component = componentById.get(originalId);
236
262
  if (!component) {
237
263
  throw new Error(`Component ${originalId} not found`);
238
264
  }
239
- compressedPageState.c[compressedId] = {
240
- i: ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0
241
- };
265
+ const indexes = ((_a = component.indexes) == null ? void 0 : _a.length) ? component.indexes : void 0;
266
+ if (indexes) {
267
+ componentEntries.push(`${compressedId}${V2_KV_SEP}${indexes.join(V2_INDEX_SEP)}`);
268
+ } else {
269
+ componentEntries.push(compressedId);
270
+ }
242
271
  });
272
+ parts.push(componentEntries.join(V2_ENTRY_SEP));
273
+ let rulesStr = "";
243
274
  if (typeof payload.rules !== "undefined") {
244
275
  const ruleKeys = Object.keys(payload.rules);
245
276
  if (ruleKeys.length !== 0) {
246
- compressedPageState.rl = {};
247
277
  const sortedRuleKeys = ruleKeys.sort();
248
278
  const compressedRuleKeys = compressIds(sortedRuleKeys);
279
+ const ruleEntries = [];
249
280
  Object.keys(compressedRuleKeys).forEach((compressedId) => {
250
281
  const originalId = compressedRuleKeys[compressedId];
251
- compressedPageState.rl[compressedId] = payload.rules[originalId] ? 1 : 0;
282
+ ruleEntries.push(`${compressedId}${V2_KV_SEP}${payload.rules[originalId] ? 1 : 0}`);
252
283
  });
284
+ rulesStr = ruleEntries.join(V2_ENTRY_SEP);
253
285
  }
254
286
  }
255
- const result = JSON.stringify(compressedPageState);
256
- return encode ? encodeWithReplacements(result) : result;
287
+ parts.push(rulesStr);
288
+ let keysStr = "";
289
+ if (payload.keys) {
290
+ const keyEntries = Object.entries(payload.keys).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${toBase64Url(k)}${V2_KV_SEP}${toBase64Url(v)}`);
291
+ keysStr = keyEntries.join(V2_ENTRY_SEP);
292
+ }
293
+ parts.push(keysStr);
294
+ parts.push(encodeFlags(payload));
295
+ parts.push(payload.releaseId ? toBase64Url(payload.releaseId) : "");
296
+ parts.push(payload.locale ? toBase64Url(payload.locale) : "");
297
+ return parts.join(V2_FIELD_SEP);
298
+ };
299
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
300
+ var isUnsafeKey = (key) => UNSAFE_KEYS.has(key);
301
+ var deserializeV2 = (input) => {
302
+ var _a, _b, _c, _d;
303
+ const fields = input.split(V2_FIELD_SEP);
304
+ if (fields.length < 3) {
305
+ throw new Error(`Invalid serialized PageState: expected at least 3 fields but got ${fields.length}`);
306
+ }
307
+ const compositionStateRaw = fields[1];
308
+ const compositionState = Number.parseInt(compositionStateRaw, 10);
309
+ if (Number.isNaN(compositionState)) {
310
+ throw new Error(
311
+ `Invalid serialized PageState: compositionState '${compositionStateRaw}' is not a valid number`
312
+ );
313
+ }
314
+ const routePath = fromBase64Url(fields[2]);
315
+ const components = /* @__PURE__ */ Object.create(null);
316
+ const componentsStr = (_a = fields[3]) != null ? _a : "";
317
+ if (componentsStr) {
318
+ componentsStr.split(V2_ENTRY_SEP).forEach((entry) => {
319
+ const sepIdx = entry.indexOf(V2_KV_SEP);
320
+ if (sepIdx === -1) {
321
+ const id = entry;
322
+ if (isUnsafeKey(id)) {
323
+ return;
324
+ }
325
+ components[id] = {};
326
+ } else {
327
+ const id = entry.slice(0, sepIdx);
328
+ if (isUnsafeKey(id)) {
329
+ return;
330
+ }
331
+ const indexes = entry.slice(sepIdx + 1).split(V2_INDEX_SEP).map(Number);
332
+ components[id] = { indexes };
333
+ }
334
+ });
335
+ }
336
+ const rulesStr = (_b = fields[4]) != null ? _b : "";
337
+ let rules;
338
+ if (rulesStr) {
339
+ rules = /* @__PURE__ */ Object.create(null);
340
+ rulesStr.split(V2_ENTRY_SEP).forEach((entry) => {
341
+ const sepIdx = entry.indexOf(V2_KV_SEP);
342
+ if (sepIdx !== -1) {
343
+ const id = entry.slice(0, sepIdx);
344
+ if (isUnsafeKey(id)) {
345
+ return;
346
+ }
347
+ rules[id] = entry.slice(sepIdx + 1) === "1";
348
+ }
349
+ });
350
+ }
351
+ const keysStr = (_c = fields[5]) != null ? _c : "";
352
+ const keys = /* @__PURE__ */ Object.create(null);
353
+ if (keysStr) {
354
+ keysStr.split(V2_ENTRY_SEP).forEach((entry) => {
355
+ const sepIdx = entry.indexOf(V2_KV_SEP);
356
+ if (sepIdx !== -1) {
357
+ const k = fromBase64Url(entry.slice(0, sepIdx));
358
+ if (isUnsafeKey(k)) {
359
+ return;
360
+ }
361
+ const v = fromBase64Url(entry.slice(sepIdx + 1));
362
+ keys[k] = v;
363
+ }
364
+ });
365
+ }
366
+ const { defaultConsent, previewMode, isPrefetch } = decodeFlags((_d = fields[6]) != null ? _d : "0");
367
+ const releaseId = fields[7] ? fromBase64Url(fields[7]) : void 0;
368
+ const locale = fields[8] ? fromBase64Url(fields[8]) : void 0;
369
+ return {
370
+ compositionState,
371
+ routePath,
372
+ components,
373
+ rules,
374
+ keys,
375
+ releaseId,
376
+ defaultConsent,
377
+ previewMode,
378
+ locale,
379
+ isPrefetch
380
+ };
381
+ };
382
+ var serializeEvaluationResult = ({ payload }) => {
383
+ return serializeV2(payload);
257
384
  };
258
385
  var deserializeEvaluationResult = ({
259
386
  input: providedInput,
260
387
  decode = true
261
388
  }) => {
262
389
  var _a, _b, _c;
263
- const input = decode ? decodeWithReplacements(providedInput) : providedInput;
264
- const parsed = JSON.parse(input);
390
+ const input = decode ? decodeURIComponent(providedInput) : providedInput;
391
+ if (input.startsWith("2~")) {
392
+ return deserializeV2(input);
393
+ }
394
+ const jsonInput = decode ? atob(unreplaceReservedCharacters(input)) : input;
395
+ const parsed = JSON.parse(jsonInput);
265
396
  const pageState = {
266
397
  compositionState: parsed.cs,
267
398
  routePath: parsed.r,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/next-app-router-shared",
3
- "version": "20.54.0",
3
+ "version": "20.55.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -36,8 +36,8 @@
36
36
  "vitest": "3.2.4"
37
37
  },
38
38
  "dependencies": {
39
- "@uniformdev/canvas": "20.54.0",
40
- "@uniformdev/context": "20.54.0",
39
+ "@uniformdev/canvas": "20.55.0",
40
+ "@uniformdev/context": "20.55.0",
41
41
  "uuid": "9.0.1"
42
42
  },
43
43
  "engines": {
@@ -51,5 +51,5 @@
51
51
  "publishConfig": {
52
52
  "access": "public"
53
53
  },
54
- "gitHead": "30a6699a8478b38fff6e633b496d42db5d2375cb"
54
+ "gitHead": "ef21541bd262e454318a30372f90d22a06183b82"
55
55
  }