@outlit/core 2.0.0 → 3.0.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/index.d.ts CHANGED
@@ -1,12 +1,187 @@
1
- type EventType = "pageview" | "form" | "identify" | "custom" | "calendar" | "engagement";
2
- type CalendarProvider = "cal.com" | "calendly" | "unknown";
3
- type SourceType = "client" | "server" | "integration";
1
+ type GeneratedIngestPayload = {
2
+ visitorId?: string;
3
+ fingerprint?: string;
4
+ source?: "client" | "server" | "integration";
5
+ events: Array<{
6
+ uuid?: string;
7
+ type: "pageview";
8
+ timestamp: number;
9
+ url: string;
10
+ path: string;
11
+ referrer?: string;
12
+ utm?: {
13
+ source?: string;
14
+ medium?: string;
15
+ campaign?: string;
16
+ term?: string;
17
+ content?: string;
18
+ ref?: string;
19
+ };
20
+ customerId?: string;
21
+ customerTraits?: Record<string, string | number | boolean | null>;
22
+ title?: string;
23
+ } | {
24
+ uuid?: string;
25
+ type: "form";
26
+ timestamp: number;
27
+ url: string;
28
+ path: string;
29
+ referrer?: string;
30
+ utm?: {
31
+ source?: string;
32
+ medium?: string;
33
+ campaign?: string;
34
+ term?: string;
35
+ content?: string;
36
+ ref?: string;
37
+ };
38
+ customerId?: string;
39
+ customerTraits?: Record<string, string | number | boolean | null>;
40
+ formId?: string;
41
+ formFields?: Record<string, string>;
42
+ } | {
43
+ uuid?: string;
44
+ type: "identify";
45
+ timestamp: number;
46
+ url: string;
47
+ path: string;
48
+ referrer?: string;
49
+ utm?: {
50
+ source?: string;
51
+ medium?: string;
52
+ campaign?: string;
53
+ term?: string;
54
+ content?: string;
55
+ ref?: string;
56
+ };
57
+ email?: string;
58
+ userId?: string;
59
+ fingerprint?: string;
60
+ customerId?: string;
61
+ customerTraits?: Record<string, string | number | boolean | null>;
62
+ traits?: Record<string, string | number | boolean | null>;
63
+ } | {
64
+ uuid?: string;
65
+ type: "custom";
66
+ timestamp: number;
67
+ url: string;
68
+ path: string;
69
+ referrer?: string;
70
+ utm?: {
71
+ source?: string;
72
+ medium?: string;
73
+ campaign?: string;
74
+ term?: string;
75
+ content?: string;
76
+ ref?: string;
77
+ };
78
+ customerId?: string;
79
+ customerTraits?: Record<string, string | number | boolean | null>;
80
+ email?: string;
81
+ userId?: string;
82
+ fingerprint?: string;
83
+ eventName: string;
84
+ properties?: Record<string, unknown>;
85
+ } | {
86
+ uuid?: string;
87
+ type: "calendar";
88
+ timestamp: number;
89
+ url: string;
90
+ path: string;
91
+ referrer?: string;
92
+ utm?: {
93
+ source?: string;
94
+ medium?: string;
95
+ campaign?: string;
96
+ term?: string;
97
+ content?: string;
98
+ ref?: string;
99
+ };
100
+ customerId?: string;
101
+ customerTraits?: Record<string, string | number | boolean | null>;
102
+ provider: "cal.com" | "calendly" | "unknown";
103
+ eventType?: string;
104
+ startTime?: string;
105
+ endTime?: string;
106
+ duration?: number;
107
+ isRecurring?: boolean;
108
+ inviteeEmail?: string;
109
+ inviteeName?: string;
110
+ } | {
111
+ uuid?: string;
112
+ type: "engagement";
113
+ timestamp: number;
114
+ url: string;
115
+ path: string;
116
+ referrer?: string;
117
+ utm?: {
118
+ source?: string;
119
+ medium?: string;
120
+ campaign?: string;
121
+ term?: string;
122
+ content?: string;
123
+ ref?: string;
124
+ };
125
+ customerId?: string;
126
+ customerTraits?: Record<string, string | number | boolean | null>;
127
+ activeTimeMs: number;
128
+ totalTimeMs: number;
129
+ sessionId: string;
130
+ }>;
131
+ sessionId?: string;
132
+ userIdentity?: {
133
+ email?: string;
134
+ userId?: string;
135
+ fingerprint?: string;
136
+ traits?: Record<string, string | number | boolean | null>;
137
+ };
138
+ customerIdentity?: {
139
+ customerId?: string;
140
+ customerTraits?: Record<string, string | number | boolean | null>;
141
+ };
142
+ };
143
+ type GeneratedIngestResponse = {
144
+ success: boolean;
145
+ processed: number;
146
+ errors?: Array<{
147
+ index: number;
148
+ message: string;
149
+ }>;
150
+ };
151
+
152
+ type IngestPayload = GeneratedIngestPayload;
153
+ type IngestResponse = GeneratedIngestResponse;
154
+ type TrackerEvent = IngestPayload["events"][number];
155
+ type EventType = TrackerEvent["type"];
156
+ type SourceType = NonNullable<IngestPayload["source"]>;
157
+ type PageviewEvent = Extract<TrackerEvent, {
158
+ type: "pageview";
159
+ }>;
160
+ type FormEvent = Extract<TrackerEvent, {
161
+ type: "form";
162
+ }>;
163
+ type IdentifyEvent = Extract<TrackerEvent, {
164
+ type: "identify";
165
+ }>;
166
+ type CustomEvent = Extract<TrackerEvent, {
167
+ type: "custom";
168
+ }>;
169
+ type CalendarEvent = Extract<TrackerEvent, {
170
+ type: "calendar";
171
+ }>;
172
+ type EngagementEvent = Extract<TrackerEvent, {
173
+ type: "engagement";
174
+ }>;
175
+ type CalendarProvider = CalendarEvent["provider"];
176
+ type PayloadUserIdentity = NonNullable<IngestPayload["userIdentity"]>;
177
+ type PayloadCustomerIdentity = NonNullable<IngestPayload["customerIdentity"]>;
4
178
  interface UtmParams {
5
179
  source?: string;
6
180
  medium?: string;
7
181
  campaign?: string;
8
182
  term?: string;
9
183
  content?: string;
184
+ ref?: string;
10
185
  }
