@aranova/tracking-next 1.1.0 → 1.2.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.
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,40 @@ 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
+ label: z.string(),
407
+ status: z.enum([
408
+ "pending_invite",
409
+ "awaiting_calendar_selection",
410
+ "connected",
411
+ "needs_reconnect",
412
+ "revoked",
413
+ "disabled"
414
+ ]),
415
+ time_zone: z.string()
416
+ });
249
417
  var zCustomLocation = z.strictObject({
250
418
  kind: z.literal("custom"),
251
419
  text: z.string().check(z.maxLength(1024))
@@ -265,9 +433,19 @@ var zErrorCode = z.enum([
265
433
  "bad_request",
266
434
  "not_found",
267
435
  "conflict",
436
+ "gone",
268
437
  "incompatible_payload",
269
438
  "repeat_confirmation_required",
270
439
  "idempotency_conflict",
440
+ "slot_unavailable",
441
+ "calendar_not_connected",
442
+ "calendar_disconnected",
443
+ "booking_not_found",
444
+ "booking_not_cancellable",
445
+ "booking_not_reschedulable",
446
+ "manage_token_invalid",
447
+ "google_error",
448
+ "calendar_not_owned",
271
449
  "validation_error",
272
450
  "unknown_service",
273
451
  "invalid_sale_properties",
@@ -302,15 +480,16 @@ var zBookingCreateSchema = z.strictObject({
302
480
  buffer_before_minutes: z._default(z.optional(z.int().check(z.gte(0), z.lte(1440))), 0),
303
481
  calendar_key: z.string().check(z.minLength(1), z.maxLength(64)),
304
482
  customer: zBookingCustomerInput,
483
+ date: z.nullish(z.iso.date()),
305
484
  description: z.nullish(z.string().check(z.maxLength(8e3))),
306
485
  duration_minutes: z.nullish(z.int().check(z.gt(0), z.lte(1440))),
307
486
  end_at: z.nullish(z.iso.datetime({ offset: true })),
308
487
  idempotency_key: z.nullish(z.string().check(z.maxLength(128))),
309
488
  location: z.nullish(z.union([zMeetLocation, zPhysicalLocation, zPhoneLocation, zCustomLocation])),
310
- metadata: z.nullish(zBookingMetadata),
489
+ metadata: z.nullish(zBookingMetadataInput),
311
490
  reminders: z.nullish(zBookingReminders),
312
491
  send_invites: z._default(z.optional(z.boolean()), true),
313
- start_at: z.iso.datetime({ offset: true }),
492
+ start_at: z.nullish(z.iso.datetime({ offset: true })),
314
493
  time_zone: z.string().check(z.minLength(1), z.maxLength(64), z.regex(/^[A-Za-z0-9_+\-\/]+$/)),
315
494
  title: z.nullish(z.string().check(z.maxLength(300)))
316
495
  });
@@ -344,22 +523,17 @@ var MAX_REMINDER_OVERRIDES = 5;
344
523
  var MAX_REMINDER_MINUTES = 40320;
345
524
  var MAX_BOOKING_MINUTES = 1440;
346
525
  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
- ];
526
+ var BOOKING_STATUSES = zBookingResponse.shape.status.options;
527
+ var GOOGLE_SYNC_STATES = zBookingResponse.shape.google_sync_state.options;
528
+ var CALENDAR_SYNC_STATUSES = zCalendarSummary.shape.status.options;
357
529
  var CALENDAR_ERROR_CODES = [
358
530
  "slot_unavailable",
359
531
  "calendar_not_connected",
360
532
  "calendar_disconnected",
361
533
  "booking_not_found",
362
- "outside_booking_window",
534
+ "booking_not_cancellable",
535
+ "booking_not_reschedulable",
536
+ "manage_token_invalid",
363
537
  "rate_limited",
364
538
  "google_error"
365
539
  ];
@@ -380,7 +554,7 @@ var ianaTz = z2.string().check(
380
554
  var bookingAttendeeSchema = zBookingAttendee;
381
555
  var bookingReminderSchema = zBookingReminder;
382
556
  var bookingCustomerSchema = zBookingCustomerInput;
383
- var bookingMetadataSchema = z2.extend(zBookingMetadata, {
557
+ var bookingMetadataSchema = z2.extend(zBookingMetadataInput, {
384
558
  custom: z2.nullish(
385
559
  z2.record(z2.string(), z2.union([z2.string(), z2.int(), z2.number(), z2.boolean(), z2.null()]))
386
560
  )
@@ -409,6 +583,24 @@ function refineEndXor(value, ctx) {
409
583
  addIssue(ctx, ["end_at"], "end_at must be after start_at");
410
584
  }
411
585
  }
586
+ function refineStartXor(value, ctx) {
587
+ const hasStart = value.start_at !== void 0 && value.start_at !== null;
588
+ const hasDate = value.date !== void 0 && value.date !== null;
589
+ if (hasStart === hasDate) {
590
+ addIssue(ctx, ["start_at"], "provide exactly one of start_at or date");
591
+ return;
592
+ }
593
+ if (hasStart) {
594
+ refineEndXor(value, ctx);
595
+ return;
596
+ }
597
+ if (value.end_at != null || value.duration_minutes != null) {
598
+ addIssue(ctx, ["date"], "an all-day booking (date) takes no end_at or duration_minutes");
599
+ }
600
+ if (value.buffer_before_minutes || value.buffer_after_minutes) {
601
+ addIssue(ctx, ["date"], "an all-day booking (date) takes no buffers");
602
+ }
603
+ }
412
604
  var bookingRemindersSchema = z2.extend(zBookingReminders, {
413
605
  overrides: z2._default(
414
606
  z2.array(bookingReminderSchema).check(z2.maxLength(MAX_REMINDER_OVERRIDES)),
@@ -427,7 +619,7 @@ var bookingCreateSchema = z2.extend(zBookingCreateSchema, {
427
619
  // our compositions into its own output.
428
620
  reminders: z2.nullish(bookingRemindersSchema),
429
621
  metadata: z2.nullish(bookingMetadataSchema)
430
- }).check((ctx) => refineEndXor(ctx.value, ctx));
622
+ }).check((ctx) => refineStartXor(ctx.value, ctx));
431
623
  var bookingRescheduleSchema = z2.extend(zBookingRescheduleSchema, { time_zone: ianaTz }).check((ctx) => refineEndXor(ctx.value, ctx));
432
624
  var bookingCancelSchema = zBookingCancelSchema;
433
625
 
@@ -544,6 +736,7 @@ export {
544
736
  endOfDayInTz,
545
737
  formatDateInTz,
546
738
  formatSlotRange,
739
+ getBookingAttribution,
547
740
  groupSlotsByDay,
548
741
  instantFromWallClock,
549
742
  isCalendarError,