@aranova/tracking-next 0.14.2 → 0.16.0

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.
@@ -2,25 +2,6 @@
2
2
  import "server-only";
3
3
  import { NextResponse } from "next/server";
4
4
 
5
- // ../tracking-core/src/consent.ts
6
- var CONSENT_STATE_KEY = "consent_state";
7
- var grantedListeners = /* @__PURE__ */ new Set();
8
- function onConsentGranted(listener) {
9
- grantedListeners.add(listener);
10
- return () => {
11
- grantedListeners.delete(listener);
12
- };
13
- }
14
- function getConsentState() {
15
- if (typeof window === "undefined") return "pending";
16
- try {
17
- const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
18
- if (storedState === "granted" || storedState === "denied") return storedState;
19
- } catch {
20
- }
21
- return "pending";
22
- }
23
-
24
5
  // ../tracking-core/src/tracking.ts
25
6
  var TRACKING_PARAM_KEYS = [
26
7
  "gclid",
@@ -41,60 +22,6 @@ function getTrackingQueryValues(searchParams) {
41
22
  }, {});
42
23
  }
43
24
 
44
- // ../tracking-core/src/gtag.ts
45
- var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
46
- function isValidSendTo(sendTo) {
47
- return SEND_TO_RE.test(sendTo);
48
- }
49
- function fireGtagConversion(input) {
50
- if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
51
- if (!isValidSendTo(input.sendTo)) return false;
52
- const params = { send_to: input.sendTo };
53
- if (input.value != null) params.value = input.value;
54
- if (input.currency) params.currency = input.currency;
55
- if (input.transactionId) params.transaction_id = input.transactionId;
56
- try {
57
- window.gtag("event", "conversion", params);
58
- return true;
59
- } catch {
60
- return false;
61
- }
62
- }
63
-
64
- // ../tracking-core/src/resources/conversion-firing.ts
65
- var DEDUP_PREFIX = "_aranova_conv_";
66
- var pendingQueue = [];
67
- function dedupKey(input) {
68
- return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
69
- }
70
- function alreadyFired(input) {
71
- if (!input.transactionId || typeof window === "undefined") return false;
72
- try {
73
- return window.sessionStorage.getItem(dedupKey(input)) !== null;
74
- } catch {
75
- return false;
76
- }
77
- }
78
- function markFired(input) {
79
- if (!input.transactionId || typeof window === "undefined") return;
80
- try {
81
- window.sessionStorage.setItem(dedupKey(input), "1");
82
- } catch {
83
- }
84
- }
85
- function fireOnce(input) {
86
- if (alreadyFired(input)) return;
87
- if (fireGtagConversion(input)) markFired(input);
88
- }
89
- function flushPendingConversions() {
90
- if (getConsentState() !== "granted") return;
91
- while (pendingQueue.length > 0) {
92
- const input = pendingQueue.shift();
93
- if (input) fireOnce(input);
94
- }
95
- }
96
- if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
97
-
98
25
  // ../tracking-core/src/session.ts
99
26
  var SESSION_IDLE_MS = 30 * 60 * 1e3;
100
27
 
@@ -126,9 +53,17 @@ var ctaClickMetadataSchema = z2.object({
126
53
  path: z2.string()
127
54
  }).strict(),
128
55
  section: z2.string().nullable().optional(),
129
- destination_url: z2.string().nullable().optional()
56
+ destination_url: z2.string().nullable().optional(),
57
+ // Set by auto-capture (and available to manual callers): the link target
58
+ // and a short element descriptor (tag#id) for tying clicks to specific UI.
59
+ href: z2.string().nullable().optional(),
60
+ element: z2.string().nullable().optional()
61
+ }).strict();
62
+ var ctaClickConfigSchema = z2.object({
63
+ autoCapture: z2.object({
64
+ selector: z2.string().optional()
65
+ }).strict().optional()
130
66
  }).strict();
131
- var ctaClickConfigSchema = z2.object({}).strict();
132
67
 
133
68
  // ../tracking-core/src/events/sdk-heartbeat.ts
134
69
  import { z as z3 } from "zod";
@@ -204,31 +139,44 @@ var multiPageSessionConfigSchema = z6.object({
204
139
  pageThreshold: z6.number().int().min(2)
205
140
  }).strict();
