@aranova/tracking-next 1.1.0 → 1.2.1

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/calendar.mjs CHANGED
@@ -1,3 +1,132 @@
1
+ // ../tracking-core/src/tracking.ts
2
+ var TRACKING_PARAM_KEYS = [
3
+ "gclid",
4
+ // Google's iOS/Safari replacement click IDs — issued when privacy features
5
+ // withhold gclid (wbraid: web-to-web, gbraid: app-to-web). First-class
6
+ // citizens: captured, persisted, and attributed exactly like gclid.
7
+ "wbraid",
8
+ "gbraid",
9
+ // Yelp Ads click id (40 hex chars), appended to ad-click URLs.
10
+ "ylpcid",
11
+ "fbclid",
12
+ "utm_source",
13
+ "utm_medium",
14
+ "utm_campaign",
15
+ "utm_term",
16
+ "utm_content"
17
+ ];
18
+ function createEmptyTrackingParams() {
19
+ return {
20
+ gclid: null,
21
+ wbraid: null,
22
+ gbraid: null,
23
+ ylpcid: null,
24
+ fbclid: null,
25
+ utm_source: null,
26
+ utm_medium: null,
27
+ utm_campaign: null,
28
+ utm_term: null,
29
+ utm_content: null
30
+ };
31
+ }
32
+ function normalizeTrackingCookieValue(value) {
33
+ return typeof value === "string" && value.length > 0 ? value : null;
34
+ }
35
+ function getTrackingParamsFromCookieReader(readCookie) {
36
+ return TRACKING_PARAM_KEYS.reduce((params, key) => {
37
+ params[key] = normalizeTrackingCookieValue(readCookie(key));
38
+ return params;
39
+ }, createEmptyTrackingParams());
40
+ }
41
+ var FALLBACK_STORAGE_PREFIX = "_aranova_track_";
42
+ function fallbackKey(name) {
43
+ return `${FALLBACK_STORAGE_PREFIX}${name}`;
44
+ }
45
+ function readCookieValue(name) {
46
+ if (typeof document !== "undefined") {
47
+ const cookies = document.cookie ? document.cookie.split("; ") : [];
48
+ const match = cookies.find((cookie) => cookie.startsWith(`${name}=`));
49
+ if (match) {
50
+ const [, rawValue = ""] = match.split("=");
51
+ return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
52
+ }
53
+ }
54
+ if (typeof window !== "undefined") {
55
+ try {
56
+ const stored = window.localStorage.getItem(fallbackKey(name));
57
+ if (stored) return normalizeTrackingCookieValue(decodeURIComponent(stored));
58
+ } catch {
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ function getCookieValueFromDocument(key) {
64
+ return readCookieValue(key);
65
+ }
66
+
67
+ // ../tracking-core/src/session.ts
68
+ var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
69
+ var SESSION_STORAGE_KEY = "aranova_tracking_session";
70
+ var SESSION_IDLE_MS = 30 * 60 * 1e3;
71
+ function readLocalStorage(key) {
72
+ try {
73
+ return window.localStorage.getItem(key);
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+ function peekVisitorId() {
79
+ if (typeof window === "undefined") return null;
80
+ const existing = readLocalStorage(VISITOR_STORAGE_KEY);
81
+ return existing && existing.length > 0 ? existing : null;
82
+ }
83
+ function peekSessionId(now = Date.now()) {
84
+ if (typeof window === "undefined") return null;
85
+ const raw = readLocalStorage(SESSION_STORAGE_KEY);
86
+ if (!raw) return null;
87
+ try {
88
+ const parsed = JSON.parse(raw);
89
+ if (typeof parsed.id !== "string" || typeof parsed.last_event_at !== "number") return null;
90
+ return now - parsed.last_event_at <= SESSION_IDLE_MS ? parsed.id : null;
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+
96
+ // ../tracking-core/src/resources/calendar/attribution.ts
97
+ var LIMITS = {
98
+ session_id: 64,
99
+ visitor_id: 64,
100
+ gclid: 256,
101
+ fbclid: 256,
102
+ utm_source: 128,
103
+ utm_medium: 128,
104
+ utm_campaign: 128,
105
+ utm_term: 128,
106
+ utm_content: 128
107
+ };
108
+ function getBookingAttribution() {
109
+ if (typeof window === "undefined") return {};
110
+ const params = getTrackingParamsFromCookieReader(getCookieValueFromDocument);
111
+ const values = {
112
+ session_id: peekSessionId(),
113
+ visitor_id: peekVisitorId(),
114
+ gclid: params.gclid,
115
+ fbclid: params.fbclid,
116
+ utm_source: params.utm_source,
117
+ utm_medium: params.utm_medium,
118
+ utm_campaign: params.utm_campaign,
119
+ utm_term: params.utm_term,
120
+ utm_content: params.utm_content
121
+ };
122
+ const attribution = {};
123
+ for (const key of Object.keys(LIMITS)) {
124
+ const value = values[key];
125
+ if (value) attribution[key] = value.slice(0, LIMITS[key]);
126
+ }
127
+ return attribution;
128
+ }
129
+
1
130
  // ../tracking-core/src/capabilities.ts
2
131
  var registered = /* @__PURE__ */ new Set();
3
132
  function registerCapability(capability) {
@@ -211,22 +340,27 @@ var zBookingRescheduleSchema = z.strictObject({
211
340
  time_zone: z.string().check(z.minLength(1), z.maxLength(64), z.regex(/^[A-Za-z0-9_+\-\/]+$/))
212
341
  });
213
342
  var zBookingResponse = z.strictObject({
343
+ all_day: z.boolean(),
214
344
  appointment_type: z.nullable(z.string()),
215
345
  calendar_key: z.string(),
346
+ created_at: z.iso.datetime({ offset: true }),
216
347
  customer: zBookingCustomerOutput,
217
348
  end_at: z.iso.datetime({ offset: true }),
349
+ google_event_id: z.nullable(z.string()),
218
350
  google_html_link: z.nullable(z.string()),
219
- google_sync_state: z.string(),
351
+ google_sync_state: z.enum(["queued", "synced", "uncertain", "failed", "drifted"]),
352
+ ical_uid: z.nullable(z.string()),
220
353
  id: z.string(),
221
354
  manage_token: z.nullable(z.string()),
222
355
  meet_url: z.nullable(z.string()),
356
+ organizer_email: z.nullable(z.string()),
223
357
  start_at: z.iso.datetime({ offset: true }),
224
- status: z.string(),
358
+ status: z.enum(["pending", "confirmed", "cancelled", "no_show"]),
225
359
  time_zone: z.string(),
226
360
  title: z.string()
227
361
  });
228
362
  var zBookingSource = z.enum(["website", "phone", "walk_in", "import", "operator"]);
229
- var zBookingMetadata = z.strictObject({
363
+ var zBookingMetadataInput = z.strictObject({
230
364
  custom: z.nullish(
231
365
  z.record(z.string(), z.nullable(z.union([z.string(), z.int(), z.number(), z.boolean()])))
232
366
  ),
@@ -246,6 +380,42 @@ var zBookingMetadata = z.strictObject({
246
380
  utm_term: z.nullish(z.string().check(z.maxLength(128))),
247
381
  visitor_id: z.nullish(z.string().check(z.maxLength(64)))
248
382
  });
383
+ var zBusySource = z.enum(["google", "booking"]);
384
+ var zBusyInterval = z.strictObject({
385
+ end_at: z.iso.datetime({ offset: true }),
386
+ source: zBusySource,
387
+ start_at: z.iso.datetime({ offset: true })
388
+ });
389
+ var zBusyWindow = z.strictObject({
390
+ since: z.iso.datetime({ offset: true }),
391
+ until: z.iso.datetime({ offset: true })
392
+ });
393
+ var zBusyResponse = z.strictObject({
394
+ busy: z.array(zBusyInterval),
395
+ calendar_key: z.string(),
396
+ generated_at: z.iso.datetime({ offset: true }),
397
+ time_zone: z.string(),
398
+ window: zBusyWindow
399
+ });
400
+ var zCalendarSummary = z.strictObject({
401
+ allow_overlaps: z.boolean(),
402
+ calendar_key: z.string(),
403
+ connected_at: z.nullable(z.iso.datetime({ offset: true })),
404
+ google_account_email: z.nullable(z.string()),
405
+ granted_scopes: z.nullable(z.array(z.string())),
406
+ is_sandbox: z.boolean(),
407
+ label: z.string(),
408
+ sandbox_key: z.nullable(z.string()),
409
+ status: z.enum([
410
+ "pending_invite",
411
+ "awaiting_calendar_selection",
412
+ "connected",
413
+ "needs_reconnect",
414
+ "revoked",
415
+ "disabled"
416
+ ]),
417
+ time_zone: z.string()
418
+ });
249
419
  var zCustomLocation = z.strictObject({
250
420
  kind: z.literal("custom"),
251
421
  text: z.string().check(z.maxLength(1024))
@@ -265,9 +435,23 @@ var zErrorCode = z.enum([
265
435
  "bad_request",
266
436
  "not_found",
267
437
  "conflict",
438
+ "gone",
268
439
  "incompatible_payload",
269
440
  "repeat_confirmation_required",
270
441
  "idempotency_conflict",
442
+ "slot_unavailable",
443
+ "calendar_not_connected",
444
+ "calendar_disconnected",
445
+ "booking_not_found",
446
+ "booking_not_cancellable",
447
+ "booking_not_reschedulable",
448
+ "manage_token_invalid",
449
+ "google_error",
450
+ "calendar_not_owned",
451
+ "calendar_is_sandbox",
452
+ "sandbox_exists",
453
+ "sandbox_key_too_long",
454
+ "sandbox_not_found",
271
455
  "validation_error",
272
456
  "unknown_service",
273
457
  "invalid_sale_properties",
@@ -302,15 +486,16 @@ var zBookingCreateSchema = z.strictObject({
302
486
  buffer_before_minutes: z._default(z.optional(z.int().check(z.gte(0), z.lte(1440))), 0),
303
487
  calendar_key: z.string().check(z.minLength(1), z.maxLength(64)),
304
488
  customer: zBookingCustomerInput,
489
+ date: z.nullish(z.iso.date()),
305
490
  description: z.nullish(z.string().check(z.maxLength(8e3))),
306
491
  duration_minutes: z.nullish(z.int().check(z.gt(0), z.lte(1440))),
307
492
  end_at: z.nullish(z.iso.datetime({ offset: true })),
308
493
  idempotency_key: z.nullish(z.string().check(z.maxLength(128))),
309
494
  location: z.nullish(z.union([zMeetLocation, zPhysicalLocation, zPhoneLocation, zCustomLocation])),
310
- metadata: z.nullish(zBookingMetadata),
495
+ metadata: z.nullish(zBookingMetadataInput),
311
496
  reminders: z.nullish(zBookingReminders),
312
497
  send_invites: z._default(z.optional(z.boolean()), true),
313
- start_at: z.iso.datetime({ offset: true }),
498
+ start_at: z.nullish(z.iso.datetime({ offset: true })),
314
499
  time_zone: z.string().check(z.minLength(1), z.maxLength(64), z.regex(/^[A-Za-z0-9_+\-\/]+$/)),
315
500
  title: z.nullish(z.string().check(z.maxLength(300)))
316
501
  });
@@ -344,22 +529,17 @@ var MAX_REMINDER_OVERRIDES = 5;
344
529
  var MAX_REMINDER_MINUTES = 40320;
345
530
  var MAX_BOOKING_MINUTES = 1440;
346
531
  var BOOKING_SOURCES = ["website", "phone", "walk_in", "import", "operator"];
347
- var BOOKING_STATUSES = ["pending", "confirmed", "cancelled", "no_show"];
348
- var GOOGLE_SYNC_STATES = ["queued", "synced", "uncertain", "failed", "drifted"];
349
- var CALENDAR_SYNC_STATUSES = [
350
- "pending_invite",
351
- "awaiting_calendar_selection",
352
- "connected",
353
- "needs_reconnect",
354
- "revoked",
355
- "disabled"
356
- ];
532
+ var BOOKING_STATUSES = zBookingResponse.shape.status.options;
533
+ var GOOGLE_SYNC_STATES = zBookingResponse.shape.google_sync_state.options;
534
+ var CALENDAR_SYNC_STATUSES = zCalendarSummary.shape.status.options;
357
535
  var CALENDAR_ERROR_CODES = [
358
536
  "slot_unavailable",
359
537
  "calendar_not_connected",
360
538
  "calendar_disconnected",
361
539
  "booking_not_found",
362
- "outside_booking_window",
540
+ "booking_not_cancellable",
541
+ "booking_not_reschedulable",
542
+ "manage_token_invalid",
363
543
  "rate_limited",
364
544
  "google_error"
365
545
  ];
@@ -380,7 +560,7 @@ var ianaTz = z2.string().check(
380
560
  var bookingAttendeeSchema = zBookingAttendee;
381
561
  var bookingReminderSchema = zBookingReminder;
382
562
  var bookingCustomerSchema = zBookingCustomerInput;
383
- var bookingMetadataSchema = z2.extend(zBookingMetadata, {
563
+ var bookingMetadataSchema = z2.extend(zBookingMetadataInput, {
384
564
  custom: z2.nullish(
385
565
  z2.record(z2.string(), z2.union([z2.string(), z2.int(), z2.number(), z2.boolean(), z2.null()]))
386
566
  )
@@ -409,6 +589,24 @@ function refineEndXor(value, ctx) {
409
589
  addIssue(ctx, ["end_at"], "end_at must be after start_at");
410
590
  }
411
591
  }
592
+ function refineStartXor(value, ctx) {
593
+ const hasStart = value.start_at !== void 0 && value.start_at !== null;
594
+ const hasDate = value.date !== void 0 && value.date !== null;
595
+ if (hasStart === hasDate) {
596
+ addIssue(ctx, ["start_at"], "provide exactly one of start_at or date");
597
+ return;
598
+ }
599
+ if (hasStart) {
600
+ refineEndXor(value, ctx);
601
+ return;
602
+ }
603
+ if (value.end_at != null || value.duration_minutes != null) {
604
+ addIssue(ctx, ["date"], "an all-day booking (date) takes no end_at or duration_minutes");
605
+ }
606
+ if (value.buffer_before_minutes || value.buffer_after_minutes) {
607
+ addIssue(ctx, ["date"], "an all-day booking (date) takes no buffers");
608
+ }
609
+ }
412
610
  var bookingRemindersSchema = z2.extend(zBookingReminders, {
413
611
  overrides: z2._default(
414
612
  z2.array(bookingReminderSchema).check(z2.maxLength(MAX_REMINDER_OVERRIDES)),
@@ -427,7 +625,7 @@ var bookingCreateSchema = z2.extend(zBookingCreateSchema, {
427
625
  // our compositions into its own output.
428
626
  reminders: z2.nullish(bookingRemindersSchema),
429
627
  metadata: z2.nullish(bookingMetadataSchema)
430
- }).check((ctx) => refineEndXor(ctx.value, ctx));
628
+ }).check((ctx) => refineStartXor(ctx.value, ctx));
431
629
  var bookingRescheduleSchema = z2.extend(zBookingRescheduleSchema, { time_zone: ianaTz }).check((ctx) => refineEndXor(ctx.value, ctx));
432
630
  var bookingCancelSchema = zBookingCancelSchema;
433
631
 
@@ -544,6 +742,7 @@ export {
544
742
  endOfDayInTz,
545
743
  formatDateInTz,
546
744
  formatSlotRange,
745
+ getBookingAttribution,
547
746
  groupSlotsByDay,
548
747
  instantFromWallClock,
549
748
  isCalendarError,