@nexly/core 0.15.3 → 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.
package/dist/collect.d.ts CHANGED
@@ -16,10 +16,54 @@ export type CollectCredentials = {
16
16
  /** Which SDK identity to report (see {@link TrackEventInput.client}). Optional. */
17
17
  client?: NexlyClient;
18
18
  } & IngestCredentials;
19
+ /**
20
+ * Top-level scalar payload used by the `cdata` slot. The contract is
21
+ * intentionally narrow: a flat object whose values are `string`,
22
+ * `number`, or `boolean`. All values are normalised to strings
23
+ * server-side (see `internal/apps/ingest_sanitize.go::SanitizeCData`)
24
+ * so downstream analytics deal with one type per key. Nested objects
25
+ * and arrays are silently dropped — push richer payloads through a
26
+ * different surface.
27
+ */
28
+ export type CData = Record<string, string | number | boolean>;
29
+ /**
30
+ * Typed override for the per-event attribution slot accepted by
31
+ * {@link NexlyBase.customEvent}'s third parameter. Mirrors
32
+ * `internal/apps/ingest_context.go::StandardAttributionKeys` —
33
+ * keep both ends in sync when adding new marketing parameters.
34
+ *
35
+ * Standard attribution keys are also auto-extracted by the server
36
+ * from the landing URL on the first event of a session; this type
37
+ * lets callers manually override the per-event value when the URL
38
+ * no longer carries the parameter (deep-links, post-navigation
39
+ * clicks, server-side redirects).
40
+ */
41
+ export type StandardContextOverride = {
42
+ utm_source?: string;
43
+ utm_medium?: string;
44
+ utm_campaign?: string;
45
+ utm_content?: string;
46
+ utm_term?: string;
47
+ gclid?: string;
48
+ gad_source?: string;
49
+ gad_campaignid?: string;
50
+ fbclid?: string;
51
+ msclkid?: string;
52
+ ttclid?: string;
53
+ li_fat_id?: string;
54
+ yclid?: string;
55
+ mc_cid?: string;
56
+ ref?: string;
57
+ };
19
58
  /**
20
59
  * Event envelope:
21
- * - `context` — per-event volatile metadata (path, screen, viewport, visitor_id, session_id, …).
22
- * - `data` owner-defined custom properties.
60
+ * - `context` — per-event volatile metadata (path, screen, viewport, visitor_id, session_id, …)
61
+ * plus optional standard attribution overrides (`utm_*`, `gclid`, …).
62
+ * - `data` — SDK-emitted built-in event payload (engagement: `tag`/`max_percent`,
63
+ * lifecycle: `active_seconds`, …). Validated server-side against a per-event-type
64
+ * allowlist; user-defined keys belong in `cdata` instead.
65
+ * - `cdata` — user-defined custom analytics payload validated against the per-app
66
+ * `Custom data` registry. Scalar contract — see {@link CData}.
23
67
  * - `session_context` — session-stable metadata (OS, locale, screen), sent once per session.
24
68
  */