11
186
  interface TrackerConfig {
12
187
  publicKey: string;
@@ -61,145 +236,30 @@ interface IdentifyTraits {
61
236
  /** User-level traits */
62
237
  [key: string]: string | number | boolean | null | undefined;
63
238
  }
64
- interface ServerTrackOptions extends ServerIdentity, CustomerAttribution {
65
- eventName: string;
66
- properties?: Record<string, string | number | boolean | null>;
67
- timestamp?: number;
68
- }
69
- interface ServerIdentifyOptions extends ServerIdentity, CustomerAttribution {
70
- traits?: IdentifyTraits;
71
- customerTraits?: CustomerTraits;
72
- }
73
- interface BaseEvent {
74
- uuid?: string;
75
- type: EventType;
76
- timestamp: number;
77
- url: string;
78
- path: string;
79
- referrer?: string;
80
- utm?: UtmParams;
81
- }
82
- interface PageviewEvent extends BaseEvent {
83
- type: "pageview";
84
- title?: string;
85
- }
86
- interface FormEvent extends BaseEvent {
87
- type: "form";
88
- formId?: string;
89
- formFields?: Record<string, string>;
90
- }
91
- interface IdentifyEvent extends BaseEvent {
92
- type: "identify";
93
- email?: string;
94
- userId?: string;
95
- fingerprint?: string;
96
- customerId?: string;
97
- customerTraits?: CustomerTraits;
98
- traits?: IdentifyTraits;
99
- }
100
- interface CustomEvent extends BaseEvent {
101
- type: "custom";
102
- eventName: string;
103
- email?: string;
104
- userId?: string;
105
- fingerprint?: string;
106
- customerId?: string;
107
- properties?: Record<string, string | number | boolean | null>;
108
- }
109
- interface CalendarEvent extends BaseEvent {
110
- type: "calendar";
111
- provider: CalendarProvider;
112
- eventType?: string;
113
- startTime?: string;
114
- endTime?: string;
115
- duration?: number;
116
- isRecurring?: boolean;
117
- /** Available when identity is passed via webhooks or manual integration */
118
- inviteeEmail?: string;
119
- inviteeName?: string;
120
- }
121
- interface EngagementEvent extends BaseEvent {
122
- type: "engagement";
123
- /** Time in milliseconds the user was actively engaged (visible tab + user interactions) */
124
- activeTimeMs: number;
125
- /** Total wall-clock time in milliseconds on the page */
126
- totalTimeMs: number;
127
- /** Session ID for grouping engagement events. Resets after 30 min of inactivity or tab close. */
128
- sessionId: string;
129
- }
130
- type TrackerEvent = PageviewEvent | FormEvent | IdentifyEvent | CustomEvent | CalendarEvent | EngagementEvent;
131
239
  /**
132
- * User identity for payload-level resolution.
133
- * Used by browser SDK when user is logged in (via setUser).
134
- * Customer attribution is carried separately in `customerIdentity`.
240
+ * Input accepted by the payload builder. Deprecated customer fields are lifted
241
+ * into the wire-level `customerIdentity` object and are never sent in `userIdentity`.
135
242
  */
136
- interface PayloadUserIdentity {
137
- email?: string;
138
- /** Your system-owned user/contact ID. */
139
- userId?: string;
243
+ type PayloadUserIdentityInput = Omit<PayloadUserIdentity, "traits"> & {
140
244
  /** User/contact traits. */
141
245
  traits?: IdentifyTraits;
142
- /**
143
- * @deprecated Use payload-level `customerIdentity.customerId` instead.
144
- * Kept for one compatibility window while callers migrate.
145
- */
246
+ /** @deprecated Pass `customerIdentity.customerId` to the payload builder instead. */
146
247
  customerId?: string;
147
- /**
148
- * @deprecated Use payload-level `customerIdentity.customerTraits` instead.
149
- * Kept for one compatibility window while callers migrate.
150
- */
248
+ /** @deprecated Pass `customerIdentity.customerTraits` to the payload builder instead. */
151
249
  customerTraits?: CustomerTraits;
152
- }
153
- /**
154
- * Customer identity for payload-level attribution.
155
- * Used by browser SDK to attach account/workspace context to a batch.
156
- * `customerId`-only attribution is valid and remains provisional until a later
157
- * identify(email, customerId) call links that external account/workspace to a resolved customer.
158
- */
159
- interface PayloadCustomerIdentity extends CustomerAttribution {
250
+ };
251
+ interface PayloadCustomerIdentityInput extends CustomerAttribution {
160
252
  /** Customer/account traits. */
161
253
  customerTraits?: CustomerTraits;
162
254
  }
163
- interface IngestPayload {
164
- visitorId?: string;
165
- source: SourceType;
166
- events: TrackerEvent[];
167
- /**
168
- * Device identifier for anonymous tracking.
169
- * Events with fingerprint can be linked to users later via identify.
170
- * Only present for server-side events.
171
- */
172
- fingerprint?: string;
173
- /**
174
- * Session ID for grouping all events in this batch.
175
- * Only present for browser (client) source events.
176
- * Used to correlate pageviews, forms, custom events, and engagement
177
- * within the same browsing session.
178
- */
179
- sessionId?: string;
180
- /**
181
- * User identity for this batch of events.
182
- * When present, the server can resolve directly to CustomerContact
183
- * instead of relying on anonymous visitor flow.
184
- *
185
- * This is set by the browser SDK when setUser() has been called,
186
- * allowing immediate identity resolution for SPA/React apps.
187
- */
188
- userIdentity?: PayloadUserIdentity;
189
- /**
190
- * Customer/account identity for this batch of events.
191
- * Used to attribute browser batches to a customer/workspace even when
192
- * the customer fields are not present on every event.
193
- */
194
- customerIdentity?: PayloadCustomerIdentity;
255
+ interface ServerTrackOptions extends ServerIdentity, CustomerAttribution {
256
+ eventName: string;
257
+ properties?: Record<string, string | number | boolean | null>;
258
+ timestamp?: number;
195
259
  }
196
- interface IngestResponse {
197
- success: boolean;
198
- processed: number;
199
- errors?: Array<{
200
- index: number;
201
- message: string;
202
- }>;
260
+ interface ServerIdentifyOptions extends ServerIdentity, CustomerAttribution {
261
+ traits?: IdentifyTraits;
262
+ customerTraits?: CustomerTraits;
203
263
  }
204
264
  declare const DEFAULT_API_HOST = "https://app.outlit.ai";
205
265
 
@@ -280,16 +340,20 @@ declare function buildEngagementEvent(params: BaseEventParams & {
280
340
  * batches are valid and remain provisional until a later identify(email, customerId) call
281
341
  * links that external account/workspace to a resolved customer.
282
342
  */
283
- declare function buildIngestPayload(visitorId: string, source: SourceType, events: TrackerEvent[], userIdentity?: PayloadUserIdentity, sessionId?: string, fingerprint?: string, customerIdentity?: PayloadCustomerIdentity): IngestPayload;
343
+ declare function buildIngestPayload(visitorId: string, source: SourceType, events: TrackerEvent[], userIdentity?: PayloadUserIdentityInput, sessionId?: string, fingerprint?: string, customerIdentity?: PayloadCustomerIdentityInput): IngestPayload;
284
344
  /**
285
345
  * Maximum number of events in a single batch.
286
346
  */
287
- declare const MAX_BATCH_SIZE = 100;
347
+ declare const MAX_BATCH_SIZE: 100;
288
348
  /**
289
349
  * Split events into batches of MAX_BATCH_SIZE.
290
350
  */
291
351
  declare function batchEvents(events: TrackerEvent[]): TrackerEvent[][];
292
352
 
353
+ declare const INGEST_METHOD: "POST";
354
+ declare const INGEST_EVENT_TYPES: readonly ["pageview", "form", "identify", "custom", "calendar", "engagement"];
355
+ declare function buildIngestUrl(apiHost: string, publicKey: string): string;
356
+
293
357
  /**
294
358
  * Extract UTM parameters from a URL.
295
359
  */
@@ -373,4 +437,4 @@ interface ExtractedIdentity {
373
437
  */
374
438
  declare function extractIdentityFromForm(fields: Record<string, string>, inputTypes?: Map<string, string>): ExtractedIdentity | undefined;
375
439
 
376
- export { type BrowserIdentifyOptions, type BrowserTrackOptions, type CalendarEvent, type CalendarProvider, type CustomEvent, type CustomerAttribution, type CustomerTraits, DEFAULT_API_HOST, DEFAULT_DENIED_FORM_FIELDS, type EngagementEvent, type EventType, type ExtractedIdentity, type FormEvent, type IdentifyEvent, type IdentifyTraits, type IngestPayload, type IngestResponse, MAX_BATCH_SIZE, type PageviewEvent, type PayloadCustomerIdentity, type PayloadUserIdentity, type ServerIdentifyOptions, type ServerIdentity, type ServerTrackOptions, type SourceType, type TrackerConfig, type TrackerEvent, type UtmParams, batchEvents, buildCalendarEvent, buildCustomEvent, buildEngagementEvent, buildFormEvent, buildIdentifyEvent, buildIngestPayload, buildPageviewEvent, extractIdentityFromForm, extractPathFromUrl, extractUtmParams, findEmailField, findNameFields, isFieldDenied, isValidEmail, sanitizeFormFields, validateServerIdentity };
440
+ export { type BrowserIdentifyOptions, type BrowserTrackOptions, type CalendarEvent, type CalendarProvider, type CustomEvent, type CustomerAttribution, type CustomerTraits, DEFAULT_API_HOST, DEFAULT_DENIED_FORM_FIELDS, type EngagementEvent, type EventType, type ExtractedIdentity, type FormEvent, INGEST_EVENT_TYPES, INGEST_METHOD, type IdentifyEvent, type IdentifyTraits, type IngestPayload, type IngestResponse, MAX_BATCH_SIZE, type PageviewEvent, type PayloadCustomerIdentity, type PayloadCustomerIdentityInput, type PayloadUserIdentity, type PayloadUserIdentityInput, type ServerIdentifyOptions, type ServerIdentity, type ServerTrackOptions, type SourceType, type TrackerConfig, type TrackerEvent, type UtmParams, batchEvents, buildCalendarEvent, buildCustomEvent, buildEngagementEvent, buildFormEvent, buildIdentifyEvent, buildIngestPayload, buildIngestUrl, buildPageviewEvent, extractIdentityFromForm, extractPathFromUrl, extractUtmParams, findEmailField, findNameFields, isFieldDenied, isValidEmail, sanitizeFormFields, validateServerIdentity };
package/dist/index.js CHANGED
@@ -22,6 +22,8 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  DEFAULT_API_HOST: () => DEFAULT_API_HOST,
24
24
  DEFAULT_DENIED_FORM_FIELDS: () => DEFAULT_DENIED_FORM_FIELDS,
25
+ INGEST_EVENT_TYPES: () => INGEST_EVENT_TYPES,
26
+ INGEST_METHOD: () => INGEST_METHOD,
25
27
  MAX_BATCH_SIZE: () => MAX_BATCH_SIZE,
26
28
  batchEvents: () => batchEvents,
27
29
  buildCalendarEvent: () => buildCalendarEvent,
@@ -30,6 +32,7 @@ __export(src_exports, {
30
32
  buildFormEvent: () => buildFormEvent,
31
33
  buildIdentifyEvent: () => buildIdentifyEvent,
32
34
  buildIngestPayload: () => buildIngestPayload,
35
+ buildIngestUrl: () => buildIngestUrl,
33
36
  buildPageviewEvent: () => buildPageviewEvent,
34
37
  extractIdentityFromForm: () => extractIdentityFromForm,
35
38
  extractPathFromUrl: () => extractPathFromUrl,
@@ -46,6 +49,14 @@ module.exports = __toCommonJS(src_exports);
46
49
  // src/payload.ts
47
50
  var import_uuid = require("uuid");
48
51
 
52
+ // src/generated/ingest-contract.ts
53
+ var ingestTransport = {
54
+ method: "POST",
55
+ pathTemplate: "/api/i/v1/{publicKey}/events",
56
+ maxBatchSize: 100,
57
+ eventTypes: ["pageview", "form", "identify", "custom", "calendar", "engagement"]
58
+ };
59
+
49
60
  // src/types.ts
50
61
  var DEFAULT_API_HOST = "https://app.outlit.ai";
51
62
  var DEFAULT_DENIED_FORM_FIELDS = [
@@ -264,6 +275,14 @@ function extractIdentityFromForm(fields, inputTypes) {
264
275
  }
265
276
 
266
277
  // src/payload.ts
278
+ function normalizeTraits(traits) {
279
+ if (!traits) return void 0;
280
+ const normalized = {};
281
+ for (const [key, value] of Object.entries(traits)) {
282
+ if (value !== void 0) normalized[key] = value;
283
+ }
284
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
285
+ }
267
286
  function buildPageviewEvent(params) {
268
287
  const { url, referrer, timestamp, title } = params;
269
288
  return {
@@ -315,8 +334,8 @@ function buildIdentifyEvent(params) {
315
334
  userId,
316
335
  fingerprint,
317
336
  customerId,
318
- customerTraits,
319
- traits
337
+ customerTraits: normalizeTraits(customerTraits),
338
+ traits: normalizeTraits(traits)
320
339
  };
321
340
  }
322
341
  function buildCustomEvent(params) {
@@ -405,32 +424,33 @@ function buildIngestPayload(visitorId, source, events, userIdentity, sessionId,
405
424
  ...userIdentity.customerTraits && { customerTraits: userIdentity.customerTraits }
406
425
  } : void 0;
407
426
  const resolvedCustomerIdentity = customerIdentity ?? legacyCustomerIdentity;
427
+ const userTraits = normalizeTraits(userIdentity?.traits);
428
+ const customerTraits = normalizeTraits(resolvedCustomerIdentity?.customerTraits);
408
429
  if (fingerprint) {
409
430
  payload.fingerprint = fingerprint;
410
431
  }
411
432
  if (sessionId) {
412
433
  payload.sessionId = sessionId;
413
434
  }
414
- if (userIdentity && (userIdentity.email || userIdentity.userId || userIdentity.traits)) {
435
+ if (userIdentity && (userIdentity.email || userIdentity.userId || userIdentity.fingerprint || userTraits)) {
415
436
  payload.userIdentity = {
416
437
  ...userIdentity.email && { email: userIdentity.email },
417
438
  ...userIdentity.userId && { userId: userIdentity.userId },
418
- ...userIdentity.traits && { traits: userIdentity.traits }
439
+ ...userIdentity.fingerprint && { fingerprint: userIdentity.fingerprint },
440
+ ...userTraits && { traits: userTraits }
419
441
  };
420
442
  }
421
- if (resolvedCustomerIdentity && (resolvedCustomerIdentity.customerId || resolvedCustomerIdentity.customerTraits)) {
443
+ if (resolvedCustomerIdentity && (resolvedCustomerIdentity.customerId || customerTraits)) {
422
444
  payload.customerIdentity = {
423
445
  ...resolvedCustomerIdentity.customerId && {
424
446
  customerId: resolvedCustomerIdentity.customerId
425
447
  },
426
- ...resolvedCustomerIdentity.customerTraits && {
427
- customerTraits: resolvedCustomerIdentity.customerTraits
428
- }
448
+ ...customerTraits && { customerTraits }
429
449
  };
430
450
  }
431
451
  return payload;
432
452
  }
433
- var MAX_BATCH_SIZE = 100;
453
+ var MAX_BATCH_SIZE = ingestTransport.maxBatchSize;
434
454
  function batchEvents(events) {
435
455
  const batches = [];
436
456
  for (let i = 0; i < events.length; i += MAX_BATCH_SIZE) {
@@ -438,10 +458,20 @@ function batchEvents(events) {
438
458
  }
439
459
  return batches;
440
460
  }
461
+
462
+ // src/transport.ts
463
+ var INGEST_METHOD = ingestTransport.method;
464
+ var INGEST_EVENT_TYPES = ingestTransport.eventTypes;
465
+ function buildIngestUrl(apiHost, publicKey) {
466
+ const path = ingestTransport.pathTemplate.replace("{publicKey}", encodeURIComponent(publicKey));
467
+ return `${apiHost.replace(/\/$/, "")}${path}`;
468
+ }
441
469
  // Annotate the CommonJS export names for ESM import in node:
442
470
  0 && (module.exports = {
443
471
  DEFAULT_API_HOST,
444
472
  DEFAULT_DENIED_FORM_FIELDS,
473
+ INGEST_EVENT_TYPES,
474
+ INGEST_METHOD,
445
475
  MAX_BATCH_SIZE,
446
476
  batchEvents,
447
477
  buildCalendarEvent,
@@ -450,6 +480,7 @@ function batchEvents(events) {
450
480
  buildFormEvent,
451
481
  buildIdentifyEvent,
452
482
  buildIngestPayload,
483
+ buildIngestUrl,
453
484
  buildPageviewEvent,
454
485
  extractIdentityFromForm,
455
486
  extractPathFromUrl,