@amplifyup/sdk 0.1.43 → 0.1.45

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.mjs CHANGED
@@ -394,6 +394,153 @@ function isComposerPreview() {
394
394
  return false;
395
395
  }
396
396
 
397
+ // src/page-context.ts
398
+ var defaultLog = {
399
+ warn: (...args) => {
400
+ if (typeof console !== "undefined") console.warn(...args);
401
+ }
402
+ };
403
+ function coerceField(def, raw, log) {
404
+ if (raw == null) return void 0;
405
+ if (def.multiValue) {
406
+ const list = Array.isArray(raw) ? raw : [raw];
407
+ const out = [];
408
+ for (const item of list) {
409
+ const coerced = coerceScalar(def, item, log);
410
+ if (coerced !== void 0) out.push(coerced);
411
+ }
412
+ return out;
413
+ }
414
+ return coerceScalar(def, raw, log);
415
+ }
416
+ function coerceScalar(def, raw, log) {
417
+ switch (def.dataType) {
418
+ case "string":
419
+ if (typeof raw === "string") return raw;
420
+ if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
421
+ log.warn(`AmplifyUp: dropped field "${def.key}" (expected string)`);
422
+ return void 0;
423
+ case "number": {
424
+ if (typeof raw === "number" && Number.isFinite(raw)) return raw;
425
+ if (typeof raw === "string" && raw.trim() !== "" && Number.isFinite(Number(raw))) {
426
+ return Number(raw);
427
+ }
428
+ log.warn(`AmplifyUp: dropped field "${def.key}" (expected number)`);
429
+ return void 0;
430
+ }
431
+ case "boolean": {
432
+ if (typeof raw === "boolean") return raw;
433
+ if (raw === "true") return true;
434
+ if (raw === "false") return false;
435
+ log.warn(`AmplifyUp: dropped field "${def.key}" (expected boolean)`);
436
+ return void 0;
437
+ }
438
+ case "date": {
439
+ if (typeof raw === "string" && !Number.isNaN(Date.parse(raw))) return raw;
440
+ log.warn(`AmplifyUp: dropped field "${def.key}" (expected date)`);
441
+ return void 0;
442
+ }
443
+ default:
444
+ return void 0;
445
+ }
446
+ }
447
+ function applyPageContext(input, opts) {
448
+ const log = opts.log || defaultLog;
449
+ const key = String(input.key || "").trim();
450
+ if (!key || !input.resourceType) {
451
+ log.warn("AmplifyUp: pageContext needs resourceType and key");
452
+ return null;
453
+ }
454
+ const resource = opts.pageData?.resources?.[0];
455
+ if (resource && resource.type && resource.type !== input.resourceType) {
456
+ log.warn(
457
+ `AmplifyUp: pageContext resourceType "${input.resourceType}" does not match page resource "${resource.type}"`
458
+ );
459
+ return null;
460
+ }
461
+ const fieldDefs = resource?.fields || [];
462
+ const defByKey = new Map(fieldDefs.map((f) => [f.key, f]));
463
+ const rawFields = input.fields && typeof input.fields === "object" ? input.fields : {};
464
+ const fields = {};
465
+ if (fieldDefs.length === 0) {
466
+ Object.assign(fields, rawFields);
467
+ } else {
468
+ for (const [k, v] of Object.entries(rawFields)) {
469
+ const def = defByKey.get(k);
470
+ if (!def) {
471
+ log.warn(`AmplifyUp: unknown resource field "${k}" dropped`);
472
+ continue;
473
+ }
474
+ const coerced = coerceField(def, v, log);
475
+ if (coerced !== void 0) fields[k] = coerced;
476
+ }
477
+ }
478
+ const params = { ...opts.routeParams || {} };
479
+ const mapping = resource?.urlParamMapping;
480
+ let resourceKey = key;
481
+ if (mapping) {
482
+ const fromUrl = params[mapping.param];
483
+ const fromField = fields[mapping.field];
484
+ if (fromUrl) resourceKey = String(fromUrl);
485
+ if (fromUrl && fromField != null && String(fromField) !== String(fromUrl)) {
486
+ log.warn(
487
+ `AmplifyUp: resource key mismatch \u2014 URL :${mapping.param} is "${fromUrl}" but ${mapping.field} is "${String(fromField)}". Using the URL param.`
488
+ );
489
+ }
490
+ }
491
+ const pageFields = {};
492
+ for (const pf of opts.pageData?.pageFields || []) {
493
+ if (pf.source === "static") {
494
+ if (pf.value !== void 0) pageFields[pf.key] = pf.value;
495
+ continue;
496
+ }
497
+ if (pf.source === "mapped" && pf.resource && pf.field) {
498
+ pageFields[pf.key] = fields[pf.field];
499
+ }
500
+ }
501
+ return {
502
+ resource: {
503
+ type: input.resourceType,
504
+ key: resourceKey,
505
+ params,
506
+ fields
507
+ },
508
+ page: { fields: pageFields },
509
+ pageRoute: opts.pageRoute || ""
510
+ };
511
+ }
512
+ function staticPageFieldsFromSnapshot(pageData) {
513
+ const pageFields = {};
514
+ for (const pf of pageData?.pageFields || []) {
515
+ if (pf.source === "static" && pf.value !== void 0) {
516
+ pageFields[pf.key] = pf.value;
517
+ }
518
+ }
519
+ return pageFields;
520
+ }
521
+ function attachStaticPageContext(pageData, pageRoute) {
522
+ if (!pageData) return null;
523
+ const fields = staticPageFieldsFromSnapshot(pageData);
524
+ const hasStatic = Object.keys(fields).length > 0;
525
+ const hasRoute = !!pageRoute;
526
+ if (!hasStatic && !hasRoute) return null;
527
+ return {
528
+ page: { fields },
529
+ pageRoute: pageRoute || ""
530
+ };
531
+ }
532
+ function mergeEventContext(properties, attached) {
533
+ if (!attached) return properties;
534
+ return {
535
+ ...properties,
536
+ ...attached.resource ? { resource: attached.resource } : {},
537
+ page: attached.page,
538
+ ...attached.pageRoute ? { pageRoute: attached.pageRoute } : {}
539
+ };
540
+ }
541
+ function setPageResourceFields(fields) {
542
+ }
543
+
397
544
  // src/reservedRoutes.ts