25
69
  export type TrackEventInput = {
@@ -34,11 +78,13 @@ export type TrackEventInput = {
34
78
  client?: NexlyClient;
35
79
  context?: Record<string, unknown>;
36
80
  data?: Record<string, unknown>;
81
+ cdata?: CData;
37
82
  sessionContext?: Record<string, unknown>;
38
83
  };
39
84
  /**
40
85
  * Builds the JSON body for POST /v1/collect (snake_case wire format).
41
86
  * Duplicates `context.path` to the top-level `path` when present.
87
+ * Includes `cdata` when the caller passed a non-empty object.
42
88
  * Includes `session_context` when provided (first event of a session).
43
89
  */
44
90
  export declare function buildCollectPayload(input: TrackEventInput): Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,iBAAiB,CAAA;AAErB;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC,CAAA;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBnF"}
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,iBAAiB,CAAA;AAErB;;;;;;;;GAQG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;AAE7D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC,CAAA;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4BnF"}
package/dist/collect.js CHANGED
@@ -10,6 +10,7 @@ function isPlainObject(v) {
10
10
  /**
11
11
  * Builds the JSON body for POST /v1/collect (snake_case wire format).
12
12
  * Duplicates `context.path` to the top-level `path` when present.
13
+ * Includes `cdata` when the caller passed a non-empty object.
13
14
  * Includes `session_context` when provided (first event of a session).
14
15
  */
15
16
  export function buildCollectPayload(input) {
@@ -31,6 +32,10 @@ export function buildCollectPayload(input) {
31
32
  if (pathFromContext) {
32
33
  body.path = pathFromContext;
33
34
  }
35
+ const cdata = isPlainObject(input.cdata) ? input.cdata : null;
36
+ if (cdata && Object.keys(cdata).length > 0) {
37
+ body.cdata = cdata;
38
+ }
34
39
  const sc = isPlainObject(input.sessionContext) ? input.sessionContext : null;
35
40
  if (sc && Object.keys(sc).length > 0) {
36
41
  body.session_context = sc;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * - `@nexly/web` — browser (sendBeacon, DOM meta, engagement listeners).
6
6
  * - `@nexly/react-native` — React Native (fetch, AsyncStorage, AppState).
7
7
  */
8
- export { buildCollectPayload, type CollectCredentials, type IngestCredentials, type TrackEventInput, } from './collect.js';
8
+ export { buildCollectPayload, type CData, type CollectCredentials, type IngestCredentials, type StandardContextOverride, type TrackEventInput, } from './collect.js';
9
9
  export { NexlyBase, DEFAULT_COLLECT_URL, type NexlyEventInput, type NexlyEventType, type NexlyInit, } from './nexly-base.js';
10
10
  export { NexlyClient } from './clients.js';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,mBAAmB,EACnB,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import type { NexlyClient } from './clients.js';
2
- import { type IngestCredentials } from './collect.js';
2
+ import { type CData, type IngestCredentials, type StandardContextOverride } from './collect.js';
3
3
  export declare const DEFAULT_COLLECT_URL = "https://gate.nexly.to/v1/collect";
4
4
  /** Options for {@link NexlyBase}. `key` is the ingest API token (sent as `api_token` on the wire). */
5
5
  export type NexlyInit = {
@@ -22,7 +22,22 @@ export type NexlyEventType = 'pageview' | 'engagement' | 'custom' | 'navigation'
22
22
  export type NexlyEventInput = {
23
23
  name: string;
24
24
  type: NexlyEventType | string;
25
+ /**
26
+ * SDK-emitted built-in event payload. For built-in event types
27
+ * (`engagement`, `lifecycle`, `pageview`, `navigation`) the server
28
+ * validates this against a per-event-type allowlist. For
29
+ * `type: 'custom'` events, user-defined payload belongs in
30
+ * {@link cdata} instead — `data` is reserved for SDK metrics.
31
+ */
25
32
  data?: Record<string, unknown>;
33
+ /**
34
+ * User-defined custom analytics payload. Top-level scalar map
35
+ * (`string` / `number` / `boolean`). Server validates against the
36
+ * per-app `Custom data` registry; unapproved keys are discovered
37
+ * but not stored. Use {@link NexlyBase.customEvent} for the
38
+ * ergonomic per-event API.
39
+ */
40
+ cdata?: CData;
26
41
  /** Merged on top of default platform context (see {@link NexlyBase.collectEventContext}). */
27
42
  context?: Record<string, unknown>;
28
43
  };
@@ -72,9 +87,26 @@ export declare abstract class NexlyBase {
72
87
  */
73
88
  pageview(path?: string): boolean;
74
89
  /**
75
- * Sends a custom event. Pass `context` to merge or override default fields.
90
+ * Sends a generic event. The unstructured `context` is merged on top
91
+ * of the default platform context; `data` carries SDK-internal
92
+ * payload (or user payload for legacy callers; new code should
93
+ * prefer {@link customEvent} for custom analytics).
76
94
  */
77
95
  event(input: NexlyEventInput): boolean;
96
+ /**
97
+ * Sends a custom analytics event. `cdata` carries the user-defined
98
+ * scalar payload that the server validates against the per-app
99
+ * `Custom data` registry. The optional `context` slot is the typed
100
+ * override for standard attribution keys (`utm_*`, `gclid`,
101
+ * `gad_source`, …) when the landing URL no longer carries them at
102
+ * event time (deep links, post-navigation clicks, server-side
103
+ * redirects).
104
+ *
105
+ * Equivalent to calling `event({ name, type: 'custom', cdata,
106
+ * context })` but with a tighter type for `context` (only standard
107
+ * attribution keys, no free-form fields).
108
+ */
109
+ customEvent(name: string, cdata?: CData, context?: StandardContextOverride): boolean;
78
110
  private dispatch;
79
111
  }
80
112
  //# sourceMappingURL=nexly-base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nexly-base.d.ts","sourceRoot":"","sources":["../src/nexly-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAI1E,eAAO,MAAM,mBAAmB,qCAAqC,CAAA;AAErE,sGAAsG;AACtG,MAAM,MAAM,SAAS,GAAG;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAA;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,GAAG,MAAM,CAAA;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,8BAAsB,SAAS;IAC7B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAyB;IAEjD,iFAAiF;IACjF,MAAM,CAAC,WAAW,IAAI,SAAS,GAAG,IAAI;IAItC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;IAI9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;IAExC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAsB;IAEnD,SAAS,aAAa,IAAI,EAAE,SAAS;IASrC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAEhC;IAED,SAAS,KAAK,WAAW,IAAI,iBAAiB,CAE7C;IAED,kFAAkF;IAClF,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAEvE,yDAAyD;IACzD,SAAS,CAAC,QAAQ,CAAC,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEjE,yDAAyD;IACzD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnE,kDAAkD;IAClD,QAAQ,CAAC,cAAc,IAAI,MAAM;IAEjC;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAWhC;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO;IAYtC,OAAO,CAAC,QAAQ;CA4BjB"}
1
+ {"version":3,"file":"nexly-base.d.ts","sourceRoot":"","sources":["../src/nexly-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAA;AAIrB,eAAO,MAAM,mBAAmB,qCAAqC,CAAA;AAErE,sGAAsG;AACtG,MAAM,MAAM,SAAS,GAAG;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAA;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,GAAG,MAAM,CAAA;IAC7B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,8BAAsB,SAAS;IAC7B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAyB;IAEjD,iFAAiF;IACjF,MAAM,CAAC,WAAW,IAAI,SAAS,GAAG,IAAI;IAItC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;IAI9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;IAExC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAsB;IAEnD,SAAS,aAAa,IAAI,EAAE,SAAS;IASrC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAEhC;IAED,SAAS,KAAK,WAAW,IAAI,iBAAiB,CAE7C;IAED,kFAAkF;IAClF,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAEvE,yDAAyD;IACzD,SAAS,CAAC,QAAQ,CAAC,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEjE,yDAAyD;IACzD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnE,kDAAkD;IAClD,QAAQ,CAAC,cAAc,IAAI,MAAM;IAEjC;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAWhC;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO;IAatC;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO;IAapF,OAAO,CAAC,QAAQ;CA8BjB"}
@@ -1,4 +1,4 @@
1
- import { buildCollectPayload } from './collect.js';
1
+ import { buildCollectPayload, } from './collect.js';
2
2
  export const DEFAULT_COLLECT_URL = 'https://gate.nexly.to/v1/collect';
3
3
  /**
4
4
  * Platform-agnostic base class: session state, payload assembly, disabled-state logic.
@@ -65,7 +65,10 @@ export class NexlyBase {
65
65
  });
66
66
  }
67
67
  /**
68
- * Sends a custom event. Pass `context` to merge or override default fields.
68
+ * Sends a generic event. The unstructured `context` is merged on top
69
+ * of the default platform context; `data` carries SDK-internal
70
+ * payload (or user payload for legacy callers; new code should
71
+ * prefer {@link customEvent} for custom analytics).
69
72
  */
70
73
  event(input) {
71
74
  if (this.disabled)
@@ -77,6 +80,33 @@ export class NexlyBase {
77
80
  eventType: input.type,
78
81
  context,
79
82
  data: input.data ?? {},
83
+ cdata: input.cdata,
84
+ });
85
+ }
86
+ /**
87
+ * Sends a custom analytics event. `cdata` carries the user-defined
88
+ * scalar payload that the server validates against the per-app
89
+ * `Custom data` registry. The optional `context` slot is the typed
90
+ * override for standard attribution keys (`utm_*`, `gclid`,
91
+ * `gad_source`, …) when the landing URL no longer carries them at
92
+ * event time (deep links, post-navigation clicks, server-side
93
+ * redirects).
94
+ *
95
+ * Equivalent to calling `event({ name, type: 'custom', cdata,
96
+ * context })` but with a tighter type for `context` (only standard
97
+ * attribution keys, no free-form fields).
98
+ */
99
+ customEvent(name, cdata, context) {
100
+ if (this.disabled)
101
+ return false;
102
+ const defaultContext = { ...this.collectEventContext(), path: this.getDefaultPath() };
103
+ const merged = context ? { ...defaultContext, ...context } : defaultContext;
104
+ return this.dispatch({
105
+ eventName: name,
106
+ eventType: 'custom',
107
+ context: merged,
108
+ data: {},
109
+ cdata,
80
110
  });
81
111
  }
82
112
  dispatch(args) {
@@ -96,6 +126,7 @@ export class NexlyBase {
96
126
  client: this.client,
97
127
  context: args.context,
98
128
  data: args.data,
129
+ cdata: args.cdata,
99
130
  sessionContext,
100
131
  });
101
132
  return this.transport(payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexly/core",
3
- "version": "0.15.3",
3
+ "version": "0.16.0",
4
4
  "description": "Nexly ingest core (platform-agnostic): types, payload builder, abstract NexlyBase client",
5
5
  "license": "MIT",
6
6
  "keywords": [