@traffical/node 0.9.0 → 0.10.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/README.md CHANGED
@@ -44,12 +44,22 @@ await client.track('purchase', {
44
44
  ```typescript
45
45
  const client = new TrafficalClient({
46
46
  // Required
47
+ orgId: 'org_...',
48
+ projectId: 'proj_...',
49
+ env: 'production',
47
50
  apiKey: 'sk_...',
48
-
51
+
49
52
  // Optional
50
- apiBase: 'https://api.traffical.io', // Custom API endpoint
51
- cacheTtl: 60_000, // Config cache TTL in ms (default: 60s)
52
- timeout: 5_000, // Request timeout in ms (default: 5s)
53
+ baseUrl: 'https://sdk.traffical.io', // Custom edge endpoint
54
+ refreshIntervalMs: 60_000, // Config refresh interval (default: 60000)
55
+ batchSize: 10, // Events per batch (default: 10)
56
+ // (legacy alias: eventBatchSize)
57
+ flushIntervalMs: 30_000, // Flush interval (default: 30000)
58
+ // (legacy alias: eventFlushIntervalMs)
59
+ configTimeoutMs: 10_000, // Config-fetch timeout (default: 10000)
60
+ eventsTimeoutMs: 10_000, // Event-delivery timeout (default: 10000)
61
+ resolveTimeoutMs: 5_000, // Server-resolve timeout (default: 5000)
62
+ // (legacy fallback for all three: requestTimeoutMs)
53
63
  });
54
64
  ```
55
65
 
@@ -106,8 +116,8 @@ The Node SDK automatically batches events for efficiency:
106
116
  ```typescript
107
117
  const client = new TrafficalClient({
108
118
  apiKey: 'sk_...',
109
- batchSize: 100, // Events per batch (default: 100)
110
- flushInterval: 5000, // Flush interval in ms (default: 5s)
119
+ batchSize: 10, // Events per batch (default: 10)
120
+ flushIntervalMs: 30000, // Flush interval in ms (default: 30s)
111
121
  });
112
122
 
113
123
  // Events are queued and sent in batches
@@ -68,9 +68,18 @@ describe("Node TrafficalClient assignmentLogger", () => {
68
68
  expect(entry.type).toBe("decision");
69
69
  expect(entry.policyId).toBe("pol_1");
70
70
  expect(entry.allocationName).toBe("treatment");
71
- expect(entry.decisionId).toBe("dec_server_1");
71
+ // Server mode now mints a FRESH decisionId per decide() (spec 0.7.0 S8)
72
+ // it no longer reuses the resolve response's decisionId across decisions.
73
+ expect(entry.decisionId).toMatch(/^dec_/);
74
+ expect(entry.decisionId).not.toBe("dec_server_1");
72
75
  expect(entry.anonymousId).toBeUndefined();
73
76
  expect(entry.id).toMatch(/^asn_/);
77
+ // Warehouse-native passthrough fields from the layer resolution.
78
+ expect(entry.bucket).toBe(500);
79
+ expect(entry.configVersion).toBe(serverResolveResponse.stateVersion);
80
+ // The server response carries no propensity or contextual model version.
81
+ expect(entry.probability).toBeUndefined();
82
+ expect(entry.modelVersion).toBeUndefined();
74
83
  await client.destroy();
75
84
  });
76
85
  test("decide() then trackExposure() produce two distinct rows (decision + exposure)", async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"assignment-logger.test.js","sourceRoot":"","sources":["../src/assignment-logger.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;AAEvC,MAAM,qBAAqB,GAAG;IAC5B,UAAU,EAAE,cAAc;IAC1B,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;IACnC,QAAQ,EAAE;QACR,SAAS,EAAE,sBAAsB;QACjC,YAAY,EAAE,QAAQ;QACtB,MAAM,EAAE;YACN;gBACE,OAAO,EAAE,SAAS;gBAClB,MAAM,EAAE,GAAG;gBACX,QAAQ,EAAE,OAAO;gBACjB,YAAY,EAAE,SAAS;gBACvB,cAAc,EAAE,WAAW;aAC5B;SACF;KACF;IACD,YAAY,EAAE,sBAAsB;IACpC,kBAAkB,EAAE,KAAK;CAC1B,CAAC;AAEF,SAAS,cAAc;IACrB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE;QAChC,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,qBAAqB;YACvC,OAAO,EAAE,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;SAChB,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,KAAK,GAAG,SAAoC,CAAC;IACxD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,GAAG;IACjB,KAAK,EAAE,UAAU;IACjB,SAAS,EAAE,WAAW;IACtB,GAAG,EAAE,YAAY;IACjB,MAAM,EAAE,mBAAmB;IAC3B,iBAAiB,EAAE,CAAC,CAAC;IACrB,cAAc,EAAE,KAAK;IACrB,cAAc,EAAE,QAAiB;IACjC,kBAAkB,EAAE,IAAI;CACzB,CAAC;AAEF,SAAS,CAAC,GAAG,EAAE;IACb,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACrD,IAAI,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACzF,cAAc,EAAE,CAAC;QACjB,MAAM,OAAO,GAAyB,EAAE,CAAC;QAEzC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,GAAG,UAAU;YACb,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;SACjD,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAE1B,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAEnF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;QACxB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAElC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC/F,cAAc,EAAE,CAAC;QACjB,MAAM,OAAO,GAAyB,EAAE,CAAC;QAEzC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,GAAG,UAAU;YACb,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;SACjD,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAE1B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;YAC7B,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;YAC7B,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;SACjC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAE/B,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEhD,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC5E,cAAc,EAAE,CAAC;QACjB,MAAM,OAAO,GAAyB,EAAE,CAAC;QAEzC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,GAAG,UAAU;YACb,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;SACjD,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAE1B,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACnF,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAEnF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE1C,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"assignment-logger.test.js","sourceRoot":"","sources":["../src/assignment-logger.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=canonical-options.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-options.test.d.ts","sourceRoot":"","sources":["../src/canonical-options.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Canonical option-name aliases (spec 0.7.0 sdk-design-contract).
3
+ *
4
+ * The Node client accepts the canonical option names alongside the legacy
5
+ * ones, and a specific canonical option always wins when both are set:
6
+ * - batchSize (alias of eventBatchSize)
7
+ * - flushIntervalMs (alias of eventFlushIntervalMs)
8
+ * - configTimeoutMs / eventsTimeoutMs / resolveTimeoutMs
9
+ * (per-path split of the legacy single requestTimeoutMs)
10
+ */
11
+ import { describe, test, expect, afterEach, mock } from "bun:test";
12
+ import { TrafficalClient } from "./client.js";
13
+ const originalFetch = globalThis.fetch;
14
+ const originalWarn = console.warn;
15
+ afterEach(() => {
16
+ globalThis.fetch = originalFetch;
17
+ console.warn = originalWarn;
18
+ });
19
+ const localConfig = {
20
+ version: "2024-06-01T00:00:00.000Z",
21
+ orgId: "org_1",
22
+ projectId: "proj_1",
23
+ env: "test",
24
+ hashing: { unitKey: "userId", bucketCount: 1000 },
25
+ parameters: [
26
+ { key: "ui.color", type: "string", default: "#000", layerId: "layer_ui", namespace: "ui" },
27
+ ],
28
+ layers: [],
29
+ };
30
+ function baseOpts() {
31
+ return {
32
+ orgId: "org_1",
33
+ projectId: "proj_1",
34
+ env: "test",
35
+ apiKey: "pk",
36
+ localConfig,
37
+ refreshIntervalMs: -1,
38
+ trackDecisions: false,
39
+ // Never auto-flush on a timer unless a test overrides it.
40
+ eventFlushIntervalMs: 999999,
41
+ flushIntervalMs: 999999,
42
+ };
43
+ }
44
+ /** Mock fetch that records the /v1/events/batch POST bodies (config routes 404). */
45
+ function mockEventPosts(posted) {
46
+ globalThis.fetch = mock(async (url, init) => {
47
+ if (String(url).includes("/v1/events/batch")) {
48
+ const body = JSON.parse(String(init?.body ?? "{}"));
49
+ posted.push(body.events);
50
+ return new Response(JSON.stringify({ accepted: 1 }), { status: 200 });
51
+ }
52
+ return new Response("not found", { status: 404 });
53
+ });
54
+ }
55
+ const tick = () => new Promise((r) => setTimeout(r, 0));
56
+ describe("batchSize alias", () => {
57
+ test("canonical batchSize triggers auto-flush at the threshold", async () => {
58
+ const posted = [];
59
+ mockEventPosts(posted);
60
+ const client = new TrafficalClient({ ...baseOpts(), batchSize: 1 });
61
+ await client.initialize();
62
+ client.track("purchase", { orderId: "o1" }, { unitKey: "user-1" });
63
+ await tick();
64
+ expect(posted.flat().length).toBeGreaterThan(0);
65
+ await client.close();
66
+ });
67
+ test("legacy eventBatchSize still triggers auto-flush at the threshold", async () => {
68
+ const posted = [];
69
+ mockEventPosts(posted);
70
+ const client = new TrafficalClient({ ...baseOpts(), eventBatchSize: 1 });
71
+ await client.initialize();
72
+ client.track("purchase", { orderId: "o1" }, { unitKey: "user-1" });
73
+ await tick();
74
+ expect(posted.flat().length).toBeGreaterThan(0);
75
+ await client.close();
76
+ });
77
+ test("canonical batchSize wins over legacy eventBatchSize", async () => {
78
+ const posted = [];
79
+ mockEventPosts(posted);
80
+ // Canonical=1 (flush after 1) beats legacy=1000 (would never flush here).
81
+ const client = new TrafficalClient({ ...baseOpts(), batchSize: 1, eventBatchSize: 1000 });
82
+ await client.initialize();
83
+ client.track("purchase", { orderId: "o1" }, { unitKey: "user-1" });
84
+ await tick();
85
+ expect(posted.flat().length).toBeGreaterThan(0);
86
+ await client.close();
87
+ });
88
+ });
89
+ describe("flushIntervalMs alias", () => {
90
+ test("canonical flushIntervalMs wins over legacy eventFlushIntervalMs", async () => {
91
+ const posted = [];
92
+ mockEventPosts(posted);
93
+ // Canonical=10ms flushes on the timer; legacy=999999 would not within the window.
94
+ const client = new TrafficalClient({
95
+ ...baseOpts(),
96
+ flushIntervalMs: 10,
97
+ eventFlushIntervalMs: 999999,
98
+ batchSize: 1000, // keep batch threshold high so only the timer can flush
99
+ });
100
+ await client.initialize();
101
+ client.track("purchase", { orderId: "o1" }, { unitKey: "user-1" });
102
+ await new Promise((r) => setTimeout(r, 60));
103
+ expect(posted.flat().length).toBeGreaterThan(0);
104
+ await client.close();
105
+ });
106
+ });
107
+ /** A fetch that hangs forever but rejects with AbortError when aborted. */
108
+ function mockHungFetch(capture) {
109
+ globalThis.fetch = mock((url, init) => new Promise((_resolve, reject) => {
110
+ capture(String(url), init?.signal);
111
+ init?.signal?.addEventListener("abort", () => {
112
+ reject(new DOMException("The operation was aborted.", "AbortError"));
113
+ });
114
+ }));
115
+ }
116
+ describe("configTimeoutMs alias", () => {
117
+ test("canonical configTimeoutMs aborts a hung config fetch (canonical wins over legacy)", async () => {
118
+ const warnings = [];
119
+ console.warn = (...args) => warnings.push(args.map(String).join(" "));
120
+ let configSignal;
121
+ mockHungFetch((url, signal) => {
122
+ if (url.includes("/v1/config/"))
123
+ configSignal = signal;
124
+ });
125
+ const client = new TrafficalClient({
126
+ orgId: "org_1",
127
+ projectId: "proj_1",
128
+ env: "test",
129
+ apiKey: "pk",
130
+ trackDecisions: false,
131
+ refreshIntervalMs: -1,
132
+ disableCloudEvents: true,
133
+ // Canonical tiny timeout must win over the huge legacy value; otherwise
134
+ // initialize() would hang ~100s and this test would time out.
135
+ configTimeoutMs: 20,
136
+ requestTimeoutMs: 100000,
137
+ });
138
+ await client.initialize();
139
+ expect(warnings.some((w) => w.includes("Failed to fetch config"))).toBe(true);
140
+ expect(configSignal?.aborted).toBe(true);
141
+ await client.close();
142
+ });
143
+ });
144
+ describe("eventsTimeoutMs alias", () => {
145
+ test("canonical eventsTimeoutMs aborts a hung events POST (canonical wins over legacy)", async () => {
146
+ console.warn = () => { };
147
+ let eventsSignal;
148
+ mockHungFetch((url, signal) => {
149
+ if (url.includes("/v1/events/batch"))
150
+ eventsSignal = signal;
151
+ });
152
+ const client = new TrafficalClient({
153
+ ...baseOpts(),
154
+ batchSize: 1, // flush after one event
155
+ eventsTimeoutMs: 20, // canonical tiny value...
156
+ requestTimeoutMs: 100000, // ...must win over the huge legacy fallback
157
+ });
158
+ // localConfig is preloaded, so no config fetch is needed before tracking.
159
+ client.track("purchase", { orderId: "o1" }, { unitKey: "user-1" });
160
+ await new Promise((r) => setTimeout(r, 80));
161
+ expect(eventsSignal).toBeDefined();
162
+ expect(eventsSignal?.aborted).toBe(true);
163
+ // destroySync() avoids awaiting a final flush against the still-hung fetch.
164
+ client.destroySync();
165
+ });
166
+ });
167
+ //# sourceMappingURL=canonical-options.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-options.test.js","sourceRoot":"","sources":["../src/canonical-options.test.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * - Batched event transport for efficiency
12
12
  * - Graceful degradation with local config and schema defaults
13
13
  */
14
- import { type Context, type DecisionResult, type ParameterValue, type TrafficalClientOptions as CoreClientOptions, type TrackOptions, type AssignmentLogger, type TrackableEventLogger, type TrackEventMap, type OnSchemaWarnings } from "@traffical/core";
14
+ import { type Context, type DecisionResult, type ParameterValue, type TrafficalClientOptions as CoreClientOptions, type TrackOptions, type TrackEventOptions, type DecideOptions, type GetParamsOptions, type AssignmentLogger, type TrackableEventLogger, type TrackEventMap, type OnSchemaWarnings } from "@traffical/core";
15
15
  /**
16
16
  * Options for the Node.js Traffical client.
17
17
  * Extends the core options with Node-specific settings.
@@ -30,12 +30,23 @@ export interface TrafficalClientOptions extends CoreClientOptions {
30
30
  decisionDeduplicationTtlMs?: number;
31
31
  /**
32
32
  * Event batch size - number of events before auto-flush (default: 10).
33
+ * @deprecated Use the canonical `batchSize` instead. `eventBatchSize` still works.
33
34
  */
34
35
  eventBatchSize?: number;
35
36
  /**
36
37
  * Event flush interval in milliseconds (default: 30000).
38
+ * @deprecated Use the canonical `flushIntervalMs` instead. `eventFlushIntervalMs` still works.
37
39
  */
38
40
  eventFlushIntervalMs?: number;
41
+ /** Events per delivery batch (default: 10). Canonical alias of `eventBatchSize`. */
42
+ batchSize?: number;
43
+ /** Event flush cadence in milliseconds (default: 30000). Canonical alias of `eventFlushIntervalMs`. */
44
+ flushIntervalMs?: number;
45
+ /**
46
+ * Maximum number of events buffered in memory before the oldest is dropped
47
+ * (default: 1000). Bounds memory in long-lived server processes.
48
+ */
49
+ eventMaxQueueSize?: number;
39
50
  /**
40
51
  * Timeout in milliseconds for SDK network requests — the config bundle
41
52
  * fetch and event batch POSTs (default: 10000).
@@ -43,8 +54,27 @@ export interface TrafficalClientOptions extends CoreClientOptions {
43
54
  * On timeout the request is aborted and treated exactly like a network
44
55
  * failure: config fetches fall back to the cached/local config, and event
45
56
  * batches are re-queued for retry.
57
+ *
58
+ * @deprecated Use the per-path options `configTimeoutMs`, `eventsTimeoutMs`,
59
+ * and `resolveTimeoutMs` instead. `requestTimeoutMs` is still honored as the
60
+ * legacy fallback for all three when the specific option is not provided.
46
61
  */
47
62
  requestTimeoutMs?: number;
63
+ /**
64
+ * Timeout in milliseconds for the config-bundle fetch (default: 10000).
65
+ * Falls back to `requestTimeoutMs` when not set.
66
+ */
67
+ configTimeoutMs?: number;
68
+ /**
69
+ * Timeout in milliseconds for event-delivery POSTs (default: 10000).
70
+ * Falls back to `requestTimeoutMs` when not set.
71
+ */
72
+ eventsTimeoutMs?: number;
73
+ /**
74
+ * Timeout in milliseconds for server-resolve requests (POST /v1/resolve,
75
+ * default: 5000). Falls back to `requestTimeoutMs` when not set.
76
+ */
77
+ resolveTimeoutMs?: number;
48
78
  /**
49
79
  * Enable debug logging for events (default: false).
50
80
  */
@@ -70,6 +100,15 @@ export interface TrafficalClientOptions extends CoreClientOptions {
70
100
  * (same unit+policy+variant won't fire again within TTL). Default: true.
71
101
  */
72
102
  deduplicateAssignmentLogger?: boolean;
103
+ /**
104
+ * When true, exposure events are deduplicated per (unit, policy, allocation)
105
+ * within a session via in-memory LRU, mirroring the browser SDK. Default: true.
106
+ */
107
+ deduplicateExposures?: boolean;
108
+ /**
109
+ * Exposure deduplication session TTL in milliseconds (default: 30 minutes).
110
+ */
111
+ exposureSessionTtlMs?: number;
73
112
  /**
74
113
  * Optional callback for routing full events (exposure, track, decision)
75
114
  * to a customer-managed pipeline (e.g. Jitsu, Segment). Fires regardless
@@ -107,21 +146,44 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
107
146
  private readonly _disableCloudEvents;
108
147
  /** In-memory LRU for assignment logger deduplication: key → expiry timestamp */
109
148
  private readonly _assignmentLoggerDedup;
149
+ /** In-memory LRU for exposure-event deduplication: key → expiry timestamp */
150
+ private readonly _exposureDedup;
151
+ /** Session TTL for exposure deduplication (ms) */
152
+ private readonly _exposureSessionTtlMs;
110
153
  /** Cache of recent decisions for attribution lookup on rewards */
111
154
  private readonly _decisionCache;
155
+ /** Serialized context of the last server-mode resolve (per-call throttle). */
156
+ private _lastResolveContextKey;
157
+ /** Resolves once the first config load attempt completes (fail-open). */
158
+ private _readyResolve;
159
+ private readonly _readyPromise;
112
160
  constructor(options: TrafficalClientOptions);
113
161
  /**
114
162
  * Initializes the client by fetching the config bundle.
115
163
  * This is called automatically by createTrafficalClient.
116
164
  */
117
165
  initialize(): Promise<void>;
166
+ /**
167
+ * Resolves once the first usable config has loaded (or the SDK has failed
168
+ * open on an unavailable/malformed bundle). Never rejects.
169
+ */
170
+ waitForReady(): Promise<void>;
171
+ /**
172
+ * Single teardown verb (spec 0.7.0 design contract). Stops background
173
+ * refresh and awaits a final event flush before returning.
174
+ */
175
+ close(): Promise<void>;
118
176
  /**
119
177
  * Stops background refresh and cleans up resources.
178
+ *
179
+ * @deprecated Use {@link close} instead — the canonical single teardown verb.
120
180
  */
121
181
  destroy(): Promise<void>;
122
182
  /**
123
183
  * Synchronous destroy for process exit handlers.
124
- * Use destroy() when possible for proper cleanup.
184
+ *
185
+ * @deprecated Use {@link close} instead. This best-effort variant does not
186
+ * await the final flush; prefer `await close()` where you can.
125
187
  */
126
188
  destroySync(): void;
127
189
  /**
@@ -132,6 +194,17 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
132
194
  * Gets the current config bundle version.
133
195
  */
134
196
  getConfigVersion(): string | null;
197
+ /**
198
+ * Returns the context field the bundle buckets on (the project's unit key),
199
+ * or null before the bundle has loaded. Adapters (e.g. an OpenFeature
200
+ * provider) map their targeting key onto this field.
201
+ */
202
+ getUnitKeyField(): string | null;
203
+ /**
204
+ * Returns the id of the layer a parameter belongs to, or null if the
205
+ * parameter is unknown / the bundle is not yet loaded.
206
+ */
207
+ getParameterLayerId(key: string): string | null;
135
208
  /**
136
209
  * Flush pending events immediately.
137
210
  */
@@ -145,25 +218,29 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
145
218
  * 3. Local config (if remote unavailable)
146
219
  * 4. Caller defaults
147
220
  */
148
- getParams<T extends Record<string, ParameterValue>>(options: {
149
- context: Context;
150
- defaults: T;
151
- }): T;
221
+ getParams<T extends Record<string, ParameterValue>>(context: Context, defaults: T): T;
222
+ /** @deprecated Pass `(context, defaults)` positionally (spec 0.7.0 contract). */
223
+ getParams<T extends Record<string, ParameterValue>>(options: GetParamsOptions<T>): T;
152
224
  /**
153
225
  * Makes a decision with full metadata for tracking.
154
226
  *
155
227
  * When trackDecisions is enabled (default), automatically sends a DecisionEvent
156
228
  * to the backend for intent-to-treat analysis.
157
229
  */
158
- decide<T extends Record<string, ParameterValue>>(options: {
159
- context: Context;
160
- defaults: T;
161
- }): DecisionResult;
230
+ decide<T extends Record<string, ParameterValue>>(context: Context, defaults: T): DecisionResult;
231
+ /** @deprecated Pass `(context, defaults)` positionally (spec 0.7.0 contract). */
232
+ decide<T extends Record<string, ParameterValue>>(options: DecideOptions<T>): DecisionResult;
162
233
  /**
163
- * Tracks an exposure event.
234
+ * Tracks an exposure event — the "user was actually shown this treatment"
235
+ * signal (treatment-on-the-treated).
164
236
  *
165
- * If the decision includes filtered context (from policies with contextLogging),
166
- * it will be included in the exposure event for contextual bandit training.
237
+ * Only layers the caller was actually exposed to are emitted: layers without
238
+ * a policy/allocation and `attributionOnly` layers (resolved for attribution
239
+ * but whose parameters weren't requested) are skipped, and each
240
+ * (unit, policy, allocation) is deduplicated per session so the same exposure
241
+ * isn't emitted twice. Mirrors the browser SDK. If the decision includes
242
+ * filtered context (from policies with contextLogging), it is included in the
243
+ * exposure event for contextual bandit training.
167
244
  */
168
245
  trackExposure(decision: DecisionResult): void;
169
246
  /**
@@ -179,10 +256,7 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
179
256
  * // Track with explicit decision attribution
180
257
  * client.track('checkout_complete', { value: 1 }, { decisionId: 'dec_xyz' });
181
258
  */
182
- track<E extends Extract<keyof TEvents, string>>(event: E, properties?: TEvents[E], options?: {
183
- decisionId?: string;
184
- unitKey?: string;
185
- }): void;
259
+ track<E extends Extract<keyof TEvents, string>>(event: E, properties?: TEvents[E], options?: TrackEventOptions): void;
186
260
  /**
187
261
  * @deprecated Use track() instead.
188
262
  * Tracks a reward event.
@@ -206,8 +280,18 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
206
280
  /**
207
281
  * Logs an offline warning (rate-limited).
208
282
  */
283
+ /**
284
+ * Server mode: threads the per-call context into a background /v1/resolve so
285
+ * the cached snapshot converges to the contexts actually being evaluated.
286
+ * Throttled by serialized context so repeated identical contexts (the common
287
+ * case) don't hammer the edge. Because decide()/getParams() are synchronous
288
+ * they cannot await this; the current call degrades to the last-good snapshot
289
+ * and subsequent calls pick up the refreshed resolution.
290
+ */
291
+ private _maybeResolveForContext;
209
292
  private _fetchServerResolve;
210
293
  private _logOfflineWarning;
294
+ private _logMalformedBundleWarning;
211
295
  /**
212
296
  * Routes a built event to the BYO event logger (if configured) and to the
213
297
  * Traffical edge batcher (unless cloud events are disabled).
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,sBAAsB,IAAI,iBAAiB,EAChD,KAAK,YAAY,EAMjB,KAAK,gBAAgB,EAGrB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EAOtB,MAAM,iBAAiB,CAAC;AAyBzB;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAErC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,oBAAoB,CAAC;IAEnC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAoBD;;;;;;;;;;GAUG;AACH,qBAAa,eAAe,CAAC,OAAO,SAAS,aAAa,GAAG,aAAa;IACxE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CASvB;IAEF,OAAO,CAAC,MAAM,CAQZ;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuB;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAuB;IACxD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAU;IAC9C,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6B;IACpE,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0C;gBAE7D,OAAO,EAAE,sBAAsB;IAqE3C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;;OAGG;IACH,WAAW,IAAI,IAAI;IASnB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC;;OAEG;IACH,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC;;;;;;;;OAQG;IACH,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,CAAC,CAAA;KAAE,GAAG,CAAC;IAgBlG;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,CAAC,CAAA;KAAE,GAAG,cAAc;IAwC5G;;;;;OAKG;IACH,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IA4B7C;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,OAAO,EAAE,MAAM,CAAC,EAC5C,KAAK,EAAE,CAAC,EACR,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,IAAI;IA0BP;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAWxC,OAAO,CAAC,yBAAyB;IA4CjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;OAGG;YACW,YAAY;IAgD1B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqB/B;;OAEG;YACW,mBAAmB;IAYjC,OAAO,CAAC,kBAAkB;IAU1B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAatB;;;OAGG;IACH,OAAO,CAAC,cAAc;IA0CtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,wBAAwB;CAoBjC;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,SAAS,aAAa,GAAG,aAAa,EACvF,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAInC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,SAAS,aAAa,GAAG,aAAa,EACrF,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,OAAO,CAAC,CAE1B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}