398
545
  var AMPLIFYUP_EDITOR_ROUTE = "/__amplifyup/editor";
399
546
  function isAmplifyUpEditorRoute(pathname) {
@@ -519,7 +666,8 @@ function mapResolvedToPageConfig(payload) {
519
666
  // Stash edge meta for diagnostics (not visitor-facing)
520
667
  description: payload.meta?.degraded ? "degraded" : void 0
521
668
  },
522
- ...payload.eventTracking && payload.eventTracking.length > 0 ? { eventTracking: payload.eventTracking } : {}
669
+ ...payload.eventTracking && payload.eventTracking.length > 0 ? { eventTracking: payload.eventTracking } : {},
670
+ ...payload.pageData ? { pageData: payload.pageData } : {}
523
671
  };
524
672
  }
525
673
  function collectDegraded(payload) {
@@ -809,6 +957,11 @@ var AmplifyUpSDK = class {
809
957
  this.pageEngagementActive = false;
810
958
  /** Path of the last page() / routeChange — avoids duplicate SPA fires. */
811
959
  this.lastTrackedPath = null;
960
+ this.pendingPageContext = null;
961
+ this.attachedPageContext = null;
962
+ this.resolvedPageData = null;
963
+ this.resolvedPageRoute = "";
964
+ this.resolvedRouteParams = {};
812
965
  this.historyHooksInstalled = false;
813
966
  this.pageEngagementState = {
814
967
  reached: /* @__PURE__ */ new Set(),
@@ -971,8 +1124,13 @@ var AmplifyUpSDK = class {
971
1124
  // Enable debug by default
972
1125
  target: this.target,
973
1126
  dev: config.dev,
974
- ...config.siteId ? { siteId: config.siteId } : {}
1127
+ ...config.siteId ? { siteId: config.siteId } : {},
1128
+ ...config.pageContext ? { pageContext: config.pageContext } : {}
975
1129
  };
1130
+ if (config.pageContext) {
1131
+ this.pendingPageContext = config.pageContext;
1132
+ this.recomputeAttachedContext();
1133
+ }
976
1134
  try {
977
1135
  const adapterConfig = {
978
1136
  ...this.config,
@@ -1329,6 +1487,43 @@ var AmplifyUpSDK = class {
1329
1487
  this.componentViewObservers.forEach((obs) => obs.disconnect());
1330
1488
  this.componentViewObservers = [];
1331
1489
  }
1490
+ /**
1491
+ * Set resource context for this page. Prefer passing `pageContext` on
1492
+ * AmplifyUpProvider / init — required for components using From page.
1493
+ * Late calls still attach to subsequent events (not a second page view).
1494
+ */
1495
+ setPageContext(input) {
1496
+ this.pendingPageContext = input;
1497
+ this.recomputeAttachedContext();
1498
+ }
1499
+ /**
1500
+ * Apply published pageData (from /v1/resolve) so field validation and
1501
+ * mapped page fields can run.
1502
+ */
1503
+ applyResolvedPageData(pageData, pageRoute, routeParams) {
1504
+ this.resolvedPageData = pageData || null;
1505
+ if (pageRoute) this.resolvedPageRoute = pageRoute;
1506
+ if (routeParams) this.resolvedRouteParams = routeParams;
1507
+ this.recomputeAttachedContext();
1508
+ }
1509
+ recomputeAttachedContext() {
1510
+ if (!this.pendingPageContext) {
1511
+ this.attachedPageContext = attachStaticPageContext(
1512
+ this.resolvedPageData,
1513
+ this.resolvedPageRoute
1514
+ );
1515
+ return;
1516
+ }
1517
+ this.attachedPageContext = applyPageContext(this.pendingPageContext, {
1518
+ pageData: this.resolvedPageData,
1519
+ routeParams: this.resolvedRouteParams,
1520
+ pageRoute: this.resolvedPageRoute
1521
+ });
1522
+ setPageResourceFields(this.attachedPageContext?.resource?.fields || null);
1523
+ }
1524
+ getAttachedPageContext() {
1525
+ return this.attachedPageContext;
1526
+ }
1332
1527
  /**
1333
1528
  * Track a page view
1334
1529
  */
@@ -1350,7 +1545,7 @@ var AmplifyUpSDK = class {
1350
1545
  sessionId,
1351
1546
  trackingId: this.config?.trackingId,
1352
1547
  // Timestamp is included in event payload
1353
- ...properties
1548
+ ...mergeEventContext(properties || {}, this.attachedPageContext)
1354
1549
  };
1355
1550
  this.adapter.page(pageProperties);
1356
1551
  this.lastTrackedPath = url;
@@ -1374,7 +1569,7 @@ var AmplifyUpSDK = class {
1374
1569
  url: typeof window !== "undefined" ? window.location.href : void 0,
1375
1570
  path: properties?.path || (typeof window !== "undefined" ? window.location.pathname : void 0),
1376
1571
  // Timestamp is included in event payload
1377
- ...properties
1572
+ ...mergeEventContext(properties || {}, this.attachedPageContext)
1378
1573
  };
1379
1574
  if (!trackProperties.path && typeof window !== "undefined") {
1380
1575
  trackProperties.path = window.location.pathname;