@avsbhq/node 0.3.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +345 -145
- package/dist/index.cjs +827 -339
- package/dist/index.d.cts +112 -107
- package/dist/index.d.ts +112 -107
- package/dist/index.js +832 -337
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { FlagDatafile } from '@avsbhq/
|
|
2
|
-
export { ExposureEvent, FlagDatafile, FlagEvaluationDetails, MetricEvent } from '@avsbhq/
|
|
1
|
+
import { FlagDatafile, StickyBucketService, Logger, EvaluationSource, StickyAssignment, DecideOption, Flag, TrackPayload, DecisionLog, InitResult, EvalContext } from '@avsbhq/core';
|
|
2
|
+
export { DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
|
|
3
|
+
import { AvsbUtils } from '@avsbhq/utils';
|
|
4
|
+
export { AvsbUtils } from '@avsbhq/utils';
|
|
3
5
|
|
|
4
|
-
interface
|
|
6
|
+
interface AvsbServerOptions {
|
|
5
7
|
/** SDK key for the flag environment (e.g., "env_abc123") */
|
|
6
8
|
sdkKey: string;
|
|
7
9
|
/** Datafile polling interval in ms. Default: 60_000 (60s). Min: 5_000. */
|
|
@@ -33,67 +35,6 @@ interface EventOptions {
|
|
|
33
35
|
/** Retry attempts on flush failure. Default: 3. */
|
|
34
36
|
retryAttempts?: number;
|
|
35
37
|
}
|
|
36
|
-
interface UserContext {
|
|
37
|
-
/** User identifier for bucketing. Required. */
|
|
38
|
-
userId: string;
|
|
39
|
-
/** Targeting attributes (plan, country, device, etc.). */
|
|
40
|
-
attributes?: Record<string, unknown>;
|
|
41
|
-
/** When true, evaluate without firing an exposure event. Default: false. */
|
|
42
|
-
suppressExposure?: boolean;
|
|
43
|
-
/** Collect evaluation details into this log. */
|
|
44
|
-
decisionLog?: DecisionLog;
|
|
45
|
-
/** Attribute keys to strip from event payloads (used for targeting, not sent to analytics). */
|
|
46
|
-
privateAttributes?: string[];
|
|
47
|
-
}
|
|
48
|
-
interface TrackContext {
|
|
49
|
-
/** User identifier. Required. */
|
|
50
|
-
userId: string;
|
|
51
|
-
/** Revenue value for conversion tracking. */
|
|
52
|
-
revenue?: number;
|
|
53
|
-
/** Custom event properties. */
|
|
54
|
-
properties?: Record<string, unknown>;
|
|
55
|
-
}
|
|
56
|
-
interface DecisionLog {
|
|
57
|
-
readonly entries: DecisionLogEntry[];
|
|
58
|
-
}
|
|
59
|
-
interface DecisionLogEntry {
|
|
60
|
-
flagKey: string;
|
|
61
|
-
value: unknown;
|
|
62
|
-
variationKey: string | null;
|
|
63
|
-
source: EvaluationSource;
|
|
64
|
-
ruleId: string | null;
|
|
65
|
-
ruleType: 'targeted_delivery' | 'ab_test' | null;
|
|
66
|
-
reasons: string[];
|
|
67
|
-
evaluatedAt: number;
|
|
68
|
-
durationMs: number;
|
|
69
|
-
}
|
|
70
|
-
type EvaluationSource = 'override' | 'sticky' | 'rule' | 'default' | 'not_found' | 'disabled' | 'runtime_override';
|
|
71
|
-
interface ServerFlagEvaluationDetails {
|
|
72
|
-
value: unknown;
|
|
73
|
-
variationKey: string | null;
|
|
74
|
-
source: EvaluationSource;
|
|
75
|
-
ruleId: string | null;
|
|
76
|
-
ruleType: 'targeted_delivery' | 'ab_test' | null;
|
|
77
|
-
flagKey: string;
|
|
78
|
-
reasons: string[];
|
|
79
|
-
}
|
|
80
|
-
interface InitResult {
|
|
81
|
-
success: boolean;
|
|
82
|
-
source: 'network' | 'bootstrap' | 'cache' | 'timeout' | 'error';
|
|
83
|
-
error?: Error;
|
|
84
|
-
}
|
|
85
|
-
interface StickyBucketService {
|
|
86
|
-
/** Look up stored variation for a user+flag. Return variationId or null. Synchronous. */
|
|
87
|
-
lookup(userId: string, flagKey: string): string | null;
|
|
88
|
-
/** Persist a variation assignment. Fire-and-forget (may be async internally). */
|
|
89
|
-
save(userId: string, flagKey: string, variationId: string): void;
|
|
90
|
-
}
|
|
91
|
-
interface Logger {
|
|
92
|
-
debug(message: string, data?: Record<string, unknown>): void;
|
|
93
|
-
info(message: string, data?: Record<string, unknown>): void;
|
|
94
|
-
warn(message: string, data?: Record<string, unknown>): void;
|
|
95
|
-
error(message: string, data?: Record<string, unknown>): void;
|
|
96
|
-
}
|
|
97
38
|
type ServerEventMap = {
|
|
98
39
|
ready: () => void;
|
|
99
40
|
configUpdate: (data: {
|
|
@@ -106,6 +47,12 @@ type ServerEventMap = {
|
|
|
106
47
|
source: EvaluationSource;
|
|
107
48
|
}) => void;
|
|
108
49
|
error: (error: Error) => void;
|
|
50
|
+
/** Fired when a sticky assignment references a rule that no longer matches the datafile. */
|
|
51
|
+
stickyOrphan: (data: {
|
|
52
|
+
flagKey: string;
|
|
53
|
+
userId: string;
|
|
54
|
+
assignment: StickyAssignment;
|
|
55
|
+
}) => void;
|
|
109
56
|
};
|
|
110
57
|
type ServerEventName = keyof ServerEventMap;
|
|
111
58
|
interface MiddlewareConfig {
|
|
@@ -114,26 +61,57 @@ interface MiddlewareConfig {
|
|
|
114
61
|
/** Extract targeting attributes from the request. */
|
|
115
62
|
attributesFrom?: (req: unknown) => Record<string, unknown>;
|
|
116
63
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A per-request scoped client with a bound EvalContext.
|
|
67
|
+
*
|
|
68
|
+
* Created via `server.forUser(ctx)` or the `server.createUserContext(ctx)`
|
|
69
|
+
* alias. All flag evaluations and track calls use the bound context.
|
|
70
|
+
*
|
|
71
|
+
* Forced decisions set on a UserBoundClient survive only for the lifetime
|
|
72
|
+
* of the instance — they do not affect the shared AvsbServer override state.
|
|
73
|
+
* This makes them safe for test middleware and per-request debugging.
|
|
74
|
+
*
|
|
75
|
+
* Spec §5.8.
|
|
76
|
+
*/
|
|
77
|
+
interface UserBoundClient {
|
|
78
|
+
getFlag<T>(flagKey: string, defaultValue: T, options?: {
|
|
79
|
+
decideOptions?: DecideOption[];
|
|
80
|
+
}): Flag<T>;
|
|
81
|
+
getBoolFlag(flagKey: string, defaultValue: boolean, options?: {
|
|
82
|
+
decideOptions?: DecideOption[];
|
|
83
|
+
}): Flag<boolean>;
|
|
84
|
+
getStringFlag(flagKey: string, defaultValue: string, options?: {
|
|
85
|
+
decideOptions?: DecideOption[];
|
|
86
|
+
}): Flag<string>;
|
|
87
|
+
getNumberFlag(flagKey: string, defaultValue: number, options?: {
|
|
88
|
+
decideOptions?: DecideOption[];
|
|
89
|
+
}): Flag<number>;
|
|
90
|
+
getJsonFlag<T>(flagKey: string, defaultValue: T, options?: {
|
|
91
|
+
decideOptions?: DecideOption[];
|
|
92
|
+
}): Flag<T>;
|
|
93
|
+
getAllFlags(options?: GetAllFlagsOptions): Record<string, Flag>;
|
|
94
|
+
track(eventKey: string, payload?: Omit<TrackPayload, 'context'>): void;
|
|
95
|
+
setForcedDecision(flagKey: string, opts: {
|
|
96
|
+
ruleId?: string;
|
|
97
|
+
variationKey: string;
|
|
128
98
|
}): void;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
flagKey: string;
|
|
132
|
-
variationKey: string;
|
|
133
|
-
userId?: string;
|
|
99
|
+
clearForcedDecision(flagKey: string): void;
|
|
100
|
+
getDecisionLog(): DecisionLog;
|
|
134
101
|
}
|
|
135
102
|
|
|
136
|
-
|
|
103
|
+
interface GetFlagOptions {
|
|
104
|
+
context?: EvalContext;
|
|
105
|
+
decideOptions?: DecideOption[];
|
|
106
|
+
decisionLog?: DecisionLog;
|
|
107
|
+
/** Internal: UserBoundClient forced decision override. */
|
|
108
|
+
forcedVariationKey?: string;
|
|
109
|
+
}
|
|
110
|
+
interface GetAllFlagsOptions {
|
|
111
|
+
fireExposures?: boolean;
|
|
112
|
+
decideOptions?: DecideOption[];
|
|
113
|
+
}
|
|
114
|
+
declare class AvsbServer {
|
|
137
115
|
private sdkKey;
|
|
138
116
|
private pollingInterval;
|
|
139
117
|
private cdnHost;
|
|
@@ -141,57 +119,87 @@ declare class AvsBServer {
|
|
|
141
119
|
private logger;
|
|
142
120
|
private stickyBucketService;
|
|
143
121
|
private eventOptions;
|
|
122
|
+
private streamingEnabled;
|
|
123
|
+
private streamingEndpoint;
|
|
144
124
|
private datafile;
|
|
145
125
|
private ready;
|
|
146
126
|
private destroyed;
|
|
147
127
|
private tracker;
|
|
128
|
+
private streamingClient;
|
|
148
129
|
private pollingId;
|
|
130
|
+
private abortController;
|
|
149
131
|
private overrides;
|
|
150
132
|
private listeners;
|
|
151
133
|
private readyPromise;
|
|
152
|
-
|
|
134
|
+
private pendingEvents;
|
|
135
|
+
/**
|
|
136
|
+
* §6 — `client.utils.*` surface. Constructed lazily on first access so
|
|
137
|
+
* the utils package is only imported when actually consumed.
|
|
138
|
+
*
|
|
139
|
+
* The server's event surface (`ServerEventMap`) is a subset of the
|
|
140
|
+
* shared `ClientEventMap`; the utils-adapter `on` here ignores events
|
|
141
|
+
* the server doesn't emit (e.g. `flagChange`). Workstream 5 (CoW 6)
|
|
142
|
+
* harmonises the two maps when the streaming evaluator lands.
|
|
143
|
+
*/
|
|
144
|
+
private _utils;
|
|
145
|
+
get utils(): AvsbUtils;
|
|
146
|
+
constructor(options: AvsbServerOptions);
|
|
153
147
|
onReady(): Promise<InitResult>;
|
|
154
148
|
private initializeAndReady;
|
|
155
149
|
close(): Promise<void>;
|
|
156
150
|
flush(): Promise<void>;
|
|
157
151
|
refreshDatafile(): Promise<void>;
|
|
158
|
-
getFlag<T
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
getFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
|
|
153
|
+
getBoolFlag(flagKey: string, defaultValue: NoInfer<boolean> | boolean, options?: GetFlagOptions): Flag<boolean>;
|
|
154
|
+
getStringFlag(flagKey: string, defaultValue: NoInfer<string> | string, options?: GetFlagOptions): Flag<string>;
|
|
155
|
+
getNumberFlag(flagKey: string, defaultValue: NoInfer<number> | number, options?: GetFlagOptions): Flag<number>;
|
|
156
|
+
getJsonFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
|
|
157
|
+
getAllFlags(context: EvalContext, options?: GetAllFlagsOptions): Record<string, Flag>;
|
|
158
|
+
track(eventKey: string, payload: TrackPayload & {
|
|
159
|
+
context: EvalContext;
|
|
164
160
|
}): void;
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
manualExposure(flagKey: string, context: EvalContext): void;
|
|
162
|
+
forUser(context: EvalContext): UserBoundClient;
|
|
163
|
+
createUserContext(context: EvalContext): UserBoundClient;
|
|
164
|
+
setOverrideForUser(flagKey: string, contextKey: string, variationKey: string, contextKind?: string): void;
|
|
165
|
+
setGlobalOverride(flagKey: string, variationKey: string): void;
|
|
166
|
+
clearOverrideForUser(flagKey: string, contextKey: string, contextKind?: string): void;
|
|
167
|
+
clearGlobalOverride(flagKey: string): void;
|
|
167
168
|
clearAllOverrides(): void;
|
|
168
169
|
createDecisionLog(): DecisionLog;
|
|
169
|
-
on<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): void;
|
|
170
|
+
on<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): () => void;
|
|
170
171
|
off<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): void;
|
|
171
172
|
private evaluate;
|
|
173
|
+
private getTypedFlag;
|
|
174
|
+
private toFlag;
|
|
175
|
+
/** toFlag variant that never writes a decision log (used by getAllFlags suppressed path). */
|
|
176
|
+
private toFlagNoLog;
|
|
177
|
+
/** Build a Flag<T> from a forced variation key (per-request override). */
|
|
178
|
+
private buildFlagFromVariationKey;
|
|
179
|
+
private buildLegacyContext;
|
|
180
|
+
private resolveRuntimeOverride;
|
|
181
|
+
private resolveStickyBucket;
|
|
182
|
+
private findVariation;
|
|
183
|
+
private fireExposureForStickyAssignment;
|
|
172
184
|
private emit;
|
|
185
|
+
private emitEvaluation;
|
|
173
186
|
private initTracker;
|
|
187
|
+
private startStreamingIfEnabled;
|
|
174
188
|
private fetchDatafile;
|
|
175
189
|
private startPolling;
|
|
176
190
|
private sendHeartbeat;
|
|
177
|
-
private resolveRuntimeOverride;
|
|
178
|
-
private resolveStickyBucket;
|
|
179
|
-
private findVariation;
|
|
180
|
-
private fireExposureForVariation;
|
|
181
|
-
private recordDecisionLog;
|
|
182
|
-
private emitEvaluation;
|
|
183
191
|
}
|
|
184
192
|
|
|
185
|
-
declare function expressMiddleware(client:
|
|
193
|
+
declare function expressMiddleware(client: AvsbServer, config: MiddlewareConfig): (req: unknown, res: unknown, next: () => void) => void;
|
|
186
194
|
declare function fastifyPlugin(instance: unknown, opts: {
|
|
187
|
-
client:
|
|
195
|
+
client: AvsbServer;
|
|
188
196
|
} & MiddlewareConfig, done: () => void): void;
|
|
189
197
|
|
|
190
198
|
declare class InMemoryStickyBucketService implements StickyBucketService {
|
|
191
199
|
private cache;
|
|
192
200
|
private key;
|
|
193
|
-
lookup(userId: string, flagKey: string):
|
|
194
|
-
save(userId: string, flagKey: string,
|
|
201
|
+
lookup(userId: string, flagKey: string): StickyAssignment | null;
|
|
202
|
+
save(userId: string, flagKey: string, assignment: StickyAssignment): void;
|
|
195
203
|
}
|
|
196
204
|
interface RedisLike {
|
|
197
205
|
get(key: string): Promise<string | null>;
|
|
@@ -216,8 +224,8 @@ declare class RedisStickyBucketService implements StickyBucketService {
|
|
|
216
224
|
constructor(options: RedisStickyBucketOptions);
|
|
217
225
|
private redisKey;
|
|
218
226
|
private cacheKey;
|
|
219
|
-
lookup(userId: string, flagKey: string):
|
|
220
|
-
save(userId: string, flagKey: string,
|
|
227
|
+
lookup(userId: string, flagKey: string): StickyAssignment | null;
|
|
228
|
+
save(userId: string, flagKey: string, assignment: StickyAssignment): void;
|
|
221
229
|
private backgroundFetch;
|
|
222
230
|
private evictIfNeeded;
|
|
223
231
|
}
|
|
@@ -238,9 +246,6 @@ declare function createStreamingClient(options: StreamingOptions): StreamingClie
|
|
|
238
246
|
|
|
239
247
|
declare function createDecisionLog(): DecisionLog;
|
|
240
248
|
|
|
241
|
-
/** No-op logger — used when no custom logger is provided. */
|
|
242
|
-
declare const noopLogger: Logger;
|
|
243
|
-
|
|
244
249
|
declare const SDK_VERSION = "0.3.0";
|
|
245
250
|
|
|
246
|
-
export {
|
|
251
|
+
export { AvsbServer, type AvsbServerOptions, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type StreamingClient, type StreamingOptions, type UserBoundClient, createDecisionLog, createStreamingClient, expressMiddleware, fastifyPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { FlagDatafile } from '@avsbhq/
|
|
2
|
-
export { ExposureEvent, FlagDatafile, FlagEvaluationDetails, MetricEvent } from '@avsbhq/
|
|
1
|
+
import { FlagDatafile, StickyBucketService, Logger, EvaluationSource, StickyAssignment, DecideOption, Flag, TrackPayload, DecisionLog, InitResult, EvalContext } from '@avsbhq/core';
|
|
2
|
+
export { DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
|
|
3
|
+
import { AvsbUtils } from '@avsbhq/utils';
|
|
4
|
+
export { AvsbUtils } from '@avsbhq/utils';
|
|
3
5
|
|
|
4
|
-
interface
|
|
6
|
+
interface AvsbServerOptions {
|
|
5
7
|
/** SDK key for the flag environment (e.g., "env_abc123") */
|
|
6
8
|
sdkKey: string;
|
|
7
9
|
/** Datafile polling interval in ms. Default: 60_000 (60s). Min: 5_000. */
|
|
@@ -33,67 +35,6 @@ interface EventOptions {
|
|
|
33
35
|
/** Retry attempts on flush failure. Default: 3. */
|
|
34
36
|
retryAttempts?: number;
|
|
35
37
|
}
|
|
36
|
-
interface UserContext {
|
|
37
|
-
/** User identifier for bucketing. Required. */
|
|
38
|
-
userId: string;
|
|
39
|
-
/** Targeting attributes (plan, country, device, etc.). */
|
|
40
|
-
attributes?: Record<string, unknown>;
|
|
41
|
-
/** When true, evaluate without firing an exposure event. Default: false. */
|
|
42
|
-
suppressExposure?: boolean;
|
|
43
|
-
/** Collect evaluation details into this log. */
|
|
44
|
-
decisionLog?: DecisionLog;
|
|
45
|
-
/** Attribute keys to strip from event payloads (used for targeting, not sent to analytics). */
|
|
46
|
-
privateAttributes?: string[];
|
|
47
|
-
}
|
|
48
|
-
interface TrackContext {
|
|
49
|
-
/** User identifier. Required. */
|
|
50
|
-
userId: string;
|
|
51
|
-
/** Revenue value for conversion tracking. */
|
|
52
|
-
revenue?: number;
|
|
53
|
-
/** Custom event properties. */
|
|
54
|
-
properties?: Record<string, unknown>;
|
|
55
|
-
}
|
|
56
|
-
interface DecisionLog {
|
|
57
|
-
readonly entries: DecisionLogEntry[];
|
|
58
|
-
}
|
|
59
|
-
interface DecisionLogEntry {
|
|
60
|
-
flagKey: string;
|
|
61
|
-
value: unknown;
|
|
62
|
-
variationKey: string | null;
|
|
63
|
-
source: EvaluationSource;
|
|
64
|
-
ruleId: string | null;
|
|
65
|
-
ruleType: 'targeted_delivery' | 'ab_test' | null;
|
|
66
|
-
reasons: string[];
|
|
67
|
-
evaluatedAt: number;
|
|
68
|
-
durationMs: number;
|
|
69
|
-
}
|
|
70
|
-
type EvaluationSource = 'override' | 'sticky' | 'rule' | 'default' | 'not_found' | 'disabled' | 'runtime_override';
|
|
71
|
-
interface ServerFlagEvaluationDetails {
|
|
72
|
-
value: unknown;
|
|
73
|
-
variationKey: string | null;
|
|
74
|
-
source: EvaluationSource;
|
|
75
|
-
ruleId: string | null;
|
|
76
|
-
ruleType: 'targeted_delivery' | 'ab_test' | null;
|
|
77
|
-
flagKey: string;
|
|
78
|
-
reasons: string[];
|
|
79
|
-
}
|
|
80
|
-
interface InitResult {
|
|
81
|
-
success: boolean;
|
|
82
|
-
source: 'network' | 'bootstrap' | 'cache' | 'timeout' | 'error';
|
|
83
|
-
error?: Error;
|
|
84
|
-
}
|
|
85
|
-
interface StickyBucketService {
|
|
86
|
-
/** Look up stored variation for a user+flag. Return variationId or null. Synchronous. */
|
|
87
|
-
lookup(userId: string, flagKey: string): string | null;
|
|
88
|
-
/** Persist a variation assignment. Fire-and-forget (may be async internally). */
|
|
89
|
-
save(userId: string, flagKey: string, variationId: string): void;
|
|
90
|
-
}
|
|
91
|
-
interface Logger {
|
|
92
|
-
debug(message: string, data?: Record<string, unknown>): void;
|
|
93
|
-
info(message: string, data?: Record<string, unknown>): void;
|
|
94
|
-
warn(message: string, data?: Record<string, unknown>): void;
|
|
95
|
-
error(message: string, data?: Record<string, unknown>): void;
|
|
96
|
-
}
|
|
97
38
|
type ServerEventMap = {
|
|
98
39
|
ready: () => void;
|
|
99
40
|
configUpdate: (data: {
|
|
@@ -106,6 +47,12 @@ type ServerEventMap = {
|
|
|
106
47
|
source: EvaluationSource;
|
|
107
48
|
}) => void;
|
|
108
49
|
error: (error: Error) => void;
|
|
50
|
+
/** Fired when a sticky assignment references a rule that no longer matches the datafile. */
|
|
51
|
+
stickyOrphan: (data: {
|
|
52
|
+
flagKey: string;
|
|
53
|
+
userId: string;
|
|
54
|
+
assignment: StickyAssignment;
|
|
55
|
+
}) => void;
|
|
109
56
|
};
|
|
110
57
|
type ServerEventName = keyof ServerEventMap;
|
|
111
58
|
interface MiddlewareConfig {
|
|
@@ -114,26 +61,57 @@ interface MiddlewareConfig {
|
|
|
114
61
|
/** Extract targeting attributes from the request. */
|
|
115
62
|
attributesFrom?: (req: unknown) => Record<string, unknown>;
|
|
116
63
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A per-request scoped client with a bound EvalContext.
|
|
67
|
+
*
|
|
68
|
+
* Created via `server.forUser(ctx)` or the `server.createUserContext(ctx)`
|
|
69
|
+
* alias. All flag evaluations and track calls use the bound context.
|
|
70
|
+
*
|
|
71
|
+
* Forced decisions set on a UserBoundClient survive only for the lifetime
|
|
72
|
+
* of the instance — they do not affect the shared AvsbServer override state.
|
|
73
|
+
* This makes them safe for test middleware and per-request debugging.
|
|
74
|
+
*
|
|
75
|
+
* Spec §5.8.
|
|
76
|
+
*/
|
|
77
|
+
interface UserBoundClient {
|
|
78
|
+
getFlag<T>(flagKey: string, defaultValue: T, options?: {
|
|
79
|
+
decideOptions?: DecideOption[];
|
|
80
|
+
}): Flag<T>;
|
|
81
|
+
getBoolFlag(flagKey: string, defaultValue: boolean, options?: {
|
|
82
|
+
decideOptions?: DecideOption[];
|
|
83
|
+
}): Flag<boolean>;
|
|
84
|
+
getStringFlag(flagKey: string, defaultValue: string, options?: {
|
|
85
|
+
decideOptions?: DecideOption[];
|
|
86
|
+
}): Flag<string>;
|
|
87
|
+
getNumberFlag(flagKey: string, defaultValue: number, options?: {
|
|
88
|
+
decideOptions?: DecideOption[];
|
|
89
|
+
}): Flag<number>;
|
|
90
|
+
getJsonFlag<T>(flagKey: string, defaultValue: T, options?: {
|
|
91
|
+
decideOptions?: DecideOption[];
|
|
92
|
+
}): Flag<T>;
|
|
93
|
+
getAllFlags(options?: GetAllFlagsOptions): Record<string, Flag>;
|
|
94
|
+
track(eventKey: string, payload?: Omit<TrackPayload, 'context'>): void;
|
|
95
|
+
setForcedDecision(flagKey: string, opts: {
|
|
96
|
+
ruleId?: string;
|
|
97
|
+
variationKey: string;
|
|
128
98
|
}): void;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
flagKey: string;
|
|
132
|
-
variationKey: string;
|
|
133
|
-
userId?: string;
|
|
99
|
+
clearForcedDecision(flagKey: string): void;
|
|
100
|
+
getDecisionLog(): DecisionLog;
|
|
134
101
|
}
|
|
135
102
|
|
|
136
|
-
|
|
103
|
+
interface GetFlagOptions {
|
|
104
|
+
context?: EvalContext;
|
|
105
|
+
decideOptions?: DecideOption[];
|
|
106
|
+
decisionLog?: DecisionLog;
|
|
107
|
+
/** Internal: UserBoundClient forced decision override. */
|
|
108
|
+
forcedVariationKey?: string;
|
|
109
|
+
}
|
|
110
|
+
interface GetAllFlagsOptions {
|
|
111
|
+
fireExposures?: boolean;
|
|
112
|
+
decideOptions?: DecideOption[];
|
|
113
|
+
}
|
|
114
|
+
declare class AvsbServer {
|
|
137
115
|
private sdkKey;
|
|
138
116
|
private pollingInterval;
|
|
139
117
|
private cdnHost;
|
|
@@ -141,57 +119,87 @@ declare class AvsBServer {
|
|
|
141
119
|
private logger;
|
|
142
120
|
private stickyBucketService;
|
|
143
121
|
private eventOptions;
|
|
122
|
+
private streamingEnabled;
|
|
123
|
+
private streamingEndpoint;
|
|
144
124
|
private datafile;
|
|
145
125
|
private ready;
|
|
146
126
|
private destroyed;
|
|
147
127
|
private tracker;
|
|
128
|
+
private streamingClient;
|
|
148
129
|
private pollingId;
|
|
130
|
+
private abortController;
|
|
149
131
|
private overrides;
|
|
150
132
|
private listeners;
|
|
151
133
|
private readyPromise;
|
|
152
|
-
|
|
134
|
+
private pendingEvents;
|
|
135
|
+
/**
|
|
136
|
+
* §6 — `client.utils.*` surface. Constructed lazily on first access so
|
|
137
|
+
* the utils package is only imported when actually consumed.
|
|
138
|
+
*
|
|
139
|
+
* The server's event surface (`ServerEventMap`) is a subset of the
|
|
140
|
+
* shared `ClientEventMap`; the utils-adapter `on` here ignores events
|
|
141
|
+
* the server doesn't emit (e.g. `flagChange`). Workstream 5 (CoW 6)
|
|
142
|
+
* harmonises the two maps when the streaming evaluator lands.
|
|
143
|
+
*/
|
|
144
|
+
private _utils;
|
|
145
|
+
get utils(): AvsbUtils;
|
|
146
|
+
constructor(options: AvsbServerOptions);
|
|
153
147
|
onReady(): Promise<InitResult>;
|
|
154
148
|
private initializeAndReady;
|
|
155
149
|
close(): Promise<void>;
|
|
156
150
|
flush(): Promise<void>;
|
|
157
151
|
refreshDatafile(): Promise<void>;
|
|
158
|
-
getFlag<T
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
getFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
|
|
153
|
+
getBoolFlag(flagKey: string, defaultValue: NoInfer<boolean> | boolean, options?: GetFlagOptions): Flag<boolean>;
|
|
154
|
+
getStringFlag(flagKey: string, defaultValue: NoInfer<string> | string, options?: GetFlagOptions): Flag<string>;
|
|
155
|
+
getNumberFlag(flagKey: string, defaultValue: NoInfer<number> | number, options?: GetFlagOptions): Flag<number>;
|
|
156
|
+
getJsonFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
|
|
157
|
+
getAllFlags(context: EvalContext, options?: GetAllFlagsOptions): Record<string, Flag>;
|
|
158
|
+
track(eventKey: string, payload: TrackPayload & {
|
|
159
|
+
context: EvalContext;
|
|
164
160
|
}): void;
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
manualExposure(flagKey: string, context: EvalContext): void;
|
|
162
|
+
forUser(context: EvalContext): UserBoundClient;
|
|
163
|
+
createUserContext(context: EvalContext): UserBoundClient;
|
|
164
|
+
setOverrideForUser(flagKey: string, contextKey: string, variationKey: string, contextKind?: string): void;
|
|
165
|
+
setGlobalOverride(flagKey: string, variationKey: string): void;
|
|
166
|
+
clearOverrideForUser(flagKey: string, contextKey: string, contextKind?: string): void;
|
|
167
|
+
clearGlobalOverride(flagKey: string): void;
|
|
167
168
|
clearAllOverrides(): void;
|
|
168
169
|
createDecisionLog(): DecisionLog;
|
|
169
|
-
on<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): void;
|
|
170
|
+
on<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): () => void;
|
|
170
171
|
off<E extends ServerEventName>(event: E, cb: ServerEventMap[E]): void;
|
|
171
172
|
private evaluate;
|
|
173
|
+
private getTypedFlag;
|
|
174
|
+
private toFlag;
|
|
175
|
+
/** toFlag variant that never writes a decision log (used by getAllFlags suppressed path). */
|
|
176
|
+
private toFlagNoLog;
|
|
177
|
+
/** Build a Flag<T> from a forced variation key (per-request override). */
|
|
178
|
+
private buildFlagFromVariationKey;
|
|
179
|
+
private buildLegacyContext;
|
|
180
|
+
private resolveRuntimeOverride;
|
|
181
|
+
private resolveStickyBucket;
|
|
182
|
+
private findVariation;
|
|
183
|
+
private fireExposureForStickyAssignment;
|
|
172
184
|
private emit;
|
|
185
|
+
private emitEvaluation;
|
|
173
186
|
private initTracker;
|
|
187
|
+
private startStreamingIfEnabled;
|
|
174
188
|
private fetchDatafile;
|
|
175
189
|
private startPolling;
|
|
176
190
|
private sendHeartbeat;
|
|
177
|
-
private resolveRuntimeOverride;
|
|
178
|
-
private resolveStickyBucket;
|
|
179
|
-
private findVariation;
|
|
180
|
-
private fireExposureForVariation;
|
|
181
|
-
private recordDecisionLog;
|
|
182
|
-
private emitEvaluation;
|
|
183
191
|
}
|
|
184
192
|
|
|
185
|
-
declare function expressMiddleware(client:
|
|
193
|
+
declare function expressMiddleware(client: AvsbServer, config: MiddlewareConfig): (req: unknown, res: unknown, next: () => void) => void;
|
|
186
194
|
declare function fastifyPlugin(instance: unknown, opts: {
|
|
187
|
-
client:
|
|
195
|
+
client: AvsbServer;
|
|
188
196
|
} & MiddlewareConfig, done: () => void): void;
|
|
189
197
|
|
|
190
198
|
declare class InMemoryStickyBucketService implements StickyBucketService {
|
|
191
199
|
private cache;
|
|
192
200
|
private key;
|
|
193
|
-
lookup(userId: string, flagKey: string):
|
|
194
|
-
save(userId: string, flagKey: string,
|
|
201
|
+
lookup(userId: string, flagKey: string): StickyAssignment | null;
|
|
202
|
+
save(userId: string, flagKey: string, assignment: StickyAssignment): void;
|
|
195
203
|
}
|
|
196
204
|
interface RedisLike {
|
|
197
205
|
get(key: string): Promise<string | null>;
|
|
@@ -216,8 +224,8 @@ declare class RedisStickyBucketService implements StickyBucketService {
|
|
|
216
224
|
constructor(options: RedisStickyBucketOptions);
|
|
217
225
|
private redisKey;
|
|
218
226
|
private cacheKey;
|
|
219
|
-
lookup(userId: string, flagKey: string):
|
|
220
|
-
save(userId: string, flagKey: string,
|
|
227
|
+
lookup(userId: string, flagKey: string): StickyAssignment | null;
|
|
228
|
+
save(userId: string, flagKey: string, assignment: StickyAssignment): void;
|
|
221
229
|
private backgroundFetch;
|
|
222
230
|
private evictIfNeeded;
|
|
223
231
|
}
|
|
@@ -238,9 +246,6 @@ declare function createStreamingClient(options: StreamingOptions): StreamingClie
|
|
|
238
246
|
|
|
239
247
|
declare function createDecisionLog(): DecisionLog;
|
|
240
248
|
|
|
241
|
-
/** No-op logger — used when no custom logger is provided. */
|
|
242
|
-
declare const noopLogger: Logger;
|
|
243
|
-
|
|
244
249
|
declare const SDK_VERSION = "0.3.0";
|
|
245
250
|
|
|
246
|
-
export {
|
|
251
|
+
export { AvsbServer, type AvsbServerOptions, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type StreamingClient, type StreamingOptions, type UserBoundClient, createDecisionLog, createStreamingClient, expressMiddleware, fastifyPlugin };
|