@amplifyup/sdk 0.1.21 → 0.1.23

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
@@ -151,17 +151,42 @@ var AWSAdapter = class {
151
151
  };
152
152
  this.sendEvent("/v1/track", eventData);
153
153
  }
154
- identify(userId, traits) {
154
+ identify(userIdOrIdentifiers, traits = {}) {
155
155
  if (!this.initialized) {
156
156
  console.warn("AmplifyUp SDK: Not initialized. Call init() first.");
157
157
  return;
158
158
  }
159
+ const isMap = userIdOrIdentifiers !== null && typeof userIdOrIdentifiers === "object" && !Array.isArray(userIdOrIdentifiers);
160
+ const identifiers = isMap ? userIdOrIdentifiers : traits.identifiers;
161
+ const userId = isMap ? void 0 : String(userIdOrIdentifiers);
159
162
  const eventData = {
160
163
  type: "identify",
161
- userId,
162
164
  anonymousId: traits.instanceId,
163
165
  traits: {
164
- ...traits
166
+ ...traits,
167
+ ...identifiers ? { identifiers } : {}
168
+ },
169
+ ...identifiers ? { identifiers } : {},
170
+ ...userId ? { userId } : {},
171
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
172
+ };
173
+ this.sendEvent("/v1/track", eventData);
174
+ }
175
+ setProfileFields(fields, context = {}) {
176
+ if (!this.initialized) {
177
+ console.warn("AmplifyUp SDK: Not initialized. Call init() first.");
178
+ return;
179
+ }
180
+ const eventData = {
181
+ type: "set_fields",
182
+ anonymousId: context.instanceId,
183
+ fields,
184
+ traits: {
185
+ instanceId: context.instanceId,
186
+ trackingId: context.trackingId
187
+ },
188
+ properties: {
189
+ trackingId: context.trackingId
165
190
  },
166
191
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
167
192
  };
@@ -223,6 +248,7 @@ function clearIds() {
223
248
  var AWS_DEV_API = "https://api-dev.amplifyup.ai";
224
249
  var AWS_PROD_API = "https://api.amplifyup.ai";
225
250
  var PROD_ORCHESTRATOR = "https://amplifyup.ai";
251
+ var PROD_EDGE = "https://edge.amplifyup.ai";
226
252
  function isAmplifyUpTarget(value) {
227
253
  return value === "local" || value === "dev" || value === "production";
228
254
  }
@@ -258,6 +284,10 @@ function localAwsApiUrl() {
258
284
  const fromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_AMPLIFYUP_API_URL : void 0;
259
285
  return (fromEnv || AWS_DEV_API).replace(/\/$/, "");
260
286
  }
287
+ function localEdgeUrl() {
288
+ const fromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_EDGE_URL : void 0;
289
+ return (fromEnv || "http://localhost:8787").replace(/\/$/, "");
290
+ }
261
291
  function resolveAmplifyUpUrls(target) {
262
292
  if (target === "local") {
263
293
  const orchestratorUrl2 = localOrchestratorUrl();
@@ -268,18 +298,22 @@ function resolveAmplifyUpUrls(target) {
268
298
  orchestratorUrl: orchestratorUrl2,
269
299
  // Events + personalize → AWS development stack
270
300
  apiGatewayUrl,
271
- decisionApiUrl: `${apiGatewayUrl}/v1/personalize`
301
+ decisionApiUrl: `${apiGatewayUrl}/v1/personalize`,
302
+ edgeUrl: localEdgeUrl()
272
303
  };
273
304
  }
274
305
  const resolvedApi = typeof process !== "undefined" && process.env.NEXT_PUBLIC_AMPLIFYUP_API_URL?.replace(/\/$/, "") || AWS_PROD_API;
275
306
  const orchestratorFromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_ORCHESTRATOR_URL : void 0;
276
307
  const isLocalOrchestrator = !!orchestratorFromEnv && (orchestratorFromEnv.includes("localhost") || orchestratorFromEnv.includes("127.0.0.1"));
277
308
  const orchestratorUrl = isLocalOrchestrator || !orchestratorFromEnv ? PROD_ORCHESTRATOR : orchestratorFromEnv.replace(/\/$/, "");
309
+ const edgeFromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_EDGE_URL?.replace(/\/$/, "") : void 0;
310
+ const edgeUrl = edgeFromEnv && !edgeFromEnv.includes("localhost") && !edgeFromEnv.includes("127.0.0.1") ? edgeFromEnv : PROD_EDGE;
278
311
  return {
279
312
  target: "production",
280
313
  apiGatewayUrl: resolvedApi,
281
314
  orchestratorUrl,
282
- decisionApiUrl: `${resolvedApi}/v1/personalize`
315
+ decisionApiUrl: `${resolvedApi}/v1/personalize`,
316
+ edgeUrl
283
317
  };
284
318
  }
285
319
 
@@ -309,7 +343,179 @@ function isComposerPreview() {
309
343
  return false;
310
344
  }
311
345
 
346
+ // src/edge/normalizeRoute.ts
347
+ function normalizeRoute(route) {
348
+ let path = String(route || "").trim();
349
+ if (!path) return "/";
350
+ try {
351
+ if (/^https?:\/\//i.test(path)) {
352
+ path = new URL(path).pathname;
353
+ }
354
+ } catch {
355
+ }
356
+ const q = path.indexOf("?");
357
+ if (q >= 0) path = path.slice(0, q);
358
+ const h = path.indexOf("#");
359
+ if (h >= 0) path = path.slice(0, h);
360
+ if (!path.startsWith("/")) path = `/${path}`;
361
+ if (path.length > 1 && path.endsWith("/")) {
362
+ path = path.replace(/\/+$/, "");
363
+ }
364
+ return path || "/";
365
+ }
366
+
367
+ // src/edge/resolve.ts
368
+ var EdgeResolveError = class extends Error {
369
+ constructor(message, status, body) {
370
+ super(message);
371
+ this.name = "EdgeResolveError";
372
+ this.status = status;
373
+ this.body = body;
374
+ }
375
+ };
376
+ async function fetchEdgeResolve(options) {
377
+ const base = options.edgeUrl.replace(/\/+$/, "");
378
+ const route = normalizeRoute(options.route);
379
+ const params = new URLSearchParams({
380
+ route,
381
+ trackingId: options.trackingId
382
+ });
383
+ if (options.siteId) params.set("site", options.siteId);
384
+ if (options.anonId) params.set("anonId", options.anonId);
385
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
386
+ const res = await fetchFn(`${base}/v1/resolve?${params.toString()}`, {
387
+ method: "GET",
388
+ headers: { Accept: "application/json" }
389
+ });
390
+ const body = await res.json().catch(() => ({}));
391
+ if (!res.ok) {
392
+ throw new EdgeResolveError(
393
+ (body && typeof body === "object" && "error" in body ? String(body.error) : `Edge resolve failed (${res.status})`) || `Edge resolve failed (${res.status})`,
394
+ res.status,
395
+ body
396
+ );
397
+ }
398
+ return body;
399
+ }
400
+
401
+ // src/edge/mapResolvedToPageConfig.ts
402
+ function mapResolvedComponent(node) {
403
+ const slots = [];
404
+ if (node.children) {
405
+ for (const [slotId, kids] of Object.entries(node.children)) {
406
+ slots.push({
407
+ slotId,
408
+ children: (kids || []).map(mapResolvedComponent)
409
+ });
410
+ }
411
+ }
412
+ return {
413
+ id: node.instanceId,
414
+ componentId: node.componentId,
415
+ props: { ...node.props || {} },
416
+ ...slots.length > 0 ? { slots } : {},
417
+ _contentSource: "edge"
418
+ };
419
+ }
420
+ function mapResolvedToPageConfig(payload) {
421
+ let layoutTree = [];
422
+ if (payload.tree && payload.tree.length > 0) {
423
+ layoutTree = payload.tree.map(mapResolvedComponent);
424
+ } else {
425
+ const zoneIds = Object.keys(payload.zones || {}).sort();
426
+ for (const zoneId of zoneIds) {
427
+ const roots = payload.zones[zoneId] || [];
428
+ layoutTree.push(...roots.map(mapResolvedComponent));
429
+ }
430
+ }
431
+ return {
432
+ id: `edge:${payload.siteId}:${payload.route}:v${payload.version}`,
433
+ route: payload.route,
434
+ title: "",
435
+ layoutTree,
436
+ meta: {
437
+ // Stash edge meta for diagnostics (not visitor-facing)
438
+ description: payload.meta?.degraded ? "degraded" : void 0
439
+ }
440
+ };
441
+ }
442
+ function collectDegraded(payload) {
443
+ if (payload.meta?.degraded) return true;
444
+ const walk = (nodes) => nodes.some(
445
+ (n) => !!n.degraded || (n.children ? Object.values(n.children).some((kids) => walk(kids || [])) : false)
446
+ );
447
+ if (payload.tree && walk(payload.tree)) return true;
448
+ return Object.values(payload.zones || {}).some((roots) => walk(roots || []));
449
+ }
450
+
451
+ // src/content/fetchContent.ts
452
+ async function fetchContent(options) {
453
+ const preview = options.preview ?? (typeof window !== "undefined" ? isComposerPreview() : false);
454
+ if (preview) {
455
+ try {
456
+ const page = await options.fetchOrchestratorPage(options.route, true);
457
+ return {
458
+ pageConfig: page,
459
+ source: "orchestrator",
460
+ meta: { source: "orchestrator" },
461
+ error: null
462
+ };
463
+ } catch (err) {
464
+ return {
465
+ pageConfig: null,
466
+ source: "orchestrator",
467
+ meta: { source: "orchestrator" },
468
+ error: err instanceof Error ? err.message : "Failed to load preview"
469
+ };
470
+ }
471
+ }
472
+ try {
473
+ const payload = await fetchEdgeResolve({
474
+ edgeUrl: options.edgeUrl,
475
+ trackingId: options.trackingId,
476
+ route: options.route,
477
+ anonId: options.anonId,
478
+ siteId: options.siteId,
479
+ fetch: options.fetchFn
480
+ });
481
+ const pageConfig = mapResolvedToPageConfig(payload);
482
+ const degraded = collectDegraded(payload);
483
+ return {
484
+ pageConfig,
485
+ source: "edge",
486
+ meta: {
487
+ source: "edge",
488
+ version: payload.version,
489
+ siteId: payload.siteId,
490
+ variantKeys: payload.meta?.variantKeys,
491
+ degraded,
492
+ audienceLookup: payload.meta?.audienceLookup,
493
+ decideLookup: payload.meta?.decideLookup,
494
+ resolvedAt: payload.meta?.resolvedAt
495
+ },
496
+ error: null
497
+ };
498
+ } catch (err) {
499
+ if (err instanceof EdgeResolveError && err.status === 404) {
500
+ return {
501
+ pageConfig: null,
502
+ source: "edge",
503
+ meta: { source: "edge" },
504
+ error: null
505
+ // unpublished → site fallback, not an error banner
506
+ };
507
+ }
508
+ return {
509
+ pageConfig: null,
510
+ source: "edge",
511
+ meta: { source: "edge" },
512
+ error: err instanceof Error ? err.message : "Couldn't load page content."
513
+ };
514
+ }
515
+ }
516
+
312
517
  // src/index.ts
518
+ var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
313
519
  function readPreviewQueryOverrides() {
314
520
  if (typeof window === "undefined") return {};
315
521
  const params = new URLSearchParams(window.location.search);
@@ -337,6 +543,8 @@ var AmplifyUpSDK = class {
337
543
  this.apiGatewayUrl = "";
338
544
  this.orchestratorUrl = "";
339
545
  this.decisionApiUrl = "";
546
+ this.edgeUrl = "";
547
+ this.siteId = "";
340
548
  this.target = "local";
341
549
  this.initialized = false;
342
550
  /** Prevents overlapping init() from React Strict Mode double-mount */
@@ -376,7 +584,9 @@ var AmplifyUpSDK = class {
376
584
  reached: /* @__PURE__ */ new Set(),
377
585
  visibleMs: 0,
378
586
  visibleSince: null,
379
- lastDwellSecondsSent: 0
587
+ lastDwellSecondsSent: 0,
588
+ /** When the tab last became hidden — used for idle-resume re-page. */
589
+ hiddenAt: null
380
590
  };
381
591
  this.adapter = adapter || new AWSAdapter();
382
592
  if (typeof window !== "undefined") {
@@ -491,7 +701,8 @@ var AmplifyUpSDK = class {
491
701
  isInitialized: () => this.isInitialized(),
492
702
  page: (url, properties) => this.page(url, properties),
493
703
  track: (eventName, properties) => this.track(eventName, properties),
494
- identify: (userId, traits) => this.identify(userId, traits)
704
+ identify: (userIdOrIdentifiers, traits) => this.identify(userIdOrIdentifiers, traits),
705
+ setProfileFields: (fields) => this.setProfileFields(fields)
495
706
  };
496
707
  }
497
708
  async performInit(config) {
@@ -506,6 +717,8 @@ var AmplifyUpSDK = class {
506
717
  this.apiGatewayUrl = urls.apiGatewayUrl;
507
718
  this.orchestratorUrl = urls.orchestratorUrl;
508
719
  this.decisionApiUrl = urls.decisionApiUrl;
720
+ this.edgeUrl = urls.edgeUrl;
721
+ this.siteId = config.siteId || "";
509
722
  const previewOverrides = readPreviewQueryOverrides();
510
723
  if (previewOverrides.orchestratorUrl) {
511
724
  this.orchestratorUrl = previewOverrides.orchestratorUrl;
@@ -514,6 +727,7 @@ var AmplifyUpSDK = class {
514
727
  this.target = "production";
515
728
  this.apiGatewayUrl = prodUrls.apiGatewayUrl;
516
729
  this.decisionApiUrl = prodUrls.decisionApiUrl;
730
+ this.edgeUrl = prodUrls.edgeUrl;
517
731
  }
518
732
  }
519
733
  this.config = {
@@ -521,7 +735,8 @@ var AmplifyUpSDK = class {
521
735
  debug: config.debug ?? true,
522
736
  // Enable debug by default
523
737
  target: this.target,
524
- dev: config.dev
738
+ dev: config.dev,
739
+ ...config.siteId ? { siteId: config.siteId } : {}
525
740
  };
526
741
  try {
527
742
  const adapterConfig = {
@@ -607,6 +822,7 @@ var AmplifyUpSDK = class {
607
822
  state.visibleMs = 0;
608
823
  state.visibleSince = document.visibilityState === "visible" ? Date.now() : null;
609
824
  state.lastDwellSecondsSent = 0;
825
+ state.hiddenAt = document.visibilityState === "hidden" ? Date.now() : null;
610
826
  let scrollRaf = null;
611
827
  const path = () => this.currentPath();
612
828
  const measureScrollPercent = () => {
@@ -649,12 +865,12 @@ var AmplifyUpSDK = class {
649
865
  state.visibleMs += Date.now() - state.visibleSince;
650
866
  state.visibleSince = Date.now();
651
867
  };
652
- const emitDwell = (force = false) => {
868
+ const emitDwell = (_force = false) => {
653
869
  if (this.isPreviewMode()) return;
654
870
  accumulateVisible();
655
871
  const seconds = Math.floor(state.visibleMs / 1e3);
656
872
  if (seconds <= 0) return;
657
- if (!force && seconds <= state.lastDwellSecondsSent) return;
873
+ if (seconds <= state.lastDwellSecondsSent) return;
658
874
  state.lastDwellSecondsSent = seconds;
659
875
  this.track("Time on Page", {
660
876
  seconds,
@@ -664,14 +880,34 @@ var AmplifyUpSDK = class {
664
880
  this._emitPageDwell = emitDwell;
665
881
  const onVisibility = () => {
666
882
  if (document.visibilityState === "visible") {
883
+ const idleMs = state.hiddenAt != null ? Date.now() - state.hiddenAt : 0;
884
+ state.hiddenAt = null;
885
+ if (idleMs >= SESSION_IDLE_GAP_MS) {
886
+ this.resetEngagementQuiet();
887
+ const resumePath = path();
888
+ this.page(resumePath, { resumed: true });
889
+ this.lastTrackedPath = resumePath;
890
+ if (this.config?.debug) {
891
+ console.log(
892
+ "[AmplifyUp SDK] Idle resume page view",
893
+ resumePath,
894
+ `(hidden ${Math.round(idleMs / 6e4)}m)`
895
+ );
896
+ }
897
+ }
667
898
  state.visibleSince = Date.now();
668
899
  } else {
669
900
  emitDwell(true);
901
+ state.hiddenAt = Date.now();
670
902
  state.visibleSince = null;
671
903
  }
672
904
  };
673
905
  const onPageHide = () => {
674
906
  emitDwell(true);
907
+ if (state.hiddenAt == null) {
908
+ state.hiddenAt = Date.now();
909
+ }
910
+ state.visibleSince = null;
675
911
  };
676
912
  window.addEventListener("scroll", onScroll, { passive: true });
677
913
  document.addEventListener("visibilitychange", onVisibility);
@@ -700,13 +936,19 @@ var AmplifyUpSDK = class {
700
936
  console.log("[AmplifyUp SDK] Page engagement tracking enabled");
701
937
  }
702
938
  }
939
+ /** Flush dwell then reset — used on SPA route changes. */
703
940
  resetEngagementForNewPage() {
704
941
  const emit = this._emitPageDwell;
705
942
  emit?.(true);
943
+ this.resetEngagementQuiet();
944
+ }
945
+ /** Reset dwell/scroll state without emitting (idle resume already flushed on hide). */
946
+ resetEngagementQuiet() {
706
947
  const state = this.pageEngagementState;
707
948
  state.reached = /* @__PURE__ */ new Set();
708
949
  state.visibleMs = 0;
709
950
  state.lastDwellSecondsSent = 0;
951
+ state.hiddenAt = null;
710
952
  state.visibleSince = typeof document !== "undefined" && document.visibilityState === "visible" ? Date.now() : null;
711
953
  this.componentViewSeen.clear();
712
954
  }
@@ -892,12 +1134,17 @@ var AmplifyUpSDK = class {
892
1134
  });
893
1135
  }
894
1136
  /**
895
- * Identify user (when they sign up or log in)
1137
+ * Identify a visitor.
1138
+ * - identify('user_123') — bare string; server maps via org default type
1139
+ * - identify({ email: '...', crm_id: '...' }) — explicit types
1140
+ * - identify('user_123', traits) — legacy form
896
1141
  */
897
- identify(userId, traits) {
1142
+ identify(userIdOrIdentifiers, traits) {
898
1143
  if (this.isPreviewMode()) {
899
1144
  if (this.config?.debug) {
900
- console.log("AmplifyUp SDK: Identify tracking disabled in preview mode", { userId });
1145
+ console.log("AmplifyUp SDK: Identify tracking disabled in preview mode", {
1146
+ userIdOrIdentifiers
1147
+ });
901
1148
  }
902
1149
  return;
903
1150
  }
@@ -913,10 +1160,45 @@ var AmplifyUpSDK = class {
913
1160
  trackingId: this.config?.trackingId,
914
1161
  ...traits
915
1162
  };
916
- this.adapter.identify(userId, identifyTraits);
917
- setUserId(userId);
1163
+ this.adapter.identify(userIdOrIdentifiers, identifyTraits);
1164
+ if (typeof userIdOrIdentifiers === "string") {
1165
+ setUserId(userIdOrIdentifiers);
1166
+ }
1167
+ if (this.config?.debug) {
1168
+ console.log("AmplifyUp SDK: User identified", {
1169
+ userIdOrIdentifiers,
1170
+ instanceId
1171
+ });
1172
+ }
1173
+ }
1174
+ /**
1175
+ * Set profile fields (partial update). Omitted keys are left alone;
1176
+ * an explicit empty value clears the field.
1177
+ */
1178
+ setProfileFields(fields) {
1179
+ if (this.isPreviewMode()) {
1180
+ if (this.config?.debug) {
1181
+ console.log("AmplifyUp SDK: setProfileFields disabled in preview mode", {
1182
+ fields
1183
+ });
1184
+ }
1185
+ return;
1186
+ }
1187
+ if (!this.isInitialized()) {
1188
+ if (this.config?.debug) {
1189
+ console.warn("AmplifyUp SDK: Not initialized. setProfileFields not called.");
1190
+ }
1191
+ return;
1192
+ }
1193
+ const instanceId = getInstanceId();
1194
+ if (typeof this.adapter.setProfileFields === "function") {
1195
+ this.adapter.setProfileFields(fields, {
1196
+ instanceId: instanceId || void 0,
1197
+ trackingId: this.config?.trackingId
1198
+ });
1199
+ }
918
1200
  if (this.config?.debug) {
919
- console.log("AmplifyUp SDK: User identified", { userId, instanceId });
1201
+ console.log("AmplifyUp SDK: Profile fields set", { fields, instanceId });
920
1202
  }
921
1203
  }
922
1204
  /**
@@ -1091,6 +1373,18 @@ Available Console Commands:
1091
1373
  getDecisionApiUrl() {
1092
1374
  return this.decisionApiUrl || void 0;
1093
1375
  }
1376
+ /**
1377
+ * Get Edge Worker URL (production content resolve)
1378
+ */
1379
+ getEdgeUrl() {
1380
+ return this.edgeUrl || void 0;
1381
+ }
1382
+ /**
1383
+ * Optional site id from config (Edge can resolve via trackingId alone).
1384
+ */
1385
+ getSiteId() {
1386
+ return this.siteId || this.config?.siteId || void 0;
1387
+ }
1094
1388
  /**
1095
1389
  * Build API URL for fetching page config from the Layout Provider
1096
1390
  */
@@ -2377,6 +2671,7 @@ function AmplifyRenderer({
2377
2671
  const pageConfig = serverPageConfig || clientHook.pageConfig || null;
2378
2672
  const loading = serverPageConfig ? false : clientHook.loading;
2379
2673
  const error = serverPageConfig ? null : clientHook.error;
2674
+ const contentSource = clientHook.source;
2380
2675
  const [variantCache, setVariantCache] = useState({});
2381
2676
  useEffect(() => {
2382
2677
  if (typeof window !== "undefined") {
@@ -2518,6 +2813,9 @@ function AmplifyRenderer({
2518
2813
  }, [pageConfig]);
2519
2814
  useEffect(() => {
2520
2815
  if (!pageConfig?.layoutTree || !pageConfig.layoutId) return;
2816
+ const roots = pageConfig.layoutTree;
2817
+ const fromEdge = contentSource === "edge" || roots.some((n) => n._contentSource === "edge");
2818
+ if (fromEdge) return;
2521
2819
  const sdk = getSDK();
2522
2820
  const instanceId = sdk.getInstanceId();
2523
2821
  const decisionApiUrl = sdk.getDecisionApiUrl();
@@ -2612,7 +2910,7 @@ function AmplifyRenderer({
2612
2910
  setVariantCache(newCache);
2613
2911
  };
2614
2912
  fetchVariants();
2615
- }, [pageConfig?.layoutTree, pageConfig?.layoutId, pageConfig?.route]);
2913
+ }, [pageConfig?.layoutTree, pageConfig?.layoutId, pageConfig?.route, contentSource]);
2616
2914
  if (loading) {
2617
2915
  return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-gray-50", children: /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse", children: [
2618
2916
  /* @__PURE__ */ jsx("div", { className: "h-8 bg-gray-200 rounded w-1/4 mb-4" }),
@@ -2813,28 +3111,38 @@ async function fetchPageConfigServer(route, trackingId, preview = false, options
2813
3111
  const target = resolveAmplifyUpTarget({
2814
3112
  configTarget: options?.target
2815
3113
  });
2816
- const { orchestratorUrl } = resolveAmplifyUpUrls(target);
2817
- const params = new URLSearchParams({
2818
- route,
2819
- trackingId
2820
- });
2821
- if (preview) {
2822
- params.set("preview", "true");
2823
- }
2824
- const url = `${orchestratorUrl}/api/layout/provider?${params.toString()}`;
2825
- try {
2826
- const res = await fetch(url, {
2827
- cache: "no-store",
2828
- headers: { Accept: "application/json" }
3114
+ const { orchestratorUrl, edgeUrl } = resolveAmplifyUpUrls(target);
3115
+ const previewFlag = preview || (options?.searchParams ? isPreviewRequest(options.searchParams) : false);
3116
+ const fetchOrchestratorPage = async (pageRoute, isPreview) => {
3117
+ const params = new URLSearchParams({
3118
+ route: pageRoute,
3119
+ trackingId
2829
3120
  });
2830
- if (!res.ok) {
3121
+ if (isPreview) params.set("preview", "true");
3122
+ const url = `${orchestratorUrl}/api/layout/provider?${params.toString()}`;
3123
+ try {
3124
+ const res = await fetch(url, {
3125
+ cache: "no-store",
3126
+ headers: { Accept: "application/json" }
3127
+ });
3128
+ if (!res.ok) return null;
3129
+ const data = await res.json();
3130
+ return data.page || null;
3131
+ } catch {
2831
3132
  return null;
2832
3133
  }
2833
- const data = await res.json();
2834
- return data.page || null;
2835
- } catch {
2836
- return null;
2837
- }
3134
+ };
3135
+ const result = await fetchContent({
3136
+ route,
3137
+ trackingId,
3138
+ anonId: options?.anonId,
3139
+ siteId: options?.siteId,
3140
+ preview: previewFlag,
3141
+ orchestratorUrl,
3142
+ edgeUrl,
3143
+ fetchOrchestratorPage
3144
+ });
3145
+ return result.pageConfig;
2838
3146
  }
2839
3147
  var ComponentContext = createContext(null);
2840
3148
  function ComponentContextProvider({
@@ -2993,6 +3301,8 @@ function AmplifyUpProvider({ children, config }) {
2993
3301
  const [pageConfig, setPageConfig] = useState(null);
2994
3302
  const [loading, setLoading] = useState(true);
2995
3303
  const [error, setError] = useState(null);
3304
+ const [source, setSource] = useState(null);
3305
+ const [meta, setMeta] = useState(null);
2996
3306
  const getActualRoute = () => {
2997
3307
  if (typeof window === "undefined") return "";
2998
3308
  const currentPath = window.location.pathname;
@@ -3058,10 +3368,10 @@ function AmplifyUpProvider({ children, config }) {
3058
3368
  return () => {
3059
3369
  cancelled = true;
3060
3370
  };
3061
- }, [config.trackingId, config.target, config.debug, config.dev]);
3371
+ }, [config.trackingId, config.target, config.debug, config.dev, config.siteId]);
3062
3372
  useEffect(() => {
3063
3373
  if (!initialized) return;
3064
- const fetchConfig = async () => {
3374
+ const load = async () => {
3065
3375
  try {
3066
3376
  setLoading(true);
3067
3377
  setError(null);
@@ -3072,29 +3382,57 @@ function AmplifyUpProvider({ children, config }) {
3072
3382
  }
3073
3383
  const sdk = getSDK();
3074
3384
  sdk.routeChange(actualRoute);
3075
- const isPreviewContext = isComposerPreview();
3076
- const page = await sdk.fetchPageConfig(actualRoute, isPreviewContext);
3077
- if (!page) {
3385
+ const preview = isComposerPreview();
3386
+ const edgeUrl = sdk.getEdgeUrl();
3387
+ const orchestratorUrl = sdk.getOrchestratorUrl();
3388
+ const trackingId = sdk.getTrackingId();
3389
+ if (!trackingId || !orchestratorUrl || !edgeUrl) {
3390
+ setError("SDK not initialized");
3391
+ setLoading(false);
3392
+ return;
3393
+ }
3394
+ const result = await fetchContent({
3395
+ route: actualRoute,
3396
+ trackingId,
3397
+ anonId: sdk.getInstanceId(),
3398
+ siteId: sdk.getSiteId() || null,
3399
+ preview,
3400
+ orchestratorUrl,
3401
+ edgeUrl,
3402
+ fetchOrchestratorPage: (route, isPreview) => sdk.fetchPageConfig(route, isPreview)
3403
+ });
3404
+ setSource(result.source);
3405
+ setMeta(result.meta);
3406
+ setError(result.error);
3407
+ if (!result.pageConfig) {
3078
3408
  setPageConfig({
3079
3409
  id: "default",
3080
3410
  route: actualRoute,
3081
3411
  title: "Page Not Configured",
3082
- description: "This page has not been configured in the orchestrator yet.",
3412
+ description: "This page has not been published yet.",
3083
3413
  layoutTree: []
3084
3414
  });
3085
3415
  } else {
3086
- setPageConfig(page);
3416
+ setPageConfig(result.pageConfig);
3087
3417
  }
3088
3418
  } catch (err) {
3089
3419
  console.error("Error fetching page config:", err);
3090
3420
  setError(err instanceof Error ? err.message : "Unknown error");
3421
+ setSource(null);
3422
+ setMeta(null);
3091
3423
  } finally {
3092
3424
  setLoading(false);
3093
3425
  }
3094
3426
  };
3095
- fetchConfig();
3427
+ void load();
3096
3428
  }, [pathname, initialized]);
3097
- return /* @__PURE__ */ jsx(AmplifyUpContext.Provider, { value: { pageConfig, loading, error }, children });
3429
+ return /* @__PURE__ */ jsx(
3430
+ AmplifyUpContext.Provider,
3431
+ {
3432
+ value: { pageConfig, loading, error, source, meta },
3433
+ children
3434
+ }
3435
+ );
3098
3436
  }
3099
3437
  function useAmplifyUp() {
3100
3438
  const context = useContext(AmplifyUpContext);