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