@traffical/node 0.8.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 +16 -6
- package/dist/assignment-logger.test.js +10 -1
- package/dist/assignment-logger.test.js.map +1 -1
- package/dist/canonical-options.test.d.ts +2 -0
- package/dist/canonical-options.test.d.ts.map +1 -0
- package/dist/canonical-options.test.js +167 -0
- package/dist/canonical-options.test.js.map +1 -0
- package/dist/client.d.ts +111 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +280 -50
- package/dist/client.js.map +1 -1
- package/dist/contract-0.7.0.test.d.ts +2 -0
- package/dist/contract-0.7.0.test.d.ts.map +1 -0
- package/dist/contract-0.7.0.test.js +171 -0
- package/dist/contract-0.7.0.test.js.map +1 -0
- package/dist/event-batcher.d.ts +58 -2
- package/dist/event-batcher.d.ts.map +1 -1
- package/dist/event-batcher.js +157 -23
- package/dist/event-batcher.js.map +1 -1
- package/dist/event-batcher.test.js +66 -0
- package/dist/event-batcher.test.js.map +1 -1
- package/dist/event-logger.test.js +63 -3
- package/dist/event-logger.test.js.map +1 -1
- package/dist/malformed-bundle.test.d.ts +12 -0
- package/dist/malformed-bundle.test.d.ts.map +1 -0
- package/dist/malformed-bundle.test.js +110 -0
- package/dist/malformed-bundle.test.js.map +1 -0
- package/dist/track-exposure.test.d.ts +12 -0
- package/dist/track-exposure.test.d.ts.map +1 -0
- package/dist/track-exposure.test.js +112 -0
- package/dist/track-exposure.test.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +5 -5
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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:
|
|
110
|
-
|
|
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
|
-
|
|
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;
|
|
1
|
+
{"version":3,"file":"assignment-logger.test.js","sourceRoot":"","sources":["../src/assignment-logger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,51 @@ 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;
|
|
50
|
+
/**
|
|
51
|
+
* Timeout in milliseconds for SDK network requests — the config bundle
|
|
52
|
+
* fetch and event batch POSTs (default: 10000).
|
|
53
|
+
*
|
|
54
|
+
* On timeout the request is aborted and treated exactly like a network
|
|
55
|
+
* failure: config fetches fall back to the cached/local config, and event
|
|
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.
|
|
61
|
+
*/
|
|
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;
|
|
39
78
|
/**
|
|
40
79
|
* Enable debug logging for events (default: false).
|
|
41
80
|
*/
|
|
@@ -61,6 +100,15 @@ export interface TrafficalClientOptions extends CoreClientOptions {
|
|
|
61
100
|
* (same unit+policy+variant won't fire again within TTL). Default: true.
|
|
62
101
|
*/
|
|
63
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;
|
|
64
112
|
/**
|
|
65
113
|
* Optional callback for routing full events (exposure, track, decision)
|
|
66
114
|
* to a customer-managed pipeline (e.g. Jitsu, Segment). Fires regardless
|
|
@@ -90,6 +138,7 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
90
138
|
private readonly _options;
|
|
91
139
|
private _state;
|
|
92
140
|
private readonly _eventBatcher;
|
|
141
|
+
private readonly _requestTimeoutMs;
|
|
93
142
|
private readonly _decisionDedup;
|
|
94
143
|
private readonly _decisionClient;
|
|
95
144
|
private readonly _assignmentLogger?;
|
|
@@ -97,21 +146,44 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
97
146
|
private readonly _disableCloudEvents;
|
|
98
147
|
/** In-memory LRU for assignment logger deduplication: key → expiry timestamp */
|
|
99
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;
|
|
100
153
|
/** Cache of recent decisions for attribution lookup on rewards */
|
|
101
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;
|
|
102
160
|
constructor(options: TrafficalClientOptions);
|
|
103
161
|
/**
|
|
104
162
|
* Initializes the client by fetching the config bundle.
|
|
105
163
|
* This is called automatically by createTrafficalClient.
|
|
106
164
|
*/
|
|
107
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>;
|
|
108
176
|
/**
|
|
109
177
|
* Stops background refresh and cleans up resources.
|
|
178
|
+
*
|
|
179
|
+
* @deprecated Use {@link close} instead — the canonical single teardown verb.
|
|
110
180
|
*/
|
|
111
181
|
destroy(): Promise<void>;
|
|
112
182
|
/**
|
|
113
183
|
* Synchronous destroy for process exit handlers.
|
|
114
|
-
*
|
|
184
|
+
*
|
|
185
|
+
* @deprecated Use {@link close} instead. This best-effort variant does not
|
|
186
|
+
* await the final flush; prefer `await close()` where you can.
|
|
115
187
|
*/
|
|
116
188
|
destroySync(): void;
|
|
117
189
|
/**
|
|
@@ -122,6 +194,17 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
122
194
|
* Gets the current config bundle version.
|
|
123
195
|
*/
|
|
124
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;
|
|
125
208
|
/**
|
|
126
209
|
* Flush pending events immediately.
|
|
127
210
|
*/
|
|
@@ -135,25 +218,29 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
135
218
|
* 3. Local config (if remote unavailable)
|
|
136
219
|
* 4. Caller defaults
|
|
137
220
|
*/
|
|
138
|
-
getParams<T extends Record<string, ParameterValue>>(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}): 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;
|
|
142
224
|
/**
|
|
143
225
|
* Makes a decision with full metadata for tracking.
|
|
144
226
|
*
|
|
145
227
|
* When trackDecisions is enabled (default), automatically sends a DecisionEvent
|
|
146
228
|
* to the backend for intent-to-treat analysis.
|
|
147
229
|
*/
|
|
148
|
-
decide<T extends Record<string, ParameterValue>>(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}): 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;
|
|
152
233
|
/**
|
|
153
|
-
* Tracks an exposure event
|
|
234
|
+
* Tracks an exposure event — the "user was actually shown this treatment"
|
|
235
|
+
* signal (treatment-on-the-treated).
|
|
154
236
|
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
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.
|
|
157
244
|
*/
|
|
158
245
|
trackExposure(decision: DecisionResult): void;
|
|
159
246
|
/**
|
|
@@ -169,10 +256,7 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
169
256
|
* // Track with explicit decision attribution
|
|
170
257
|
* client.track('checkout_complete', { value: 1 }, { decisionId: 'dec_xyz' });
|
|
171
258
|
*/
|
|
172
|
-
track<E extends Extract<keyof TEvents, string>>(event: E, properties?: TEvents[E], options?:
|
|
173
|
-
decisionId?: string;
|
|
174
|
-
unitKey?: string;
|
|
175
|
-
}): void;
|
|
259
|
+
track<E extends Extract<keyof TEvents, string>>(event: E, properties?: TEvents[E], options?: TrackEventOptions): void;
|
|
176
260
|
/**
|
|
177
261
|
* @deprecated Use track() instead.
|
|
178
262
|
* Tracks a reward event.
|
|
@@ -196,8 +280,18 @@ export declare class TrafficalClient<TEvents extends TrackEventMap = TrackEventM
|
|
|
196
280
|
/**
|
|
197
281
|
* Logs an offline warning (rate-limited).
|
|
198
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;
|
|
199
292
|
private _fetchServerResolve;
|
|
200
293
|
private _logOfflineWarning;
|
|
294
|
+
private _logMalformedBundleWarning;
|
|
201
295
|
/**
|
|
202
296
|
* Routes a built event to the BYO event logger (if configured) and to the
|
|
203
297
|
* Traffical edge batcher (unless cloud events are disabled).
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|