@amplifyup/sdk 0.1.22 → 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/index.js CHANGED
@@ -145,17 +145,42 @@ var AWSAdapter = class {
145
145
  };
146
146
  this.sendEvent("/v1/track", eventData);
147
147
  }
148
- identify(userId, traits) {
148
+ identify(userIdOrIdentifiers, traits = {}) {
149
149
  if (!this.initialized) {
150
150
  console.warn("AmplifyUp SDK: Not initialized. Call init() first.");
151
151
  return;
152
152
  }
153
+ const isMap = userIdOrIdentifiers !== null && typeof userIdOrIdentifiers === "object" && !Array.isArray(userIdOrIdentifiers);
154
+ const identifiers = isMap ? userIdOrIdentifiers : traits.identifiers;
155
+ const userId = isMap ? void 0 : String(userIdOrIdentifiers);
153
156
  const eventData = {
154
157
  type: "identify",
155
- userId,
156
158
  anonymousId: traits.instanceId,
157
159
  traits: {
158
- ...traits
160
+ ...traits,
161
+ ...identifiers ? { identifiers } : {}
162
+ },
163
+ ...identifiers ? { identifiers } : {},
164
+ ...userId ? { userId } : {},
165
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
166
+ };
167
+ this.sendEvent("/v1/track", eventData);
168
+ }
169
+ setProfileFields(fields, context = {}) {
170
+ if (!this.initialized) {
171
+ console.warn("AmplifyUp SDK: Not initialized. Call init() first.");
172
+ return;
173
+ }
174
+ const eventData = {
175
+ type: "set_fields",
176
+ anonymousId: context.instanceId,
177
+ fields,
178
+ traits: {
179
+ instanceId: context.instanceId,
180
+ trackingId: context.trackingId
181
+ },
182
+ properties: {
183
+ trackingId: context.trackingId
159
184
  },
160
185
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
161
186
  };
@@ -217,6 +242,7 @@ function clearIds() {
217
242
  var AWS_DEV_API = "https://api-dev.amplifyup.ai";
218
243
  var AWS_PROD_API = "https://api.amplifyup.ai";
219
244
  var PROD_ORCHESTRATOR = "https://amplifyup.ai";
245
+ var PROD_EDGE = "https://edge.amplifyup.ai";
220
246
  function isAmplifyUpTarget(value) {
221
247
  return value === "local" || value === "dev" || value === "production";
222
248
  }
@@ -252,6 +278,10 @@ function localAwsApiUrl() {
252
278
  const fromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_AMPLIFYUP_API_URL : void 0;
253
279
  return (fromEnv || AWS_DEV_API).replace(/\/$/, "");
254
280
  }
281
+ function localEdgeUrl() {
282
+ const fromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_EDGE_URL : void 0;
283
+ return (fromEnv || "http://localhost:8787").replace(/\/$/, "");
284
+ }
255
285
  function resolveAmplifyUpUrls(target) {
256
286
  if (target === "local") {
257
287
  const orchestratorUrl2 = localOrchestratorUrl();
@@ -262,18 +292,22 @@ function resolveAmplifyUpUrls(target) {
262
292
  orchestratorUrl: orchestratorUrl2,
263
293
  // Events + personalize → AWS development stack
264
294
  apiGatewayUrl,
265
- decisionApiUrl: `${apiGatewayUrl}/v1/personalize`
295
+ decisionApiUrl: `${apiGatewayUrl}/v1/personalize`,
296
+ edgeUrl: localEdgeUrl()
266
297
  };
267
298
  }
268
299
  const resolvedApi = typeof process !== "undefined" && process.env.NEXT_PUBLIC_AMPLIFYUP_API_URL?.replace(/\/$/, "") || AWS_PROD_API;
269
300
  const orchestratorFromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_ORCHESTRATOR_URL : void 0;
270
301
  const isLocalOrchestrator = !!orchestratorFromEnv && (orchestratorFromEnv.includes("localhost") || orchestratorFromEnv.includes("127.0.0.1"));
271
302
  const orchestratorUrl = isLocalOrchestrator || !orchestratorFromEnv ? PROD_ORCHESTRATOR : orchestratorFromEnv.replace(/\/$/, "");
303
+ const edgeFromEnv = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_EDGE_URL?.replace(/\/$/, "") : void 0;
304
+ const edgeUrl = edgeFromEnv && !edgeFromEnv.includes("localhost") && !edgeFromEnv.includes("127.0.0.1") ? edgeFromEnv : PROD_EDGE;
272
305
  return {
273
306
  target: "production",
274
307
  apiGatewayUrl: resolvedApi,
275
308
  orchestratorUrl,
276
- decisionApiUrl: `${resolvedApi}/v1/personalize`
309
+ decisionApiUrl: `${resolvedApi}/v1/personalize`,
310
+ edgeUrl
277
311
  };
278
312
  }
279
313
 
@@ -303,6 +337,177 @@ function isComposerPreview() {
303
337
  return false;
304
338
  }
305
339
 
340
+ // src/edge/normalizeRoute.ts
341
+ function normalizeRoute(route) {
342
+ let path = String(route || "").trim();
343
+ if (!path) return "/";
344
+ try {
345
+ if (/^https?:\/\//i.test(path)) {
346
+ path = new URL(path).pathname;
347
+ }
348
+ } catch {
349
+ }
350
+ const q = path.indexOf("?");
351
+ if (q >= 0) path = path.slice(0, q);
352
+ const h = path.indexOf("#");
353
+ if (h >= 0) path = path.slice(0, h);
354
+ if (!path.startsWith("/")) path = `/${path}`;
355
+ if (path.length > 1 && path.endsWith("/")) {
356
+ path = path.replace(/\/+$/, "");
357
+ }
358
+ return path || "/";
359
+ }
360
+
361
+ // src/edge/resolve.ts
362
+ var EdgeResolveError = class extends Error {
363
+ constructor(message, status, body) {
364
+ super(message);
365
+ this.name = "EdgeResolveError";
366
+ this.status = status;
367
+ this.body = body;
368
+ }
369
+ };
370
+ async function fetchEdgeResolve(options) {
371
+ const base = options.edgeUrl.replace(/\/+$/, "");
372
+ const route = normalizeRoute(options.route);
373
+ const params = new URLSearchParams({
374
+ route,
375
+ trackingId: options.trackingId
376
+ });
377
+ if (options.siteId) params.set("site", options.siteId);
378
+ if (options.anonId) params.set("anonId", options.anonId);
379
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
380
+ const res = await fetchFn(`${base}/v1/resolve?${params.toString()}`, {
381
+ method: "GET",
382
+ headers: { Accept: "application/json" }
383
+ });
384
+ const body = await res.json().catch(() => ({}));
385
+ if (!res.ok) {
386
+ throw new EdgeResolveError(
387
+ (body && typeof body === "object" && "error" in body ? String(body.error) : `Edge resolve failed (${res.status})`) || `Edge resolve failed (${res.status})`,
388
+ res.status,
389
+ body
390
+ );
391
+ }
392
+ return body;
393
+ }
394
+
395
+ // src/edge/mapResolvedToPageConfig.ts
396
+ function mapResolvedComponent(node) {
397
+ const slots = [];
398
+ if (node.children) {
399
+ for (const [slotId, kids] of Object.entries(node.children)) {
400
+ slots.push({
401
+ slotId,
402
+ children: (kids || []).map(mapResolvedComponent)
403
+ });
404
+ }
405
+ }
406
+ return {
407
+ id: node.instanceId,
408
+ componentId: node.componentId,
409
+ props: { ...node.props || {} },
410
+ ...slots.length > 0 ? { slots } : {},
411
+ _contentSource: "edge"
412
+ };
413
+ }
414
+ function mapResolvedToPageConfig(payload) {
415
+ let layoutTree = [];
416
+ if (payload.tree && payload.tree.length > 0) {
417
+ layoutTree = payload.tree.map(mapResolvedComponent);
418
+ } else {
419
+ const zoneIds = Object.keys(payload.zones || {}).sort();
420
+ for (const zoneId of zoneIds) {
421
+ const roots = payload.zones[zoneId] || [];
422
+ layoutTree.push(...roots.map(mapResolvedComponent));
423
+ }
424
+ }
425
+ return {
426
+ id: `edge:${payload.siteId}:${payload.route}:v${payload.version}`,
427
+ route: payload.route,
428
+ title: "",
429
+ layoutTree,
430
+ meta: {
431
+ // Stash edge meta for diagnostics (not visitor-facing)
432
+ description: payload.meta?.degraded ? "degraded" : void 0
433
+ }
434
+ };
435
+ }
436
+ function collectDegraded(payload) {
437
+ if (payload.meta?.degraded) return true;
438
+ const walk = (nodes) => nodes.some(
439
+ (n) => !!n.degraded || (n.children ? Object.values(n.children).some((kids) => walk(kids || [])) : false)
440
+ );
441
+ if (payload.tree && walk(payload.tree)) return true;
442
+ return Object.values(payload.zones || {}).some((roots) => walk(roots || []));
443
+ }
444
+
445
+ // src/content/fetchContent.ts
446
+ async function fetchContent(options) {
447
+ const preview = options.preview ?? (typeof window !== "undefined" ? isComposerPreview() : false);
448
+ if (preview) {
449
+ try {
450
+ const page2 = await options.fetchOrchestratorPage(options.route, true);
451
+ return {
452
+ pageConfig: page2,
453
+ source: "orchestrator",
454
+ meta: { source: "orchestrator" },
455
+ error: null
456
+ };
457
+ } catch (err) {
458
+ return {
459
+ pageConfig: null,
460
+ source: "orchestrator",
461
+ meta: { source: "orchestrator" },
462
+ error: err instanceof Error ? err.message : "Failed to load preview"
463
+ };
464
+ }
465
+ }
466
+ try {
467
+ const payload = await fetchEdgeResolve({
468
+ edgeUrl: options.edgeUrl,
469
+ trackingId: options.trackingId,
470
+ route: options.route,
471
+ anonId: options.anonId,
472
+ siteId: options.siteId,
473
+ fetch: options.fetchFn
474
+ });
475
+ const pageConfig = mapResolvedToPageConfig(payload);
476
+ const degraded = collectDegraded(payload);
477
+ return {
478
+ pageConfig,
479
+ source: "edge",
480
+ meta: {
481
+ source: "edge",
482
+ version: payload.version,
483
+ siteId: payload.siteId,
484
+ variantKeys: payload.meta?.variantKeys,
485
+ degraded,
486
+ audienceLookup: payload.meta?.audienceLookup,
487
+ decideLookup: payload.meta?.decideLookup,
488
+ resolvedAt: payload.meta?.resolvedAt
489
+ },
490
+ error: null
491
+ };
492
+ } catch (err) {
493
+ if (err instanceof EdgeResolveError && err.status === 404) {
494
+ return {
495
+ pageConfig: null,
496
+ source: "edge",
497
+ meta: { source: "edge" },
498
+ error: null
499
+ // unpublished → site fallback, not an error banner
500
+ };
501
+ }
502
+ return {
503
+ pageConfig: null,
504
+ source: "edge",
505
+ meta: { source: "edge" },
506
+ error: err instanceof Error ? err.message : "Couldn't load page content."
507
+ };
508
+ }
509
+ }
510
+
306
511
  // src/index.ts
307
512
  var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
308
513
  function readPreviewQueryOverrides() {
@@ -332,6 +537,8 @@ var AmplifyUpSDK = class {
332
537
  this.apiGatewayUrl = "";
333
538
  this.orchestratorUrl = "";
334
539
  this.decisionApiUrl = "";
540
+ this.edgeUrl = "";
541
+ this.siteId = "";
335
542
  this.target = "local";
336
543
  this.initialized = false;
337
544
  /** Prevents overlapping init() from React Strict Mode double-mount */
@@ -488,7 +695,8 @@ var AmplifyUpSDK = class {
488
695
  isInitialized: () => this.isInitialized(),
489
696
  page: (url, properties) => this.page(url, properties),
490
697
  track: (eventName, properties) => this.track(eventName, properties),
491
- identify: (userId, traits) => this.identify(userId, traits)
698
+ identify: (userIdOrIdentifiers, traits) => this.identify(userIdOrIdentifiers, traits),
699
+ setProfileFields: (fields) => this.setProfileFields(fields)
492
700
  };
493
701
  }
494
702
  async performInit(config) {
@@ -503,6 +711,8 @@ var AmplifyUpSDK = class {
503
711
  this.apiGatewayUrl = urls.apiGatewayUrl;
504
712
  this.orchestratorUrl = urls.orchestratorUrl;
505
713
  this.decisionApiUrl = urls.decisionApiUrl;
714
+ this.edgeUrl = urls.edgeUrl;
715
+ this.siteId = config.siteId || "";
506
716
  const previewOverrides = readPreviewQueryOverrides();
507
717
  if (previewOverrides.orchestratorUrl) {
508
718
  this.orchestratorUrl = previewOverrides.orchestratorUrl;
@@ -511,6 +721,7 @@ var AmplifyUpSDK = class {
511
721
  this.target = "production";
512
722
  this.apiGatewayUrl = prodUrls.apiGatewayUrl;
513
723
  this.decisionApiUrl = prodUrls.decisionApiUrl;
724
+ this.edgeUrl = prodUrls.edgeUrl;
514
725
  }
515
726
  }
516
727
  this.config = {
@@ -518,7 +729,8 @@ var AmplifyUpSDK = class {
518
729
  debug: config.debug ?? true,
519
730
  // Enable debug by default
520
731
  target: this.target,
521
- dev: config.dev
732
+ dev: config.dev,
733
+ ...config.siteId ? { siteId: config.siteId } : {}
522
734
  };
523
735
  try {
524
736
  const adapterConfig = {
@@ -916,12 +1128,17 @@ var AmplifyUpSDK = class {
916
1128
  });
917
1129
  }
918
1130
  /**
919
- * Identify user (when they sign up or log in)
1131
+ * Identify a visitor.
1132
+ * - identify('user_123') — bare string; server maps via org default type
1133
+ * - identify({ email: '...', crm_id: '...' }) — explicit types
1134
+ * - identify('user_123', traits) — legacy form
920
1135
  */
921
- identify(userId, traits) {
1136
+ identify(userIdOrIdentifiers, traits) {
922
1137
  if (this.isPreviewMode()) {
923
1138
  if (this.config?.debug) {
924
- console.log("AmplifyUp SDK: Identify tracking disabled in preview mode", { userId });
1139
+ console.log("AmplifyUp SDK: Identify tracking disabled in preview mode", {
1140
+ userIdOrIdentifiers
1141
+ });
925
1142
  }
926
1143
  return;
927
1144
  }
@@ -937,10 +1154,45 @@ var AmplifyUpSDK = class {
937
1154
  trackingId: this.config?.trackingId,
938
1155
  ...traits
939
1156
  };
940
- this.adapter.identify(userId, identifyTraits);
941
- setUserId(userId);
1157
+ this.adapter.identify(userIdOrIdentifiers, identifyTraits);
1158
+ if (typeof userIdOrIdentifiers === "string") {
1159
+ setUserId(userIdOrIdentifiers);
1160
+ }
1161
+ if (this.config?.debug) {
1162
+ console.log("AmplifyUp SDK: User identified", {
1163
+ userIdOrIdentifiers,
1164
+ instanceId
1165
+ });
1166
+ }
1167
+ }
1168
+ /**
1169
+ * Set profile fields (partial update). Omitted keys are left alone;
1170
+ * an explicit empty value clears the field.
1171
+ */
1172
+ setProfileFields(fields) {
1173
+ if (this.isPreviewMode()) {
1174
+ if (this.config?.debug) {
1175
+ console.log("AmplifyUp SDK: setProfileFields disabled in preview mode", {
1176
+ fields
1177
+ });
1178
+ }
1179
+ return;
1180
+ }
1181
+ if (!this.isInitialized()) {
1182
+ if (this.config?.debug) {
1183
+ console.warn("AmplifyUp SDK: Not initialized. setProfileFields not called.");
1184
+ }
1185
+ return;
1186
+ }
1187
+ const instanceId = getInstanceId();
1188
+ if (typeof this.adapter.setProfileFields === "function") {
1189
+ this.adapter.setProfileFields(fields, {
1190
+ instanceId: instanceId || void 0,
1191
+ trackingId: this.config?.trackingId
1192
+ });
1193
+ }
942
1194
  if (this.config?.debug) {
943
- console.log("AmplifyUp SDK: User identified", { userId, instanceId });
1195
+ console.log("AmplifyUp SDK: Profile fields set", { fields, instanceId });
944
1196
  }
945
1197
  }
946
1198
  /**
@@ -1115,6 +1367,18 @@ Available Console Commands:
1115
1367
  getDecisionApiUrl() {
1116
1368
  return this.decisionApiUrl || void 0;
1117
1369
  }
1370
+ /**
1371
+ * Get Edge Worker URL (production content resolve)
1372
+ */
1373
+ getEdgeUrl() {
1374
+ return this.edgeUrl || void 0;
1375
+ }
1376
+ /**
1377
+ * Optional site id from config (Edge can resolve via trackingId alone).
1378
+ */
1379
+ getSiteId() {
1380
+ return this.siteId || this.config?.siteId || void 0;
1381
+ }
1118
1382
  /**
1119
1383
  * Build API URL for fetching page config from the Layout Provider
1120
1384
  */
@@ -2397,7 +2661,8 @@ var trackClick = (elementId, elementText, properties) => getSDK().trackClick(ele
2397
2661
  var trackFormSubmit = (formId, formData) => getSDK().trackFormSubmit(formId, formData);
2398
2662
  var trackFormFieldInteraction = (fieldName, fieldValue) => getSDK().trackFormFieldInteraction(fieldName, fieldValue);
2399
2663
  var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
2400
- var identify = (userId, traits) => getSDK().identify(userId, traits);
2664
+ var identify = (userIdOrIdentifiers, traits) => getSDK().identify(userIdOrIdentifiers, traits);
2665
+ var setProfileFields = (fields) => getSDK().setProfileFields(fields);
2401
2666
  var trackContentEngagement = (contentId, engagementType) => getSDK().trackContentEngagement(contentId, engagementType);
2402
2667
  var reset = () => getSDK().reset();
2403
2668
  var getInstanceId2 = () => getSDK().getInstanceId();
@@ -2428,11 +2693,14 @@ var verifyAWSConnection = () => {
2428
2693
  var index_default = getSDK();
2429
2694
 
2430
2695
  exports.AmplifyUpSDK = AmplifyUpSDK;
2696
+ exports.EdgeResolveError = EdgeResolveError;
2431
2697
  exports.SESSION_IDLE_GAP_MS = SESSION_IDLE_GAP_MS;
2432
2698
  exports.buildLayoutProviderUrl = buildLayoutProviderUrl;
2433
2699
  exports.buildPageRenderUrl = buildPageRenderUrl;
2434
2700
  exports.cleanupEventTracking = cleanupEventTracking;
2435
2701
  exports.default = index_default;
2702
+ exports.fetchContent = fetchContent;
2703
+ exports.fetchEdgeResolve = fetchEdgeResolve;
2436
2704
  exports.fetchPageConfig = fetchPageConfig;
2437
2705
  exports.getDiagnostics = getDiagnostics;
2438
2706
  exports.getInstanceId = getInstanceId2;
@@ -2447,13 +2715,16 @@ exports.init = init;
2447
2715
  exports.isAmplifyUpTarget = isAmplifyUpTarget;
2448
2716
  exports.isComposerPreview = isComposerPreview;
2449
2717
  exports.isPreviewRequest = isPreviewRequest;
2718
+ exports.mapResolvedToPageConfig = mapResolvedToPageConfig;
2450
2719
  exports.normalizeAmplifyUpTarget = normalizeAmplifyUpTarget;
2720
+ exports.normalizeRoute = normalizeRoute;
2451
2721
  exports.page = page;
2452
2722
  exports.refreshEventTracking = refreshEventTracking;
2453
2723
  exports.reset = reset;
2454
2724
  exports.resolveAmplifyUpTarget = resolveAmplifyUpTarget;
2455
2725
  exports.resolveAmplifyUpUrls = resolveAmplifyUpUrls;
2456
2726
  exports.routeChange = routeChange;
2727
+ exports.setProfileFields = setProfileFields;
2457
2728
  exports.setupComponentViewTracking = setupComponentViewTracking;
2458
2729
  exports.setupEventTracking = setupEventTracking;
2459
2730
  exports.testTracking = testTracking;