206
141
 
207
- // ../tracking-core/src/events/phone-click.ts
142
+ // ../tracking-core/src/events/page-exit.ts
208
143
  import { z as z7 } from "zod";
209
- var phoneClickMetadataSchema = z7.object({
210
- phone_number: z7.string(),
144
+ var pageExitMetadataSchema = z7.object({
145
+ dwell_ms: z7.number().int().min(0),
146
+ // null = left without any scroll signal; floor is 0 so a valid 0% is never
147
+ // rejected (a single bad field 422s the whole keepalive beacon batch).
148
+ max_scroll_percent: z7.number().int().min(0).max(100).nullable(),
211
149
  page: z7.object({
212
150
  path: z7.string()
213
- }).strict(),
214
- section: z7.string().nullable().optional()
151
+ }).strict()
215
152
  }).strict();
216
- var phoneClickConfigSchema = z7.object({}).strict();
153
+ var pageExitConfigSchema = z7.object({}).strict();
217
154
 
218
- // ../tracking-core/src/events/scroll-depth.ts
155
+ // ../tracking-core/src/events/phone-click.ts
219
156
  import { z as z8 } from "zod";
220
- var scrollDepthMetadataSchema = z8.object({
221
- depth_percent: z8.number().int().min(1).max(100),
157
+ var phoneClickMetadataSchema = z8.object({
158
+ phone_number: z8.string(),
222
159
  page: z8.object({
223
160
  path: z8.string()
161
+ }).strict(),
162
+ section: z8.string().nullable().optional()
163
+ }).strict();
164
+ var phoneClickConfigSchema = z8.object({}).strict();
165
+
166
+ // ../tracking-core/src/events/scroll-depth.ts
167
+ import { z as z9 } from "zod";
168
+ var scrollDepthMetadataSchema = z9.object({
169
+ depth_percent: z9.number().int().min(1).max(100),
170
+ page: z9.object({
171
+ path: z9.string()
224
172
  }).strict()
225
173
  }).strict();
226
- var scrollDepthConfigSchema = z8.object({
227
- thresholds: z8.array(z8.number().int().min(1).max(100)).min(1)
174
+ var scrollDepthConfigSchema = z9.object({
175
+ thresholds: z9.array(z9.number().int().min(1).max(100)).min(1)
228
176
  }).strict();
229
177
 
230
178
  // ../tracking-core/src/events/specific-page-visit.ts
231
- import { z as z9 } from "zod";
179
+ import { z as z10 } from "zod";
232
180
  var SPECIFIC_PAGE_NAMES = [
233
181
  "contact_page",
234
182
  "about_page",
@@ -239,18 +187,18 @@ var SPECIFIC_PAGE_NAMES = [
239
187
  "faq_page",
240
188
  "testimonials_page"
241
189
  ];
242
- var specificPageNameSchema = z9.enum(SPECIFIC_PAGE_NAMES);
243
- var specificPageVisitMetadataSchema = z9.object({
190
+ var specificPageNameSchema = z10.enum(SPECIFIC_PAGE_NAMES);
191
+ var specificPageVisitMetadataSchema = z10.object({
244
192
  page_name: specificPageNameSchema,
245
- page: z9.object({
246
- path: z9.string()
193
+ page: z10.object({
194
+ path: z10.string()
247
195
  }).strict()
248
196
  }).strict();
249
- var specificPageVisitConfigSchema = z9.object({
250
- pages: z9.array(
251
- z9.object({
197
+ var specificPageVisitConfigSchema = z10.object({
198
+ pages: z10.array(
199
+ z10.object({
252
200
  name: specificPageNameSchema,
253
- pathPattern: z9.custom((value) => value instanceof RegExp, {
201
+ pathPattern: z10.custom((value) => value instanceof RegExp, {
254
202
  message: "pathPattern must be a RegExp"
255
203
  })
256
204
  }).strict()
@@ -258,15 +206,15 @@ var specificPageVisitConfigSchema = z9.object({
258
206
  }).strict();
259
207
 
260
208
  // ../tracking-core/src/events/time-on-site.ts
261
- import { z as z10 } from "zod";
262
- var timeOnSiteMetadataSchema = z10.object({
263
- duration_ms: z10.number().int().nonnegative(),
264
- page: z10.object({
265
- path: z10.string()
209
+ import { z as z11 } from "zod";
210
+ var timeOnSiteMetadataSchema = z11.object({
211
+ duration_ms: z11.number().int().nonnegative(),
212
+ page: z11.object({
213
+ path: z11.string()
266
214
  }).strict()
267
215
  }).strict();
268
- var timeOnSiteConfigSchema = z10.object({
269
- thresholdSeconds: z10.number().int().positive()
216
+ var timeOnSiteConfigSchema = z11.object({
217
+ thresholdSeconds: z11.number().int().positive()
270
218
  }).strict();
271
219
 
272
220
  // ../tracking-core/src/events/registry.ts
@@ -308,6 +256,11 @@ var EVENT_REGISTRY = {
308
256
  metadataSchema: sdkHeartbeatMetadataSchema,
309
257
  configSchema: sdkHeartbeatConfigSchema
310
258
  },
259
+ page_exit: {
260
+ kind: "automatic",
261
+ metadataSchema: pageExitMetadataSchema,
262
+ configSchema: pageExitConfigSchema
263
+ },
311
264
  // --- manual triggers ---
312
265
  form_submit: {
313
266
  kind: "manual",
@@ -329,42 +282,42 @@ var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def])
329
282
  var ALL_MANUAL_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "manual").map(([name]) => name);
330
283
 
331
284
  // ../tracking-core/src/resources/sales/schema.ts
332
- import { z as z11 } from "zod";
285
+ import { z as z12 } from "zod";
333
286
  var SUPPORTED_CURRENCIES = ["USD", "CAD"];
334
287
  var TRACKING_ENVIRONMENTS = ["production", "development"];
335
- var currencySchema = z11.enum(SUPPORTED_CURRENCIES);
336
- var centsSchema = z11.number().int().nonnegative();
337
- var quantitySchema = z11.string().regex(/^\d+(\.\d{1,3})?$/);
338
- var metadataSchema = z11.record(z11.unknown());
339
- var saleItemSchema = z11.object({
340
- external_item_id: z11.string().nullable().optional(),
341
- name: z11.string().nullable().optional(),
342
- category: z11.string().nullable().optional(),
288
+ var currencySchema = z12.enum(SUPPORTED_CURRENCIES);
289
+ var centsSchema = z12.number().int().nonnegative();
290
+ var quantitySchema = z12.string().regex(/^\d+(\.\d{1,3})?$/);
291
+ var metadataSchema = z12.record(z12.unknown());
292
+ var saleItemSchema = z12.object({
293
+ external_item_id: z12.string().nullable().optional(),
294
+ name: z12.string().nullable().optional(),
295
+ category: z12.string().nullable().optional(),
343
296
  quantity: quantitySchema,
344
297
  unit_price_cents: centsSchema,
345
298
  // Non-negativity validated on the wire — same contract as the other cents
346
299
  // fields — and backstopped by the DB CHECK.
347
300
  unit_cost_cents: centsSchema.nullable().optional()
348
301
  }).strict();
349
- var saleServiceSchema = z11.object({
350
- service: z11.string(),
302
+ var saleServiceSchema = z12.object({
303
+ service: z12.string(),
351
304
  amount_cents: centsSchema
352
305
  }).strict();
353
- var customerNameSchema = z11.string().max(200);
354
- var customerPhoneSchema = z11.string().max(64);
355
- var customerEmailSchema = z11.string().max(320).email();
306
+ var customerNameSchema = z12.string().max(200);
307
+ var customerPhoneSchema = z12.string().max(64);
308
+ var customerEmailSchema = z12.string().max(320).email();
356
309
  function refineServiceXor(val, ctx, { requireAmount }) {
357
310
  if (val.services != null) {
358
311
  if (val.service != null) {
359
312
  ctx.addIssue({
360
- code: z11.ZodIssueCode.custom,
313
+ code: z12.ZodIssueCode.custom,
361
314
  message: "pass either `service` or `services`, not both",
362
315
  path: ["services"]
363
316
  });
364
317
  }
365
318
  if (val.services.length === 0) {
366
319
  ctx.addIssue({
367
- code: z11.ZodIssueCode.custom,
320
+ code: z12.ZodIssueCode.custom,
368
321
  message: "`services` must not be empty",
369
322
  path: ["services"]
370
323
  });
@@ -372,7 +325,7 @@ function refineServiceXor(val, ctx, { requireAmount }) {
372
325
  const keys = val.services.map((s) => s.service);
373
326
  if (new Set(keys).size !== keys.length) {
374
327
  ctx.addIssue({
375
- code: z11.ZodIssueCode.custom,
328
+ code: z12.ZodIssueCode.custom,
376
329
  message: "`services` must not list the same service more than once",
377
330
  path: ["services"]
378
331
  });
@@ -381,7 +334,7 @@ function refineServiceXor(val, ctx, { requireAmount }) {
381
334
  const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
382
335
  if (val.amount_total_cents !== sum) {
383
336
  ctx.addIssue({
384
- code: z11.ZodIssueCode.custom,
337
+ code: z12.ZodIssueCode.custom,
385
338
  message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
386
339
  path: ["amount_total_cents"]
387
340
  });
@@ -389,37 +342,37 @@ function refineServiceXor(val, ctx, { requireAmount }) {
389
342
  }
390
343
  } else if (requireAmount && val.amount_total_cents == null) {
391
344
  ctx.addIssue({
392
- code: z11.ZodIssueCode.custom,
345
+ code: z12.ZodIssueCode.custom,
393
346
  message: "amount_total_cents is required unless `services` is provided",
394
347
  path: ["amount_total_cents"]
395
348
  });
396
349
  }
397
350
  }
398
- var saleCreateSchema = z11.object({
399
- external_id: z11.string().nullable().optional(),
400
- description: z11.string().nullable().optional(),
401
- service: z11.string().nullable().optional(),
402
- services: z11.array(saleServiceSchema).nullable().optional(),
351
+ var saleCreateSchema = z12.object({
352
+ external_id: z12.string().nullable().optional(),
353
+ description: z12.string().nullable().optional(),
354
+ service: z12.string().nullable().optional(),
355
+ services: z12.array(saleServiceSchema).nullable().optional(),
403
356
  currency: currencySchema,
404
357
  // Optional only because the plural `services` form derives it from the sum
405
358
  // (see refineServiceXor); the singular/serviceless path still requires it.
406
359
  amount_total_cents: centsSchema.nullable().optional(),
407
- occurred_at: z11.string().datetime(),
408
- environment: z11.enum(TRACKING_ENVIRONMENTS).default("production"),
409
- items: z11.array(saleItemSchema).default([]),
360
+ occurred_at: z12.string().datetime(),
361
+ environment: z12.enum(TRACKING_ENVIRONMENTS).default("production"),
362
+ items: z12.array(saleItemSchema).default([]),
410
363
  metadata: metadataSchema.nullable().optional(),
411
364
  customer_name: customerNameSchema.nullable().optional(),
412
365
  customer_phone: customerPhoneSchema.nullable().optional(),
413
366
  customer_email: customerEmailSchema.nullable().optional()
414
367
  }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
415
- var saleUpdateSchema = z11.object({
416
- description: z11.string().nullable().optional(),
417
- service: z11.string().nullable().optional(),
418
- services: z11.array(saleServiceSchema).nullable().optional(),
368
+ var saleUpdateSchema = z12.object({
369
+ description: z12.string().nullable().optional(),
370
+ service: z12.string().nullable().optional(),
371
+ services: z12.array(saleServiceSchema).nullable().optional(),
419
372
  currency: currencySchema.optional(),
420
373
  amount_total_cents: centsSchema.optional(),
421
- occurred_at: z11.string().datetime().optional(),
422
- items: z11.array(saleItemSchema).optional(),
374
+ occurred_at: z12.string().datetime().optional(),
375
+ items: z12.array(saleItemSchema).optional(),
423
376
  metadata: metadataSchema.nullable().optional(),
424
377
  customer_name: customerNameSchema.nullable().optional(),
425
378
  customer_phone: customerPhoneSchema.nullable().optional(),