@amplifyup/sdk 0.1.33 → 0.1.35

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/react.mjs CHANGED
@@ -206,6 +206,7 @@ var AWSAdapter = class {
206
206
  // src/storage.ts
207
207
  var INSTANCE_ID_KEY = "amplifyup_instance_id";
208
208
  var USER_ID_KEY = "amplifyup_user_id";
209
+ var ANON_COOKIE_NAME = "amplifyup_anon_id";
209
210
  function generateGuid() {
210
211
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
211
212
  return crypto.randomUUID();
@@ -216,16 +217,39 @@ function generateGuid() {
216
217
  return v.toString(16);
217
218
  });
218
219
  }
220
+ function readCookie(name) {
221
+ if (typeof document === "undefined") return null;
222
+ const parts = document.cookie.split(";");
223
+ for (const part of parts) {
224
+ const idx = part.indexOf("=");
225
+ if (idx === -1) continue;
226
+ if (part.slice(0, idx).trim() !== name) continue;
227
+ const value = part.slice(idx + 1).trim();
228
+ try {
229
+ return value ? decodeURIComponent(value) : null;
230
+ } catch {
231
+ return value || null;
232
+ }
233
+ }
234
+ return null;
235
+ }
236
+ function writeCookie(name, value) {
237
+ if (typeof document === "undefined") return;
238
+ document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=31536000; SameSite=Lax`;
239
+ }
219
240
  function getInstanceId() {
220
241
  if (typeof window === "undefined") {
221
242
  return "";
222
243
  }
223
- const stored = localStorage.getItem(INSTANCE_ID_KEY);
224
- if (stored) {
225
- return stored;
244
+ const fromCookie = readCookie(ANON_COOKIE_NAME);
245
+ const fromLs = localStorage.getItem(INSTANCE_ID_KEY);
246
+ const instanceId = fromLs || fromCookie || `browser_${generateGuid()}`;
247
+ if (fromLs !== instanceId) {
248
+ localStorage.setItem(INSTANCE_ID_KEY, instanceId);
249
+ }
250
+ if (fromCookie !== instanceId) {
251
+ writeCookie(ANON_COOKIE_NAME, instanceId);
226
252
  }
227
- const instanceId = `browser_${generateGuid()}`;
228
- localStorage.setItem(INSTANCE_ID_KEY, instanceId);
229
253
  return instanceId;
230
254
  }
231
255
  function getUserId() {
@@ -246,6 +270,7 @@ function clearIds() {
246
270
  }
247
271
  localStorage.removeItem(INSTANCE_ID_KEY);
248
272
  localStorage.removeItem(USER_ID_KEY);
273
+ document.cookie = `${ANON_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=Lax`;
249
274
  }
250
275
 
251
276
  // src/targets.ts
@@ -373,6 +398,19 @@ function normalizeRoute(route) {
373
398
  return path || "/";
374
399
  }
375
400
 
401
+ // src/edge/variantKeys.ts
402
+ function serializeVariantKeys(keys) {
403
+ if (!keys) return "";
404
+ const parts = [];
405
+ const zoneIds = Object.keys(keys).sort();
406
+ for (const zoneId of zoneIds) {
407
+ const variant = keys[zoneId];
408
+ if (!variant || variant === "default") continue;
409
+ parts.push(`${zoneId}:${variant}`);
410
+ }
411
+ return parts.join(",");
412
+ }
413
+
376
414
  // src/edge/resolve.ts
377
415
  var EdgeResolveError = class extends Error {
378
416
  constructor(message, status, body) {
@@ -390,12 +428,23 @@ async function fetchEdgeResolve(options) {
390
428
  trackingId: options.trackingId
391
429
  });
392
430
  if (options.siteId) params.set("site", options.siteId);
393
- if (options.anonId) params.set("anonId", options.anonId);
431
+ const variantParam = serializeVariantKeys(options.variantKeys);
432
+ if (variantParam) {
433
+ params.set("variants", variantParam);
434
+ } else if (options.anonId) {
435
+ params.set("anonId", options.anonId);
436
+ }
394
437
  const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
395
- const res = await fetchFn(`${base}/v1/resolve?${params.toString()}`, {
438
+ const init = {
396
439
  method: "GET",
397
440
  headers: { Accept: "application/json" }
398
- });
441
+ };
442
+ if (options.revalidate !== void 0) {
443
+ init.next = { revalidate: options.revalidate };
444
+ } else {
445
+ init.cache = "no-store";
446
+ }
447
+ const res = await fetchFn(`${base}/v1/resolve?${params.toString()}`, init);
399
448
  const body = await res.json().catch(() => ({}));
400
449
  if (!res.ok) {
401
450
  throw new EdgeResolveError(
@@ -484,9 +533,11 @@ async function fetchContent(options) {
484
533
  edgeUrl: options.edgeUrl,
485
534
  trackingId: options.trackingId,
486
535
  route: options.route,
487
- anonId: options.anonId,
536
+ anonId: options.variantKeys ? void 0 : options.anonId,
488
537
  siteId: options.siteId,
489
- fetch: options.fetchFn
538
+ fetch: options.fetchFn,
539
+ revalidate: options.revalidate,
540
+ variantKeys: options.variantKeys
490
541
  });
491
542
  const pageConfig = mapResolvedToPageConfig(payload);
492
543
  const degraded = collectDegraded(payload);
@@ -524,6 +575,145 @@ async function fetchContent(options) {
524
575
  }
525
576
  }
526
577
 
578
+ // src/edge/select.ts
579
+ var SelectVariantsError = class extends Error {
580
+ constructor(message, status, body) {
581
+ super(message);
582
+ this.name = "SelectVariantsError";
583
+ this.status = status;
584
+ this.body = body;
585
+ }
586
+ };
587
+ async function fetchEdgeSelect(options) {
588
+ const base = options.edgeUrl.replace(/\/+$/, "");
589
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
590
+ if (!options.trackingId && !options.site) {
591
+ throw new SelectVariantsError("trackingId or site is required", 400);
592
+ }
593
+ const res = await fetchFn(`${base}/v1/select`, {
594
+ method: "POST",
595
+ headers: {
596
+ Accept: "application/json",
597
+ "Content-Type": "application/json"
598
+ },
599
+ cache: "no-store",
600
+ signal: options.signal,
601
+ body: JSON.stringify({
602
+ view: normalizeRoute(options.view),
603
+ ...options.trackingId ? { trackingId: options.trackingId } : {},
604
+ ...options.site ? { site: options.site } : {},
605
+ anonId: options.anonId,
606
+ ...options.zones?.length ? { zones: options.zones } : {},
607
+ ...options.context ? { context: options.context } : {}
608
+ })
609
+ });
610
+ const body = await res.json().catch(() => ({}));
611
+ if (!res.ok) {
612
+ throw new SelectVariantsError(
613
+ body.error || `Select failed (${res.status})`,
614
+ res.status,
615
+ body
616
+ );
617
+ }
618
+ return {
619
+ siteId: String(body.siteId || ""),
620
+ view: String(body.view || normalizeRoute(options.view)),
621
+ variantKeys: body.variantKeys && typeof body.variantKeys === "object" ? body.variantKeys : {},
622
+ meta: body.meta
623
+ };
624
+ }
625
+ async function selectVariants(options) {
626
+ const target = resolveAmplifyUpTarget({ configTarget: options.target });
627
+ const { edgeUrl } = resolveAmplifyUpUrls(target);
628
+ return fetchEdgeSelect({
629
+ edgeUrl: options.edgeUrl || edgeUrl,
630
+ trackingId: options.trackingId,
631
+ site: options.site,
632
+ view: options.view,
633
+ anonId: options.anonId,
634
+ zones: options.zones,
635
+ context: options.context,
636
+ fetch: options.fetch,
637
+ signal: options.signal
638
+ });
639
+ }
640
+
641
+ // src/edge/query.ts
642
+ var QueryContentError = class extends Error {
643
+ constructor(message, status, body) {
644
+ super(message);
645
+ this.name = "QueryContentError";
646
+ this.status = status;
647
+ this.body = body;
648
+ }
649
+ };
650
+ async function fetchEdgeQuery(options) {
651
+ const base = options.edgeUrl.replace(/\/+$/, "");
652
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
653
+ const limit = Math.max(1, Number(options.spec.limit) || 10);
654
+ const offset = Math.max(0, Number(options.spec.offset) || 0);
655
+ const res = await fetchFn(`${base}/v1/query`, {
656
+ method: "POST",
657
+ headers: {
658
+ Accept: "application/json",
659
+ "Content-Type": "application/json"
660
+ },
661
+ cache: "no-store",
662
+ signal: options.signal,
663
+ body: JSON.stringify({
664
+ route: normalizeRoute(options.route),
665
+ trackingId: options.trackingId,
666
+ ...options.siteId ? { site: options.siteId } : {},
667
+ spec: { ...options.spec, limit, offset }
668
+ })
669
+ });
670
+ const body = await res.json().catch(() => ({}));
671
+ if (!res.ok) {
672
+ throw new QueryContentError(
673
+ body.error || `Content query failed (${res.status})`,
674
+ res.status,
675
+ body
676
+ );
677
+ }
678
+ const results = Array.isArray(body.results) ? body.results : [];
679
+ const resolvedLimit = Number(body.limit) || limit;
680
+ const resolvedOffset = Number.isFinite(Number(body.offset)) ? Number(body.offset) : offset;
681
+ return {
682
+ results,
683
+ count: Number(body.count) || results.length,
684
+ hasMore: !!body.hasMore,
685
+ limit: resolvedLimit,
686
+ offset: resolvedOffset,
687
+ nextOffset: Number(body.nextOffset) || resolvedOffset + resolvedLimit,
688
+ degraded: body.degraded
689
+ };
690
+ }
691
+ async function queryContent(options) {
692
+ const target = resolveAmplifyUpTarget({ configTarget: options.target });
693
+ const { edgeUrl } = resolveAmplifyUpUrls(target);
694
+ return fetchEdgeQuery({
695
+ edgeUrl,
696
+ trackingId: options.trackingId,
697
+ route: options.route,
698
+ spec: options.spec,
699
+ siteId: options.siteId,
700
+ fetch: options.fetch,
701
+ signal: options.signal
702
+ });
703
+ }
704
+ function nextPageSpec(pagination) {
705
+ return { ...pagination.spec, offset: pagination.nextOffset };
706
+ }
707
+ function searchSpec(pagination, field, term) {
708
+ const value = String(term || "").trim();
709
+ const base = { ...pagination.spec, offset: 0 };
710
+ if (!value) return base;
711
+ return {
712
+ ...base,
713
+ filter: [...base.filter || [], { field, op: "contains", value }]
714
+ };
715
+ }
716
+
527
717
  // src/index.ts
528
718
  var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
529
719
  var DWELL_ACTIVITY_IDLE_MS = 2 * 60 * 1e3;
@@ -3774,6 +3964,21 @@ function defaultPreviewCanvas() {
3774
3964
  function hasAmplifyLayout(pageConfig) {
3775
3965
  return !!(pageConfig && pageConfig.id !== "default" && Array.isArray(pageConfig.layoutTree) && pageConfig.layoutTree.length > 0);
3776
3966
  }
3967
+ function normalizeRoutePath(route) {
3968
+ if (!route) return "";
3969
+ const path = route.split("?")[0] || "/";
3970
+ if (path.length > 1 && path.endsWith("/")) return path.replace(/\/+$/, "");
3971
+ return path || "/";
3972
+ }
3973
+ function samePageRoute(a, b) {
3974
+ const ar = normalizeRoutePath(a?.route);
3975
+ const br = normalizeRoutePath(b?.route);
3976
+ return !!ar && !!br && ar === br;
3977
+ }
3978
+ function layoutTreesEqual(a, b) {
3979
+ if (!a || !b) return a === b;
3980
+ return JSON.stringify(a.layoutTree) === JSON.stringify(b.layoutTree);
3981
+ }
3777
3982
  function AmplifyPageContent({
3778
3983
  fallback,
3779
3984
  renderComponent,
@@ -3787,9 +3992,18 @@ function AmplifyPageContent({
3787
3992
  }) {
3788
3993
  const client = useAmplifyUp();
3789
3994
  const preview = forceComposerPreview || isComposerPreview();
3790
- const pageConfig = pageConfigProp ?? client.pageConfig;
3791
- const loading = pageConfigProp ? false : client.loading;
3792
- const error = pageConfigProp ? null : client.error;
3995
+ const clientLayout = hasAmplifyLayout(client.pageConfig) ? client.pageConfig : null;
3996
+ const serverLayout = hasAmplifyLayout(pageConfigProp) ? pageConfigProp : null;
3997
+ let pageConfig = serverLayout ?? clientLayout;
3998
+ if (preview && clientLayout) {
3999
+ pageConfig = clientLayout;
4000
+ } else if (clientLayout && serverLayout && samePageRoute(clientLayout, serverLayout) && !layoutTreesEqual(clientLayout, serverLayout)) {
4001
+ pageConfig = clientLayout;
4002
+ } else if (clientLayout && !serverLayout) {
4003
+ pageConfig = clientLayout;
4004
+ }
4005
+ const loading = !hasAmplifyLayout(pageConfig) && client.loading;
4006
+ const error = hasAmplifyLayout(pageConfig) ? null : pageConfigProp ? null : client.error;
3793
4007
  const previewCanvas = previewEmptyComponent ?? defaultPreviewCanvas();
3794
4008
  const previewLoading = previewLoadingComponent ?? previewCanvas;
3795
4009
  if (preview) {
@@ -3828,6 +4042,7 @@ function AmplifyPageContent({
3828
4042
  }
3829
4043
 
3830
4044
  // src/server.tsx
4045
+ var AMPLIFY_DEFAULT_REVALIDATE = 60;
3831
4046
  async function fetchPageConfigServer(route, trackingId, preview = false, options) {
3832
4047
  const target = resolveAmplifyUpTarget({
3833
4048
  configTarget: options?.target
@@ -3863,7 +4078,9 @@ async function fetchPageConfigServer(route, trackingId, preview = false, options
3863
4078
  preview: previewFlag,
3864
4079
  orchestratorUrl,
3865
4080
  edgeUrl,
3866
- fetchOrchestratorPage
4081
+ fetchOrchestratorPage,
4082
+ revalidate: previewFlag ? void 0 : options?.revalidate ?? AMPLIFY_DEFAULT_REVALIDATE,
4083
+ variantKeys: previewFlag ? void 0 : options?.variantKeys
3867
4084
  });
3868
4085
  return result.pageConfig;
3869
4086
  }
@@ -3953,10 +4170,9 @@ function AmplifyUpProvider({ children, config }) {
3953
4170
  }, [config.trackingId, config.target, config.debug, config.dev, config.siteId]);
3954
4171
  useEffect(() => {
3955
4172
  if (!initialized) return;
4173
+ let cancelled = false;
3956
4174
  const load = async () => {
3957
4175
  try {
3958
- setLoading(true);
3959
- setError(null);
3960
4176
  const actualRoute = getActualRoute();
3961
4177
  if (!actualRoute) {
3962
4178
  setLoading(false);
@@ -3965,6 +4181,15 @@ function AmplifyUpProvider({ children, config }) {
3965
4181
  const sdk = getSDK();
3966
4182
  sdk.routeChange(actualRoute);
3967
4183
  const preview = isComposerPreview();
4184
+ const overlay = preview || config.clientPersonalization !== false;
4185
+ if (!overlay) {
4186
+ setPageConfig(null);
4187
+ setLoading(false);
4188
+ return;
4189
+ }
4190
+ setPageConfig(null);
4191
+ setError(null);
4192
+ setLoading(false);
3968
4193
  const edgeUrl = sdk.getEdgeUrl();
3969
4194
  const orchestratorUrl = sdk.getOrchestratorUrl();
3970
4195
  const trackingId = sdk.getTrackingId();
@@ -3973,16 +4198,34 @@ function AmplifyUpProvider({ children, config }) {
3973
4198
  setLoading(false);
3974
4199
  return;
3975
4200
  }
4201
+ let variantKeys;
4202
+ const anonId = sdk.getInstanceId();
4203
+ if (!preview && anonId) {
4204
+ try {
4205
+ const selected = await selectVariants({
4206
+ trackingId,
4207
+ view: actualRoute,
4208
+ anonId,
4209
+ site: sdk.getSiteId() || void 0,
4210
+ edgeUrl
4211
+ });
4212
+ variantKeys = selected.variantKeys;
4213
+ } catch (err) {
4214
+ console.error("AmplifyUp selectVariants failed; overlay will use visitor id", err);
4215
+ }
4216
+ }
3976
4217
  const result = await fetchContent({
3977
4218
  route: actualRoute,
3978
4219
  trackingId,
3979
- anonId: sdk.getInstanceId(),
4220
+ anonId: variantKeys ? void 0 : anonId,
3980
4221
  siteId: sdk.getSiteId() || null,
3981
4222
  preview,
3982
4223
  orchestratorUrl,
3983
4224
  edgeUrl,
4225
+ variantKeys,
3984
4226
  fetchOrchestratorPage: (route, isPreview) => sdk.fetchPageConfig(route, isPreview)
3985
4227
  });
4228
+ if (cancelled) return;
3986
4229
  setSource(result.source);
3987
4230
  setMeta(result.meta);
3988
4231
  setError(result.error);
@@ -3998,16 +4241,20 @@ function AmplifyUpProvider({ children, config }) {
3998
4241
  setPageConfig(result.pageConfig);
3999
4242
  }
4000
4243
  } catch (err) {
4244
+ if (cancelled) return;
4001
4245
  console.error("Error fetching page config:", err);
4002
4246
  setError(err instanceof Error ? err.message : "Unknown error");
4003
4247
  setSource(null);
4004
4248
  setMeta(null);
4005
4249
  } finally {
4006
- setLoading(false);
4250
+ if (!cancelled) setLoading(false);
4007
4251
  }
4008
4252
  };
4009
4253
  void load();
4010
- }, [pathname, initialized]);
4254
+ return () => {
4255
+ cancelled = true;
4256
+ };
4257
+ }, [pathname, initialized, config.clientPersonalization]);
4011
4258
  return /* @__PURE__ */ jsx(
4012
4259
  AmplifyUpContext.Provider,
4013
4260
  {
@@ -4024,6 +4271,6 @@ function useAmplifyUp() {
4024
4271
  return context;
4025
4272
  }
4026
4273
 
4027
- export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, Field, Image, RichText, Slot, fetchPageConfigServer, isComposerPreview, isPreviewRequest, isWorkingContentRequest, useAmplifyUp, useComponentProps, useLiveComposerProps };
4274
+ export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, Field, Image, QueryContentError, RichText, SelectVariantsError, Slot, fetchPageConfigServer, isComposerPreview, isPreviewRequest, isWorkingContentRequest, nextPageSpec, queryContent, searchSpec, selectVariants, useAmplifyUp, useComponentProps, useLiveComposerProps };
4028
4275
  //# sourceMappingURL=react.mjs.map
4029
4276
  //# sourceMappingURL=react.mjs.map