@nexly/core 0.15.4 → 0.16.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/collect.d.ts CHANGED
@@ -16,10 +16,77 @@ 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
+ };
58
+ /**
59
+ * Runtime mirror of the keys in {@link StandardContextOverride}.
60
+ * Mirrors `internal/apps/ingest_context.go::StandardAttributionKeys`
61
+ * on the server — when adding a new marketing parameter, update both
62
+ * sides plus the type above.
63
+ *
64
+ * Useful when application code needs to split a free-form payload
65
+ * into the {@link CData} slot (product-data) and the third `context`
66
+ * parameter of {@link NexlyBase.customEvent} (attribution
67
+ * overrides). Note that `ref` is included because it is a
68
+ * standard affiliate / referral parameter; apps that use `ref` as
69
+ * a product-internal code (e.g. Vaiz) should treat it as cdata
70
+ * rather than attribution — partition it out manually.
71
+ */
72
+ export declare const STANDARD_ATTRIBUTION_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term", "gclid", "gad_source", "gad_campaignid", "fbclid", "msclkid", "ttclid", "li_fat_id", "yclid", "mc_cid", "ref"];
73
+ /** Union of {@link STANDARD_ATTRIBUTION_KEYS} entries. */
74
+ export type StandardAttributionKey = (typeof STANDARD_ATTRIBUTION_KEYS)[number];
75
+ /**
76
+ * Returns `true` when `key` is a member of {@link STANDARD_ATTRIBUTION_KEYS}.
77
+ * Use this as a predicate when splitting a flat payload into the
78
+ * {@link CData} slot and the attribution-overrides slot.
79
+ */
80
+ export declare function isStandardAttributionKey(key: string): key is StandardAttributionKey;
19
81
  /**
20
82
  * Event envelope:
21
- * - `context` — per-event volatile metadata (path, screen, viewport, visitor_id, session_id, …).
22
- * - `data` owner-defined custom properties.
83
+ * - `context` — per-event volatile metadata (path, screen, viewport, visitor_id, session_id, …)
84
+ * plus optional standard attribution overrides (`utm_*`, `gclid`, …).
85
+ * - `data` — SDK-emitted built-in event payload (engagement: `tag`/`max_percent`,
86
+ * lifecycle: `active_seconds`, …). Validated server-side against a per-event-type
87
+ * allowlist; user-defined keys belong in `cdata` instead.
88
+ * - `cdata` — user-defined custom analytics payload validated against the per-app
89
+ * `Custom data` registry. Scalar contract — see {@link CData}.
23
90
  * - `session_context` — session-stable metadata (OS, locale, screen), sent once per session.
24
91
  */
25
92
  export type TrackEventInput = {
@@ -34,11 +101,13 @@ export type TrackEventInput = {
34
101
  client?: NexlyClient;
35
102
  context?: Record<string, unknown>;
36
103
  data?: Record<string, unknown>;
104
+ cdata?: CData;
37
105
  sessionContext?: Record<string, unknown>;
38
106
  };
39
107
  /**
40
108
  * Builds the JSON body for POST /v1/collect (snake_case wire format).
41
109
  * Duplicates `context.path` to the top-level `path` when present.
110
+ * Includes `cdata` when the caller passed a non-empty object.
42
111
  * Includes `session_context` when provided (first event of a session).
43
112
  */
44
113
  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;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,iMAgB5B,CAAA;AAEV,0DAA0D;AAC1D,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAI/E;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,sBAAsB,CAEnF;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
@@ -4,12 +4,53 @@
4
4
  * This module is safe to import from any runtime (browser, React Native, Node).
5
5
  * Transport (beacon / fetch / native) lives in platform-specific packages.
6
6
  */
7
+ /**
8
+ * Runtime mirror of the keys in {@link StandardContextOverride}.
9
+ * Mirrors `internal/apps/ingest_context.go::StandardAttributionKeys`
10
+ * on the server — when adding a new marketing parameter, update both
11
+ * sides plus the type above.
12
+ *
13
+ * Useful when application code needs to split a free-form payload
14
+ * into the {@link CData} slot (product-data) and the third `context`
15
+ * parameter of {@link NexlyBase.customEvent} (attribution
16
+ * overrides). Note that `ref` is included because it is a
17
+ * standard affiliate / referral parameter; apps that use `ref` as
18
+ * a product-internal code (e.g. Vaiz) should treat it as cdata
19
+ * rather than attribution — partition it out manually.
20
+ */
21
+ export const STANDARD_ATTRIBUTION_KEYS = [
22
+ 'utm_source',
23
+ 'utm_medium',
24
+ 'utm_campaign',
25
+ 'utm_content',
26
+ 'utm_term',
27
+ 'gclid',
28
+ 'gad_source',
29
+ 'gad_campaignid',
30
+ 'fbclid',
31
+ 'msclkid',
32
+ 'ttclid',
33
+ 'li_fat_id',
34
+ 'yclid',
35
+ 'mc_cid',
36
+ 'ref',
37
+ ];
38
+ const STANDARD_ATTRIBUTION_KEY_SET = new Set(STANDARD_ATTRIBUTION_KEYS);
39
+ /**
40
+ * Returns `true` when `key` is a member of {@link STANDARD_ATTRIBUTION_KEYS}.
41
+ * Use this as a predicate when splitting a flat payload into the
42
+ * {@link CData} slot and the attribution-overrides slot.
43
+ */
44
+ export function isStandardAttributionKey(key) {
45
+ return STANDARD_ATTRIBUTION_KEY_SET.has(key);
46
+ }
7
47
  function isPlainObject(v) {
8
48
  return v !== null && typeof v === 'object' && !Array.isArray(v);
9
49
  }
10
50
  /**
11
51
  * Builds the JSON body for POST /v1/collect (snake_case wire format).
12
52
  * Duplicates `context.path` to the top-level `path` when present.
53
+ * Includes `cdata` when the caller passed a non-empty object.
13
54
  * Includes `session_context` when provided (first event of a session).
14
55
  */
15
56
  export function buildCollectPayload(input) {
@@ -31,6 +72,10 @@ export function buildCollectPayload(input) {
31
72
  if (pathFromContext) {
32
73
  body.path = pathFromContext;
33
74
  }
75
+ const cdata = isPlainObject(input.cdata) ? input.cdata : null;
76
+ if (cdata && Object.keys(cdata).length > 0) {
77
+ body.cdata = cdata;
78
+ }
34
79
  const sc = isPlainObject(input.sessionContext) ? input.sessionContext : null;
35
80
  if (sc && Object.keys(sc).length > 0) {
36
81
  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, isStandardAttributionKey, STANDARD_ATTRIBUTION_KEYS, type CData, type CollectCredentials, type IngestCredentials, type StandardAttributionKey, 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,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,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"}
package/dist/index.js CHANGED
@@ -5,6 +5,6 @@
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, } from './collect.js';
8
+ export { buildCollectPayload, isStandardAttributionKey, STANDARD_ATTRIBUTION_KEYS, } from './collect.js';
9
9
  export { NexlyBase, DEFAULT_COLLECT_URL, } from './nexly-base.js';
10
10
  export { NexlyClient } from './clients.js';
@@ -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.4",
3
+ "version": "0.16.1",
4
4
  "description": "Nexly ingest core (platform-agnostic): types, payload builder, abstract NexlyBase client",
5
5
  "license": "MIT",
6
6
  "keywords": [