@amplifyup/sdk 0.1.74 → 0.1.76

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
@@ -1,6 +1,120 @@
1
1
  /* @amplifyup/sdk - https://amplifyup.ai */
2
2
 
3
+ // src/storage.ts
4
+ var INSTANCE_ID_KEY = "amplifyup_instance_id";
5
+ var USER_ID_KEY = "amplifyup_user_id";
6
+ var SESSION_ID_KEY = "amplifyup_session_id";
7
+ var SESSION_ACTIVITY_KEY = "amplifyup_session_activity";
8
+ var VISITOR_FIRST_SEEN_KEY = "amplifyup_visitor_first_seen";
9
+ var ANON_COOKIE_NAME = "amplifyup_anon_id";
10
+ var SESSION_COOKIE_NAME = "amplifyup_session_id";
11
+ var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
12
+ function generateGuid() {
13
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
14
+ return crypto.randomUUID();
15
+ }
16
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
17
+ const r = Math.random() * 16 | 0;
18
+ const v = c === "x" ? r : r & 3 | 8;
19
+ return v.toString(16);
20
+ });
21
+ }
22
+ function readCookie(name) {
23
+ if (typeof document === "undefined") return null;
24
+ const parts = document.cookie.split(";");
25
+ for (const part of parts) {
26
+ const idx = part.indexOf("=");
27
+ if (idx === -1) continue;
28
+ if (part.slice(0, idx).trim() !== name) continue;
29
+ const value = part.slice(idx + 1).trim();
30
+ try {
31
+ return value ? decodeURIComponent(value) : null;
32
+ } catch {
33
+ return value || null;
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+ function writeCookie(name, value, maxAgeSeconds = 31536e3) {
39
+ if (typeof document === "undefined") return;
40
+ document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=${maxAgeSeconds}; SameSite=Lax`;
41
+ }
42
+ function getInstanceId() {
43
+ if (typeof window === "undefined") {
44
+ return "";
45
+ }
46
+ const fromCookie = readCookie(ANON_COOKIE_NAME);
47
+ const fromLs = localStorage.getItem(INSTANCE_ID_KEY);
48
+ const instanceId = fromLs || fromCookie || `browser_${generateGuid()}`;
49
+ if (fromLs !== instanceId) {
50
+ localStorage.setItem(INSTANCE_ID_KEY, instanceId);
51
+ }
52
+ if (fromCookie !== instanceId) {
53
+ writeCookie(ANON_COOKIE_NAME, instanceId);
54
+ }
55
+ return instanceId;
56
+ }
57
+ function getUserId() {
58
+ if (typeof window === "undefined") {
59
+ return null;
60
+ }
61
+ return localStorage.getItem(USER_ID_KEY);
62
+ }
63
+ function getSessionId() {
64
+ if (typeof window === "undefined") {
65
+ return "";
66
+ }
67
+ const now = Date.now();
68
+ const lastActivity = Number(localStorage.getItem(SESSION_ACTIVITY_KEY) || 0);
69
+ const fromCookie = readCookie(SESSION_COOKIE_NAME);
70
+ const fromLs = localStorage.getItem(SESSION_ID_KEY);
71
+ let sessionId = fromLs || fromCookie || "";
72
+ if (!sessionId || lastActivity > 0 && now - lastActivity >= SESSION_IDLE_GAP_MS) {
73
+ sessionId = generateGuid();
74
+ }
75
+ localStorage.setItem(SESSION_ID_KEY, sessionId);
76
+ localStorage.setItem(SESSION_ACTIVITY_KEY, String(now));
77
+ writeCookie(SESSION_COOKIE_NAME, sessionId, Math.floor(SESSION_IDLE_GAP_MS / 1e3));
78
+ return sessionId;
79
+ }
80
+ function getVisitorFirstSeenAt() {
81
+ if (typeof window === "undefined") {
82
+ return null;
83
+ }
84
+ try {
85
+ const existing = localStorage.getItem(VISITOR_FIRST_SEEN_KEY);
86
+ if (existing) return existing;
87
+ const firstSeenAt = (/* @__PURE__ */ new Date()).toISOString();
88
+ localStorage.setItem(VISITOR_FIRST_SEEN_KEY, firstSeenAt);
89
+ return firstSeenAt;
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ function setUserId(userId) {
95
+ if (typeof window === "undefined") {
96
+ return;
97
+ }
98
+ localStorage.setItem(USER_ID_KEY, userId);
99
+ }
100
+ function clearIds() {
101
+ if (typeof window === "undefined") {
102
+ return;
103
+ }
104
+ localStorage.removeItem(INSTANCE_ID_KEY);
105
+ localStorage.removeItem(USER_ID_KEY);
106
+ localStorage.removeItem(SESSION_ID_KEY);
107
+ localStorage.removeItem(SESSION_ACTIVITY_KEY);
108
+ localStorage.removeItem(VISITOR_FIRST_SEEN_KEY);
109
+ document.cookie = `${ANON_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=Lax`;
110
+ document.cookie = `${SESSION_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=Lax`;
111
+ }
112
+
3
113
  // src/adapters/aws.ts
114
+ function visitorContext() {
115
+ const firstSeenAt = getVisitorFirstSeenAt();
116
+ return firstSeenAt ? { firstSeenAt } : void 0;
117
+ }
4
118
  var AWSAdapter = class {
5
119
  constructor() {
6
120
  this.initialized = false;
@@ -40,7 +154,9 @@ var AWSAdapter = class {
40
154
  console.warn("AmplifyUp SDK: AWS configuration missing");
41
155
  return;
42
156
  }
43
- const url = `${this.apiGatewayUrl}${endpoint}`;
157
+ const trackingId = eventData?.trackingId || this.config?.trackingId;
158
+ const query = trackingId ? `?tid=${encodeURIComponent(trackingId)}` : "";
159
+ const url = `${this.apiGatewayUrl}${endpoint}${query}`;
44
160
  try {
45
161
  const response = await fetch(url, {
46
162
  method: "POST",
@@ -102,7 +218,8 @@ var AWSAdapter = class {
102
218
  page: {
103
219
  path: properties.path || properties.url,
104
220
  referrer: properties.referrer
105
- }
221
+ },
222
+ visitor: visitorContext()
106
223
  },
107
224
  timestamp: properties.timestamp || (/* @__PURE__ */ new Date()).toISOString()
108
225
  };
@@ -140,7 +257,8 @@ var AWSAdapter = class {
140
257
  ...properties
141
258
  },
142
259
  context: {
143
- url: properties.url || (typeof window !== "undefined" ? window.location.href : "")
260
+ url: properties.url || (typeof window !== "undefined" ? window.location.href : ""),
261
+ visitor: visitorContext()
144
262
  },
145
263
  timestamp: properties.timestamp || (/* @__PURE__ */ new Date()).toISOString()
146
264
  };
@@ -196,100 +314,6 @@ var AWSAdapter = class {
196
314
  }
197
315
  };
198
316
 
199
- // src/storage.ts
200
- var INSTANCE_ID_KEY = "amplifyup_instance_id";
201
- var USER_ID_KEY = "amplifyup_user_id";
202
- var SESSION_ID_KEY = "amplifyup_session_id";
203
- var SESSION_ACTIVITY_KEY = "amplifyup_session_activity";
204
- var ANON_COOKIE_NAME = "amplifyup_anon_id";
205
- var SESSION_COOKIE_NAME = "amplifyup_session_id";
206
- var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
207
- function generateGuid() {
208
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
209
- return crypto.randomUUID();
210
- }
211
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
212
- const r = Math.random() * 16 | 0;
213
- const v = c === "x" ? r : r & 3 | 8;
214
- return v.toString(16);
215
- });
216
- }
217
- function readCookie(name) {
218
- if (typeof document === "undefined") return null;
219
- const parts = document.cookie.split(";");
220
- for (const part of parts) {
221
- const idx = part.indexOf("=");
222
- if (idx === -1) continue;
223
- if (part.slice(0, idx).trim() !== name) continue;
224
- const value = part.slice(idx + 1).trim();
225
- try {
226
- return value ? decodeURIComponent(value) : null;
227
- } catch {
228
- return value || null;
229
- }
230
- }
231
- return null;
232
- }
233
- function writeCookie(name, value, maxAgeSeconds = 31536e3) {
234
- if (typeof document === "undefined") return;
235
- document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=${maxAgeSeconds}; SameSite=Lax`;
236
- }
237
- function getInstanceId() {
238
- if (typeof window === "undefined") {
239
- return "";
240
- }
241
- const fromCookie = readCookie(ANON_COOKIE_NAME);
242
- const fromLs = localStorage.getItem(INSTANCE_ID_KEY);
243
- const instanceId = fromLs || fromCookie || `browser_${generateGuid()}`;
244
- if (fromLs !== instanceId) {
245
- localStorage.setItem(INSTANCE_ID_KEY, instanceId);
246
- }
247
- if (fromCookie !== instanceId) {
248
- writeCookie(ANON_COOKIE_NAME, instanceId);
249
- }
250
- return instanceId;
251
- }
252
- function getUserId() {
253
- if (typeof window === "undefined") {
254
- return null;
255
- }
256
- return localStorage.getItem(USER_ID_KEY);
257
- }
258
- function getSessionId() {
259
- if (typeof window === "undefined") {
260
- return "";
261
- }
262
- const now = Date.now();
263
- const lastActivity = Number(localStorage.getItem(SESSION_ACTIVITY_KEY) || 0);
264
- const fromCookie = readCookie(SESSION_COOKIE_NAME);
265
- const fromLs = localStorage.getItem(SESSION_ID_KEY);
266
- let sessionId = fromLs || fromCookie || "";
267
- if (!sessionId || lastActivity > 0 && now - lastActivity >= SESSION_IDLE_GAP_MS) {
268
- sessionId = generateGuid();
269
- }
270
- localStorage.setItem(SESSION_ID_KEY, sessionId);
271
- localStorage.setItem(SESSION_ACTIVITY_KEY, String(now));
272
- writeCookie(SESSION_COOKIE_NAME, sessionId, Math.floor(SESSION_IDLE_GAP_MS / 1e3));
273
- return sessionId;
274
- }
275
- function setUserId(userId) {
276
- if (typeof window === "undefined") {
277
- return;
278
- }
279
- localStorage.setItem(USER_ID_KEY, userId);
280
- }
281
- function clearIds() {
282
- if (typeof window === "undefined") {
283
- return;
284
- }
285
- localStorage.removeItem(INSTANCE_ID_KEY);
286
- localStorage.removeItem(USER_ID_KEY);
287
- localStorage.removeItem(SESSION_ID_KEY);
288
- localStorage.removeItem(SESSION_ACTIVITY_KEY);
289
- document.cookie = `${ANON_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=Lax`;
290
- document.cookie = `${SESSION_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=Lax`;
291
- }
292
-
293
317
  // src/targets.ts
294
318
  var AWS_DEV_API = "https://api-dev.amplifyup.ai";
295
319
  var AWS_PROD_API = "https://api.amplifyup.ai";
@@ -743,6 +767,7 @@ function applyPageContext(input, opts) {
743
767
  }
744
768
  const pageFields = {};
745
769
  for (const pf of opts.pageData?.pageFields || []) {
770
+ if (pf.dataType === "taxonomy") continue;
746
771
  if (pf.source === "static") {
747
772
  if (pf.value !== void 0) pageFields[pf.key] = pf.value;
748
773
  continue;
@@ -765,6 +790,7 @@ function applyPageContext(input, opts) {
765
790
  function staticPageFieldsFromSnapshot(pageData) {
766
791
  const pageFields = {};
767
792
  for (const pf of pageData?.pageFields || []) {
793
+ if (pf.dataType === "taxonomy") continue;
768
794
  if (pf.source === "static" && pf.value !== void 0) {
769
795
  pageFields[pf.key] = pf.value;
770
796
  }
@@ -782,6 +808,11 @@ function attachStaticPageContext(pageData, pageRoute) {
782
808
  pageRoute: pageRoute || ""
783
809
  };
784
810
  }
811
+ function withPageTaxonomies(properties, taxonomies) {
812
+ if (!taxonomies || Object.keys(taxonomies).length === 0) return properties;
813
+ const page2 = properties.page && typeof properties.page === "object" && !Array.isArray(properties.page) ? properties.page : { fields: {} };
814
+ return { ...properties, page: { ...page2, taxonomies } };
815
+ }
785
816
  function mergeEventContext(properties, attached) {
786
817
  if (!attached) return properties;
787
818
  return {
@@ -792,6 +823,27 @@ function mergeEventContext(properties, attached) {
792
823
  ...attached.pageResource ? { pageResource: attached.pageResource } : {}
793
824
  };
794
825
  }
826
+
827
+ // src/edge/normalizeRoute.ts
828
+ function normalizeRoute(route) {
829
+ let path = String(route || "").trim();
830
+ if (!path) return "/";
831
+ try {
832
+ if (/^https?:\/\//i.test(path)) {
833
+ path = new URL(path).pathname;
834
+ }
835
+ } catch {
836
+ }
837
+ const q = path.indexOf("?");
838
+ if (q >= 0) path = path.slice(0, q);
839
+ const h = path.indexOf("#");
840
+ if (h >= 0) path = path.slice(0, h);
841
+ if (!path.startsWith("/")) path = `/${path}`;
842
+ if (path.length > 1 && path.endsWith("/")) {
843
+ path = path.replace(/\/+$/, "");
844
+ }
845
+ return path || "/";
846
+ }
795
847
  function setPageResourceFields(fields) {
796
848
  }
797
849
 
@@ -869,27 +921,6 @@ function isAmplifyUpEditorRoute(pathname) {
869
921
  return pathname === AMPLIFYUP_EDITOR_ROUTE || pathname.startsWith(`${AMPLIFYUP_EDITOR_ROUTE}/`);
870
922
  }
871
923
 
872
- // src/edge/normalizeRoute.ts
873
- function normalizeRoute(route) {
874
- let path = String(route || "").trim();
875
- if (!path) return "/";
876
- try {
877
- if (/^https?:\/\//i.test(path)) {
878
- path = new URL(path).pathname;
879
- }
880
- } catch {
881
- }
882
- const q = path.indexOf("?");
883
- if (q >= 0) path = path.slice(0, q);
884
- const h = path.indexOf("#");
885
- if (h >= 0) path = path.slice(0, h);
886
- if (!path.startsWith("/")) path = `/${path}`;
887
- if (path.length > 1 && path.endsWith("/")) {
888
- path = path.replace(/\/+$/, "");
889
- }
890
- return path || "/";
891
- }
892
-
893
924
  // src/edge/variantKeys.ts
894
925
  function serializeVariantKeys(keys) {
895
926
  if (!keys) return "";
@@ -1011,7 +1042,8 @@ function mapResolvedToPageConfig(payload) {
1011
1042
  },
1012
1043
  ...payload.eventTracking && payload.eventTracking.length > 0 ? { eventTracking: payload.eventTracking } : {},
1013
1044
  ...payload.pageData ? { pageData: payload.pageData } : {},
1014
- ...payload.pageResources ? { pageResources: payload.pageResources } : {}
1045
+ ...payload.pageResources ? { pageResources: payload.pageResources } : {},
1046
+ ...payload.pageTaxonomies ? { pageTaxonomies: payload.pageTaxonomies } : {}
1015
1047
  };
1016
1048
  }
1017
1049
  function collectDegraded(payload) {
@@ -1243,6 +1275,7 @@ function searchSpec(pagination, field, term) {
1243
1275
  }
1244
1276
 
1245
1277
  // src/index.ts
1278
+ var PAGE_VIEW_HOLD_MS = 1500;
1246
1279
  var DWELL_ACTIVITY_IDLE_MS = 2 * 60 * 1e3;
1247
1280
  var DWELL_POLL_MS = 5e3;
1248
1281
  function readPreviewQueryOverrides() {
@@ -1316,6 +1349,12 @@ var AmplifyUpSDK = class {
1316
1349
  this.resolvedPageResource = null;
1317
1350
  this.resolvedPageRoute = "";
1318
1351
  this.resolvedRouteParams = {};
1352
+ /** Path whose delivery response is in flight; page_view for it is held. */
1353
+ this.pendingResolvePath = null;
1354
+ this.heldPageView = null;
1355
+ this.resolvedPageTaxonomies = null;
1356
+ /** Path the taxonomies above were resolved for. */
1357
+ this.resolvedTaxonomiesPath = null;
1319
1358
  this.historyHooksInstalled = false;
1320
1359
  this.pageEngagementState = {
1321
1360
  reached: /* @__PURE__ */ new Set(),
@@ -1846,8 +1885,10 @@ var AmplifyUpSDK = class {
1846
1885
  * Apply published pageData (from /v1/resolve) so field validation and
1847
1886
  * mapped page fields can run.
1848
1887
  */
1849
- applyResolvedPageData(pageData, pageRoute, routeParams, pageResources) {
1888
+ applyResolvedPageData(pageData, pageRoute, routeParams, pageResources, pageTaxonomies) {
1850
1889
  this.resolvedPageData = pageData || null;
1890
+ this.resolvedPageTaxonomies = pageTaxonomies || null;
1891
+ this.resolvedTaxonomiesPath = this.pendingResolvePath;
1851
1892
  if (pageRoute) this.resolvedPageRoute = pageRoute;
1852
1893
  if (routeParams) this.resolvedRouteParams = routeParams;
1853
1894
  const firstResourceName = pageData?.resources?.[0]?.name;
@@ -1880,6 +1921,28 @@ var AmplifyUpSDK = class {
1880
1921
  getAttachedPageContext() {
1881
1922
  return this.attachedPageContext;
1882
1923
  }
1924
+ /**
1925
+ * The page's delivery response for `path` is on its way. A page_view for the
1926
+ * same path waits for it (up to PAGE_VIEW_HOLD_MS) so it carries the page's
1927
+ * taxonomies.
1928
+ */
1929
+ beginPageResolve(path) {
1930
+ this.pendingResolvePath = normalizeRoute(path);
1931
+ this.resolvedPageTaxonomies = null;
1932
+ this.resolvedTaxonomiesPath = null;
1933
+ }
1934
+ endPageResolve(path) {
1935
+ if (this.pendingResolvePath !== normalizeRoute(path)) return;
1936
+ this.pendingResolvePath = null;
1937
+ this.flushHeldPageView();
1938
+ }
1939
+ flushHeldPageView() {
1940
+ const held = this.heldPageView;
1941
+ if (!held) return;
1942
+ clearTimeout(held.timer);
1943
+ this.heldPageView = null;
1944
+ this.sendPageView(held.url, held.properties);
1945
+ }
1883
1946
  /**
1884
1947
  * Track a page view
1885
1948
  */
@@ -1890,6 +1953,21 @@ var AmplifyUpSDK = class {
1890
1953
  if (!this.isInitialized()) {
1891
1954
  return;
1892
1955
  }
1956
+ this.lastTrackedPath = url;
1957
+ if (this.pendingResolvePath && this.pendingResolvePath === normalizeRoute(url)) {
1958
+ this.flushHeldPageView();
1959
+ this.heldPageView = {
1960
+ url,
1961
+ properties,
1962
+ timer: setTimeout(() => this.flushHeldPageView(), PAGE_VIEW_HOLD_MS)
1963
+ };
1964
+ return;
1965
+ }
1966
+ this.flushHeldPageView();
1967
+ this.sendPageView(url, properties);
1968
+ }
1969
+ sendPageView(url, properties) {
1970
+ const taxonomies = this.resolvedTaxonomiesPath && this.resolvedTaxonomiesPath === normalizeRoute(url) ? this.resolvedPageTaxonomies : null;
1893
1971
  const instanceId = getInstanceId();
1894
1972
  const sessionId = getSessionId();
1895
1973
  const pageProperties = {
@@ -1901,10 +1979,9 @@ var AmplifyUpSDK = class {
1901
1979
  sessionId,
1902
1980
  trackingId: this.config?.trackingId,
1903
1981
  // Timestamp is included in event payload
1904
- ...mergeEventContext(properties || {}, this.attachedPageContext)
1982
+ ...withPageTaxonomies(mergeEventContext(properties || {}, this.attachedPageContext), taxonomies)
1905
1983
  };
1906
1984
  this.adapter.page(pageProperties);
1907
- this.lastTrackedPath = url;
1908
1985
  }
1909
1986
  /**
1910
1987
  * Track an event