@cloudflare/flagship 0.0.0 → 0.0.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/LICENSE +184 -0
- package/README.md +5 -0
- package/dist/index-C_sW3e_7.d.mts +233 -0
- package/dist/index-D8YLMfBG.d.cts +233 -0
- package/dist/index.cjs +7 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2 -0
- package/dist/server.cjs +298 -0
- package/dist/server.d.cts +144 -0
- package/dist/server.d.mts +144 -0
- package/dist/server.mjs +290 -0
- package/dist/src-CiVDWmng.mjs +202 -0
- package/dist/src-De-abNIr.cjs +231 -0
- package/dist/web.cjs +148 -0
- package/dist/web.d.cts +72 -0
- package/dist/web.d.mts +72 -0
- package/dist/web.mjs +142 -0
- package/package.json +102 -10
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_src = require("./src-De-abNIr.cjs");
|
|
3
|
+
let _openfeature_server_sdk = require("@openfeature/server-sdk");
|
|
4
|
+
//#region src/server-provider.ts
|
|
5
|
+
const _noop = () => {};
|
|
6
|
+
/**
|
|
7
|
+
* OpenFeature provider for Flagship (server-side / dynamic context).
|
|
8
|
+
*
|
|
9
|
+
* Use this provider with `@openfeature/server-sdk` for Node.js,
|
|
10
|
+
* Cloudflare Workers, and other server-side JavaScript environments.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
15
|
+
* import { FlagshipServerProvider } from '@cloudflare/flagship/server';
|
|
16
|
+
*
|
|
17
|
+
* await OpenFeature.setProviderAndWait(
|
|
18
|
+
* new FlagshipServerProvider({
|
|
19
|
+
* appId: 'app-abc123',
|
|
20
|
+
* accountId: 'your-account-id',
|
|
21
|
+
* authToken: 'your-token',
|
|
22
|
+
* })
|
|
23
|
+
* );
|
|
24
|
+
*
|
|
25
|
+
* const client = OpenFeature.getClient();
|
|
26
|
+
* const value = await client.getBooleanValue('my-flag', false, {
|
|
27
|
+
* targetingKey: 'user-123',
|
|
28
|
+
* email: 'user@example.com',
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
var FlagshipServerProvider = class {
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.runsOn = "server";
|
|
35
|
+
this.events = new _openfeature_server_sdk.OpenFeatureEventEmitter();
|
|
36
|
+
this.currentStatus = _openfeature_server_sdk.ProviderStatus.NOT_READY;
|
|
37
|
+
this.metadata = { name: "Flagship Server Provider" };
|
|
38
|
+
this.client = new require_src.FlagshipClient(options);
|
|
39
|
+
this.logging = options.logging ?? false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns the provided logger when logging is enabled, or a no-op logger
|
|
43
|
+
* when `logging` is `false`. Using this in every resolve method ensures
|
|
44
|
+
* the SDK produces no console output unless the caller opts in.
|
|
45
|
+
*/
|
|
46
|
+
logger(logger) {
|
|
47
|
+
if (this.logging) return logger;
|
|
48
|
+
return {
|
|
49
|
+
debug: _noop,
|
|
50
|
+
info: _noop,
|
|
51
|
+
warn: _noop,
|
|
52
|
+
error: _noop
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Probes the evaluation endpoint with a health-check request. A 404 response
|
|
57
|
+
* is treated as success — it means the endpoint is reachable but the
|
|
58
|
+
* health-check flag simply doesn't exist, which is expected. Any network
|
|
59
|
+
* failure or timeout sets the status to ERROR.
|
|
60
|
+
*/
|
|
61
|
+
async initialize(_context) {
|
|
62
|
+
try {
|
|
63
|
+
await this.client.evaluate("_flagship_health_check", {});
|
|
64
|
+
this.currentStatus = _openfeature_server_sdk.ProviderStatus.READY;
|
|
65
|
+
this.events.emit(_openfeature_server_sdk.ProviderEvents.Ready);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error instanceof require_src.FlagshipError && error.cause instanceof Response && error.cause.status === 404) {
|
|
68
|
+
this.currentStatus = _openfeature_server_sdk.ProviderStatus.READY;
|
|
69
|
+
this.events.emit(_openfeature_server_sdk.ProviderEvents.Ready);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.currentStatus = _openfeature_server_sdk.ProviderStatus.ERROR;
|
|
73
|
+
this.events.emit(_openfeature_server_sdk.ProviderEvents.Error, { message: error instanceof Error ? error.message : String(error) });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async onClose() {
|
|
77
|
+
this.currentStatus = _openfeature_server_sdk.ProviderStatus.NOT_READY;
|
|
78
|
+
}
|
|
79
|
+
get status() {
|
|
80
|
+
return this.currentStatus;
|
|
81
|
+
}
|
|
82
|
+
async resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
|
|
83
|
+
return this.resolve(flagKey, defaultValue, context, "boolean", logger);
|
|
84
|
+
}
|
|
85
|
+
async resolveStringEvaluation(flagKey, defaultValue, context, logger) {
|
|
86
|
+
return this.resolve(flagKey, defaultValue, context, "string", logger);
|
|
87
|
+
}
|
|
88
|
+
async resolveNumberEvaluation(flagKey, defaultValue, context, logger) {
|
|
89
|
+
return this.resolve(flagKey, defaultValue, context, "number", logger);
|
|
90
|
+
}
|
|
91
|
+
async resolveObjectEvaluation(flagKey, defaultValue, context, logger) {
|
|
92
|
+
return this.resolve(flagKey, defaultValue, context, "object", logger);
|
|
93
|
+
}
|
|
94
|
+
async resolve(flagKey, defaultValue, context, expectedType, logger) {
|
|
95
|
+
const log = this.logger(logger);
|
|
96
|
+
try {
|
|
97
|
+
log.debug(`[Flagship] Evaluating flag "${flagKey}" (expected: ${expectedType})`);
|
|
98
|
+
const result = await this.client.evaluate(flagKey, context);
|
|
99
|
+
const actualType = this.getValueType(result.value);
|
|
100
|
+
if (actualType !== expectedType) {
|
|
101
|
+
const msg = `Flag "${flagKey}" type mismatch: expected ${expectedType}, got ${actualType}`;
|
|
102
|
+
log.warn(`[Flagship] ${msg}`);
|
|
103
|
+
return {
|
|
104
|
+
value: defaultValue,
|
|
105
|
+
errorCode: _openfeature_server_sdk.ErrorCode.TYPE_MISMATCH,
|
|
106
|
+
errorMessage: msg,
|
|
107
|
+
reason: "ERROR"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
log.debug(`[Flagship] Flag "${flagKey}" resolved: value=${String(result.value)} reason=${result.reason} variant=${result.variant}`);
|
|
111
|
+
return {
|
|
112
|
+
value: result.value,
|
|
113
|
+
variant: result.variant,
|
|
114
|
+
reason: result.reason,
|
|
115
|
+
flagMetadata: {}
|
|
116
|
+
};
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return this.handleError(flagKey, defaultValue, error, log);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Maps a runtime value to one of the four OpenFeature flag types.
|
|
123
|
+
* `null` maps to `'object'` (typeof null === 'object'), treating it as a
|
|
124
|
+
* JSON null which belongs to the object/structure category.
|
|
125
|
+
*/
|
|
126
|
+
getValueType(value) {
|
|
127
|
+
if (typeof value === "boolean") return "boolean";
|
|
128
|
+
if (typeof value === "string") return "string";
|
|
129
|
+
if (typeof value === "number") return "number";
|
|
130
|
+
return "object";
|
|
131
|
+
}
|
|
132
|
+
handleError(flagKey, defaultValue, error, logger) {
|
|
133
|
+
if (error instanceof require_src.FlagshipError) {
|
|
134
|
+
let errorCode;
|
|
135
|
+
switch (error.code) {
|
|
136
|
+
case require_src.FlagshipErrorCode.NETWORK_ERROR:
|
|
137
|
+
errorCode = error.cause instanceof Response && error.cause.status === 404 ? _openfeature_server_sdk.ErrorCode.FLAG_NOT_FOUND : _openfeature_server_sdk.ErrorCode.GENERAL;
|
|
138
|
+
break;
|
|
139
|
+
case require_src.FlagshipErrorCode.TIMEOUT_ERROR:
|
|
140
|
+
errorCode = _openfeature_server_sdk.ErrorCode.GENERAL;
|
|
141
|
+
break;
|
|
142
|
+
case require_src.FlagshipErrorCode.PARSE_ERROR:
|
|
143
|
+
errorCode = _openfeature_server_sdk.ErrorCode.PARSE_ERROR;
|
|
144
|
+
break;
|
|
145
|
+
case require_src.FlagshipErrorCode.INVALID_CONTEXT:
|
|
146
|
+
errorCode = _openfeature_server_sdk.ErrorCode.INVALID_CONTEXT;
|
|
147
|
+
break;
|
|
148
|
+
default: errorCode = _openfeature_server_sdk.ErrorCode.GENERAL;
|
|
149
|
+
}
|
|
150
|
+
logger.error(`[Flagship] Flag "${flagKey}" evaluation failed (${errorCode}): ${error.message}`);
|
|
151
|
+
return {
|
|
152
|
+
value: defaultValue,
|
|
153
|
+
errorCode,
|
|
154
|
+
errorMessage: error.message,
|
|
155
|
+
reason: "ERROR"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const errorMessage = String(error);
|
|
159
|
+
logger.error(`[Flagship] Flag "${flagKey}" evaluation failed (GENERAL): ${errorMessage}`);
|
|
160
|
+
return {
|
|
161
|
+
value: defaultValue,
|
|
162
|
+
errorCode: _openfeature_server_sdk.ErrorCode.GENERAL,
|
|
163
|
+
errorMessage,
|
|
164
|
+
reason: "ERROR"
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/hooks/logging-hook.ts
|
|
170
|
+
/**
|
|
171
|
+
* Logging hook for debugging flag evaluations
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
176
|
+
* import { FlagshipServerProvider, LoggingHook } from '@cloudflare/flagship/server';
|
|
177
|
+
*
|
|
178
|
+
* const provider = new FlagshipServerProvider({ appId: 'your-app-id', accountId: 'your-account-id' });
|
|
179
|
+
* await OpenFeature.setProviderAndWait(provider);
|
|
180
|
+
*
|
|
181
|
+
* // Add logging hook
|
|
182
|
+
* OpenFeature.addHooks(new LoggingHook());
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
var LoggingHook = class {
|
|
186
|
+
constructor(logger = console.log) {
|
|
187
|
+
this.logger = logger;
|
|
188
|
+
}
|
|
189
|
+
before(hookContext, _hookHints) {
|
|
190
|
+
this.logger(`[Flagship] Evaluating flag: ${hookContext.flagKey}`, {
|
|
191
|
+
defaultValue: hookContext.defaultValue,
|
|
192
|
+
context: hookContext.context
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
after(hookContext, evaluationDetails, _hookHints) {
|
|
196
|
+
this.logger(`[Flagship] Flag ${hookContext.flagKey} evaluated`, {
|
|
197
|
+
value: evaluationDetails.value,
|
|
198
|
+
reason: evaluationDetails.reason,
|
|
199
|
+
variant: evaluationDetails.variant,
|
|
200
|
+
errorCode: evaluationDetails.errorCode
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
error(hookContext, error, _hookHints) {
|
|
204
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
205
|
+
this.logger(`[Flagship] Error evaluating flag ${hookContext.flagKey}:`, message);
|
|
206
|
+
}
|
|
207
|
+
finally(_hookContext, _evaluationDetails, _hookHints) {}
|
|
208
|
+
};
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/hooks/telemetry-hook.ts
|
|
211
|
+
/**
|
|
212
|
+
* Telemetry hook for tracking flag evaluations
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
217
|
+
* import { FlagshipServerProvider, TelemetryHook } from '@cloudflare/flagship/server';
|
|
218
|
+
*
|
|
219
|
+
* const telemetryHook = new TelemetryHook((event) => {
|
|
220
|
+
* // Send to your analytics service
|
|
221
|
+
* analytics.track('flag_evaluated', event);
|
|
222
|
+
* });
|
|
223
|
+
*
|
|
224
|
+
* OpenFeature.addHooks(telemetryHook);
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
var TelemetryHook = class {
|
|
228
|
+
constructor(onEvent) {
|
|
229
|
+
this.startTimes = /* @__PURE__ */ new Map();
|
|
230
|
+
this.contextKeys = /* @__PURE__ */ new WeakMap();
|
|
231
|
+
this.hints = /* @__PURE__ */ new WeakMap();
|
|
232
|
+
this.onEvent = onEvent;
|
|
233
|
+
}
|
|
234
|
+
before(hookContext, hookHints) {
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
const key = `${hookContext.flagKey}-${now}-${Math.random()}`;
|
|
237
|
+
this.startTimes.set(key, now);
|
|
238
|
+
this.contextKeys.set(hookContext, key);
|
|
239
|
+
if (hookHints !== void 0) this.hints.set(hookContext, hookHints);
|
|
240
|
+
}
|
|
241
|
+
after(hookContext, evaluationDetails, _hookHints) {
|
|
242
|
+
const telemetryKey = this.contextKeys.get(hookContext);
|
|
243
|
+
const startTime = telemetryKey ? this.startTimes.get(telemetryKey) : void 0;
|
|
244
|
+
const duration = startTime !== void 0 ? Date.now() - startTime : void 0;
|
|
245
|
+
if (telemetryKey !== void 0) {
|
|
246
|
+
this.startTimes.delete(telemetryKey);
|
|
247
|
+
this.contextKeys.delete(hookContext);
|
|
248
|
+
}
|
|
249
|
+
this.onEvent({
|
|
250
|
+
type: "evaluation",
|
|
251
|
+
flagKey: hookContext.flagKey,
|
|
252
|
+
timestamp: Date.now(),
|
|
253
|
+
duration,
|
|
254
|
+
value: evaluationDetails.value,
|
|
255
|
+
reason: evaluationDetails.reason,
|
|
256
|
+
variant: evaluationDetails.variant,
|
|
257
|
+
errorCode: evaluationDetails.errorCode,
|
|
258
|
+
context: hookContext.context,
|
|
259
|
+
hints: this.hints.get(hookContext)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
error(hookContext, error, _hookHints) {
|
|
263
|
+
const telemetryKey = this.contextKeys.get(hookContext);
|
|
264
|
+
const startTime = telemetryKey ? this.startTimes.get(telemetryKey) : void 0;
|
|
265
|
+
const duration = startTime !== void 0 ? Date.now() - startTime : void 0;
|
|
266
|
+
if (telemetryKey !== void 0) {
|
|
267
|
+
this.startTimes.delete(telemetryKey);
|
|
268
|
+
this.contextKeys.delete(hookContext);
|
|
269
|
+
}
|
|
270
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
271
|
+
this.onEvent({
|
|
272
|
+
type: "error",
|
|
273
|
+
flagKey: hookContext.flagKey,
|
|
274
|
+
timestamp: Date.now(),
|
|
275
|
+
duration,
|
|
276
|
+
errorMessage,
|
|
277
|
+
context: hookContext.context,
|
|
278
|
+
hints: this.hints.get(hookContext)
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
finally(hookContext, _evaluationDetails, _hookHints) {
|
|
282
|
+
const telemetryKey = this.contextKeys.get(hookContext);
|
|
283
|
+
if (telemetryKey !== void 0) {
|
|
284
|
+
this.startTimes.delete(telemetryKey);
|
|
285
|
+
this.contextKeys.delete(hookContext);
|
|
286
|
+
}
|
|
287
|
+
this.hints.delete(hookContext);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
//#endregion
|
|
291
|
+
exports.ContextTransformer = require_src.ContextTransformer;
|
|
292
|
+
exports.FLAGSHIP_DEFAULT_BASE_URL = require_src.FLAGSHIP_DEFAULT_BASE_URL;
|
|
293
|
+
exports.FlagshipClient = require_src.FlagshipClient;
|
|
294
|
+
exports.FlagshipError = require_src.FlagshipError;
|
|
295
|
+
exports.FlagshipErrorCode = require_src.FlagshipErrorCode;
|
|
296
|
+
exports.FlagshipServerProvider = FlagshipServerProvider;
|
|
297
|
+
exports.LoggingHook = LoggingHook;
|
|
298
|
+
exports.TelemetryHook = TelemetryHook;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { c as FlagshipEvaluationResponse, i as FLAGSHIP_DEFAULT_BASE_URL, l as FlagshipProviderOptions, n as ContextTransformer, o as FlagshipError, s as FlagshipErrorCode, t as FlagshipClient } from "./index-D8YLMfBG.cjs";
|
|
2
|
+
import { BeforeHookContext, ErrorCode, EvaluationContext, EvaluationDetails, FlagValue, Hook, HookContext, HookHints, JsonValue, Logger, OpenFeatureEventEmitter, Provider, ProviderMetadata, ProviderStatus, ResolutionDetails } from "@openfeature/server-sdk";
|
|
3
|
+
|
|
4
|
+
//#region src/server-provider.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* OpenFeature provider for Flagship (server-side / dynamic context).
|
|
7
|
+
*
|
|
8
|
+
* Use this provider with `@openfeature/server-sdk` for Node.js,
|
|
9
|
+
* Cloudflare Workers, and other server-side JavaScript environments.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
14
|
+
* import { FlagshipServerProvider } from '@cloudflare/flagship/server';
|
|
15
|
+
*
|
|
16
|
+
* await OpenFeature.setProviderAndWait(
|
|
17
|
+
* new FlagshipServerProvider({
|
|
18
|
+
* appId: 'app-abc123',
|
|
19
|
+
* accountId: 'your-account-id',
|
|
20
|
+
* authToken: 'your-token',
|
|
21
|
+
* })
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* const client = OpenFeature.getClient();
|
|
25
|
+
* const value = await client.getBooleanValue('my-flag', false, {
|
|
26
|
+
* targetingKey: 'user-123',
|
|
27
|
+
* email: 'user@example.com',
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare class FlagshipServerProvider implements Provider {
|
|
32
|
+
readonly metadata: ProviderMetadata;
|
|
33
|
+
readonly runsOn: "server";
|
|
34
|
+
readonly events: OpenFeatureEventEmitter;
|
|
35
|
+
private readonly client;
|
|
36
|
+
private readonly logging;
|
|
37
|
+
private currentStatus;
|
|
38
|
+
constructor(options: FlagshipProviderOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Returns the provided logger when logging is enabled, or a no-op logger
|
|
41
|
+
* when `logging` is `false`. Using this in every resolve method ensures
|
|
42
|
+
* the SDK produces no console output unless the caller opts in.
|
|
43
|
+
*/
|
|
44
|
+
private logger;
|
|
45
|
+
/**
|
|
46
|
+
* Probes the evaluation endpoint with a health-check request. A 404 response
|
|
47
|
+
* is treated as success — it means the endpoint is reachable but the
|
|
48
|
+
* health-check flag simply doesn't exist, which is expected. Any network
|
|
49
|
+
* failure or timeout sets the status to ERROR.
|
|
50
|
+
*/
|
|
51
|
+
initialize(_context?: EvaluationContext): Promise<void>;
|
|
52
|
+
onClose(): Promise<void>;
|
|
53
|
+
get status(): ProviderStatus;
|
|
54
|
+
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
|
|
55
|
+
resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<string>>;
|
|
56
|
+
resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<number>>;
|
|
57
|
+
resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<T>>;
|
|
58
|
+
private resolve;
|
|
59
|
+
/**
|
|
60
|
+
* Maps a runtime value to one of the four OpenFeature flag types.
|
|
61
|
+
* `null` maps to `'object'` (typeof null === 'object'), treating it as a
|
|
62
|
+
* JSON null which belongs to the object/structure category.
|
|
63
|
+
*/
|
|
64
|
+
private getValueType;
|
|
65
|
+
private handleError;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/hooks/logging-hook.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* Logging hook for debugging flag evaluations
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
75
|
+
* import { FlagshipServerProvider, LoggingHook } from '@cloudflare/flagship/server';
|
|
76
|
+
*
|
|
77
|
+
* const provider = new FlagshipServerProvider({ appId: 'your-app-id', accountId: 'your-account-id' });
|
|
78
|
+
* await OpenFeature.setProviderAndWait(provider);
|
|
79
|
+
*
|
|
80
|
+
* // Add logging hook
|
|
81
|
+
* OpenFeature.addHooks(new LoggingHook());
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare class LoggingHook implements Hook {
|
|
85
|
+
private readonly logger;
|
|
86
|
+
constructor(logger?: (message: string, ...args: unknown[]) => void);
|
|
87
|
+
before(hookContext: BeforeHookContext, _hookHints?: HookHints): void;
|
|
88
|
+
after(hookContext: Readonly<HookContext>, evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
89
|
+
error(hookContext: Readonly<HookContext>, error: unknown, _hookHints?: HookHints): void;
|
|
90
|
+
finally(_hookContext: Readonly<HookContext>, _evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/hooks/telemetry-hook.d.ts
|
|
94
|
+
/**
|
|
95
|
+
* Telemetry event data
|
|
96
|
+
*/
|
|
97
|
+
interface TelemetryEvent {
|
|
98
|
+
type: 'evaluation' | 'error';
|
|
99
|
+
flagKey: string;
|
|
100
|
+
timestamp: number;
|
|
101
|
+
duration?: number;
|
|
102
|
+
value?: unknown;
|
|
103
|
+
reason?: string;
|
|
104
|
+
variant?: string;
|
|
105
|
+
/** The OpenFeature ErrorCode, if evaluation produced an error. */
|
|
106
|
+
errorCode?: ErrorCode;
|
|
107
|
+
errorMessage?: string;
|
|
108
|
+
context?: Record<string, unknown>;
|
|
109
|
+
/**
|
|
110
|
+
* Caller-supplied hints forwarded from `EvaluationOptions.hookHints`.
|
|
111
|
+
* Use this to attach trace IDs, request IDs, or any other metadata
|
|
112
|
+
* that the application author wants to associate with the evaluation.
|
|
113
|
+
*/
|
|
114
|
+
hints?: Readonly<Record<string, unknown>>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Telemetry hook for tracking flag evaluations
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
122
|
+
* import { FlagshipServerProvider, TelemetryHook } from '@cloudflare/flagship/server';
|
|
123
|
+
*
|
|
124
|
+
* const telemetryHook = new TelemetryHook((event) => {
|
|
125
|
+
* // Send to your analytics service
|
|
126
|
+
* analytics.track('flag_evaluated', event);
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* OpenFeature.addHooks(telemetryHook);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare class TelemetryHook implements Hook {
|
|
133
|
+
private startTimes;
|
|
134
|
+
private contextKeys;
|
|
135
|
+
private hints;
|
|
136
|
+
private readonly onEvent;
|
|
137
|
+
constructor(onEvent: (event: TelemetryEvent) => void);
|
|
138
|
+
before(hookContext: BeforeHookContext, hookHints?: HookHints): void;
|
|
139
|
+
after(hookContext: Readonly<HookContext>, evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
140
|
+
error(hookContext: Readonly<HookContext>, error: unknown, _hookHints?: HookHints): void;
|
|
141
|
+
finally(hookContext: Readonly<HookContext>, _evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { ContextTransformer, FLAGSHIP_DEFAULT_BASE_URL, FlagshipClient, FlagshipError, FlagshipErrorCode, type FlagshipEvaluationResponse, type FlagshipProviderOptions, FlagshipServerProvider, LoggingHook, type TelemetryEvent, TelemetryHook };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { c as FlagshipEvaluationResponse, i as FLAGSHIP_DEFAULT_BASE_URL, l as FlagshipProviderOptions, n as ContextTransformer, o as FlagshipError, s as FlagshipErrorCode, t as FlagshipClient } from "./index-C_sW3e_7.mjs";
|
|
2
|
+
import { BeforeHookContext, ErrorCode, EvaluationContext, EvaluationDetails, FlagValue, Hook, HookContext, HookHints, JsonValue, Logger, OpenFeatureEventEmitter, Provider, ProviderMetadata, ProviderStatus, ResolutionDetails } from "@openfeature/server-sdk";
|
|
3
|
+
|
|
4
|
+
//#region src/server-provider.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* OpenFeature provider for Flagship (server-side / dynamic context).
|
|
7
|
+
*
|
|
8
|
+
* Use this provider with `@openfeature/server-sdk` for Node.js,
|
|
9
|
+
* Cloudflare Workers, and other server-side JavaScript environments.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
14
|
+
* import { FlagshipServerProvider } from '@cloudflare/flagship/server';
|
|
15
|
+
*
|
|
16
|
+
* await OpenFeature.setProviderAndWait(
|
|
17
|
+
* new FlagshipServerProvider({
|
|
18
|
+
* appId: 'app-abc123',
|
|
19
|
+
* accountId: 'your-account-id',
|
|
20
|
+
* authToken: 'your-token',
|
|
21
|
+
* })
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* const client = OpenFeature.getClient();
|
|
25
|
+
* const value = await client.getBooleanValue('my-flag', false, {
|
|
26
|
+
* targetingKey: 'user-123',
|
|
27
|
+
* email: 'user@example.com',
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare class FlagshipServerProvider implements Provider {
|
|
32
|
+
readonly metadata: ProviderMetadata;
|
|
33
|
+
readonly runsOn: "server";
|
|
34
|
+
readonly events: OpenFeatureEventEmitter;
|
|
35
|
+
private readonly client;
|
|
36
|
+
private readonly logging;
|
|
37
|
+
private currentStatus;
|
|
38
|
+
constructor(options: FlagshipProviderOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Returns the provided logger when logging is enabled, or a no-op logger
|
|
41
|
+
* when `logging` is `false`. Using this in every resolve method ensures
|
|
42
|
+
* the SDK produces no console output unless the caller opts in.
|
|
43
|
+
*/
|
|
44
|
+
private logger;
|
|
45
|
+
/**
|
|
46
|
+
* Probes the evaluation endpoint with a health-check request. A 404 response
|
|
47
|
+
* is treated as success — it means the endpoint is reachable but the
|
|
48
|
+
* health-check flag simply doesn't exist, which is expected. Any network
|
|
49
|
+
* failure or timeout sets the status to ERROR.
|
|
50
|
+
*/
|
|
51
|
+
initialize(_context?: EvaluationContext): Promise<void>;
|
|
52
|
+
onClose(): Promise<void>;
|
|
53
|
+
get status(): ProviderStatus;
|
|
54
|
+
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<boolean>>;
|
|
55
|
+
resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<string>>;
|
|
56
|
+
resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<number>>;
|
|
57
|
+
resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): Promise<ResolutionDetails<T>>;
|
|
58
|
+
private resolve;
|
|
59
|
+
/**
|
|
60
|
+
* Maps a runtime value to one of the four OpenFeature flag types.
|
|
61
|
+
* `null` maps to `'object'` (typeof null === 'object'), treating it as a
|
|
62
|
+
* JSON null which belongs to the object/structure category.
|
|
63
|
+
*/
|
|
64
|
+
private getValueType;
|
|
65
|
+
private handleError;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/hooks/logging-hook.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* Logging hook for debugging flag evaluations
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
75
|
+
* import { FlagshipServerProvider, LoggingHook } from '@cloudflare/flagship/server';
|
|
76
|
+
*
|
|
77
|
+
* const provider = new FlagshipServerProvider({ appId: 'your-app-id', accountId: 'your-account-id' });
|
|
78
|
+
* await OpenFeature.setProviderAndWait(provider);
|
|
79
|
+
*
|
|
80
|
+
* // Add logging hook
|
|
81
|
+
* OpenFeature.addHooks(new LoggingHook());
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare class LoggingHook implements Hook {
|
|
85
|
+
private readonly logger;
|
|
86
|
+
constructor(logger?: (message: string, ...args: unknown[]) => void);
|
|
87
|
+
before(hookContext: BeforeHookContext, _hookHints?: HookHints): void;
|
|
88
|
+
after(hookContext: Readonly<HookContext>, evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
89
|
+
error(hookContext: Readonly<HookContext>, error: unknown, _hookHints?: HookHints): void;
|
|
90
|
+
finally(_hookContext: Readonly<HookContext>, _evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/hooks/telemetry-hook.d.ts
|
|
94
|
+
/**
|
|
95
|
+
* Telemetry event data
|
|
96
|
+
*/
|
|
97
|
+
interface TelemetryEvent {
|
|
98
|
+
type: 'evaluation' | 'error';
|
|
99
|
+
flagKey: string;
|
|
100
|
+
timestamp: number;
|
|
101
|
+
duration?: number;
|
|
102
|
+
value?: unknown;
|
|
103
|
+
reason?: string;
|
|
104
|
+
variant?: string;
|
|
105
|
+
/** The OpenFeature ErrorCode, if evaluation produced an error. */
|
|
106
|
+
errorCode?: ErrorCode;
|
|
107
|
+
errorMessage?: string;
|
|
108
|
+
context?: Record<string, unknown>;
|
|
109
|
+
/**
|
|
110
|
+
* Caller-supplied hints forwarded from `EvaluationOptions.hookHints`.
|
|
111
|
+
* Use this to attach trace IDs, request IDs, or any other metadata
|
|
112
|
+
* that the application author wants to associate with the evaluation.
|
|
113
|
+
*/
|
|
114
|
+
hints?: Readonly<Record<string, unknown>>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Telemetry hook for tracking flag evaluations
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* import { OpenFeature } from '@openfeature/server-sdk';
|
|
122
|
+
* import { FlagshipServerProvider, TelemetryHook } from '@cloudflare/flagship/server';
|
|
123
|
+
*
|
|
124
|
+
* const telemetryHook = new TelemetryHook((event) => {
|
|
125
|
+
* // Send to your analytics service
|
|
126
|
+
* analytics.track('flag_evaluated', event);
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* OpenFeature.addHooks(telemetryHook);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare class TelemetryHook implements Hook {
|
|
133
|
+
private startTimes;
|
|
134
|
+
private contextKeys;
|
|
135
|
+
private hints;
|
|
136
|
+
private readonly onEvent;
|
|
137
|
+
constructor(onEvent: (event: TelemetryEvent) => void);
|
|
138
|
+
before(hookContext: BeforeHookContext, hookHints?: HookHints): void;
|
|
139
|
+
after(hookContext: Readonly<HookContext>, evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
140
|
+
error(hookContext: Readonly<HookContext>, error: unknown, _hookHints?: HookHints): void;
|
|
141
|
+
finally(hookContext: Readonly<HookContext>, _evaluationDetails: EvaluationDetails<FlagValue>, _hookHints?: HookHints): void;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { ContextTransformer, FLAGSHIP_DEFAULT_BASE_URL, FlagshipClient, FlagshipError, FlagshipErrorCode, type FlagshipEvaluationResponse, type FlagshipProviderOptions, FlagshipServerProvider, LoggingHook, type TelemetryEvent, TelemetryHook };
|