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