@fireweaveai/server-sdk-cjs 0.0.0-reserve.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -0
  3. package/dist/application/client.d.ts +77 -0
  4. package/dist/application/client.js +144 -0
  5. package/dist/application/mode.d.ts +70 -0
  6. package/dist/application/mode.js +74 -0
  7. package/dist/application/ports.d.ts +94 -0
  8. package/dist/application/ports.js +2 -0
  9. package/dist/application/runtime.d.ts +101 -0
  10. package/dist/application/runtime.js +346 -0
  11. package/dist/domain/context.d.ts +67 -0
  12. package/dist/domain/context.js +90 -0
  13. package/dist/domain/errors.d.ts +45 -0
  14. package/dist/domain/errors.js +99 -0
  15. package/dist/domain/target.d.ts +2 -0
  16. package/dist/domain/target.js +2 -0
  17. package/dist/domain/types.d.ts +107 -0
  18. package/dist/domain/types.js +2 -0
  19. package/dist/domain/validation.d.ts +124 -0
  20. package/dist/domain/validation.js +355 -0
  21. package/dist/index.d.ts +34 -0
  22. package/dist/index.js +52 -0
  23. package/dist/infrastructure/adapters/inmemory.d.ts +77 -0
  24. package/dist/infrastructure/adapters/inmemory.js +151 -0
  25. package/dist/infrastructure/adapters/local.d.ts +108 -0
  26. package/dist/infrastructure/adapters/local.js +105 -0
  27. package/dist/infrastructure/adapters/remote.d.ts +74 -0
  28. package/dist/infrastructure/adapters/remote.js +373 -0
  29. package/dist/infrastructure/hosts.d.ts +18 -0
  30. package/dist/infrastructure/hosts.js +72 -0
  31. package/dist/register-browser.d.ts +1 -0
  32. package/dist/register-browser.js +7 -0
  33. package/dist/register.d.ts +1 -0
  34. package/dist/register.js +13 -0
  35. package/dist/start/browser.d.ts +12 -0
  36. package/dist/start/browser.js +36 -0
  37. package/dist/start/build-info.d.ts +2 -0
  38. package/dist/start/build-info.js +9 -0
  39. package/dist/start/control-points.d.ts +20 -0
  40. package/dist/start/control-points.js +59 -0
  41. package/dist/start/env.d.ts +11 -0
  42. package/dist/start/env.js +64 -0
  43. package/dist/start/fw.d.ts +29 -0
  44. package/dist/start/fw.js +76 -0
  45. package/dist/start/index.d.ts +23 -0
  46. package/dist/start/index.js +28 -0
  47. package/dist/start/instance.d.ts +17 -0
  48. package/dist/start/instance.js +56 -0
  49. package/dist/start/names.d.ts +22 -0
  50. package/dist/start/names.js +25 -0
  51. package/dist/start/resolve.d.ts +40 -0
  52. package/dist/start/resolve.js +139 -0
  53. package/dist/start/state.d.ts +96 -0
  54. package/dist/start/state.js +303 -0
  55. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fireweave AI, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ > **This is the CommonJS build of [`@fireweaveai/server-sdk`](https://www.npmjs.com/package/@fireweaveai/server-sdk).**
2
+ > Use it only when your project cannot load ES modules (see
3
+ > [Module formats](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/module-formats.md)).
4
+ > Same code, same version, same import paths. ES modules are the long-term format;
5
+ > this package will be retired in a future major release.
6
+
7
+ <a href="https://app.fireweave.ai">
8
+ <picture>
9
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/FireWeave-HQ/fireweave-sdk/main/.github/assets/banner-dark.png">
10
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/FireWeave-HQ/fireweave-sdk/main/.github/assets/banner-light.png">
11
+ <img alt="Fireweave — agents write the code. We watch every rollout, under control." src="https://raw.githubusercontent.com/FireWeave-HQ/fireweave-sdk/main/.github/assets/banner-light.png" width="100%">
12
+ </picture>
13
+ </a>
14
+
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/@fireweaveai/server-sdk"><img alt="node" src="https://img.shields.io/npm/v/@fireweaveai/server-sdk?label=node&logo=nodedotjs&style=flat&labelColor=0E0E10&color=ED5502&logoColor=white"></a>
17
+ </p>
18
+
19
+ **Fireweave is the AI release engineer for teams shipping with coding agents.** Every change rolls out behind a control point, one step at a time, with guardrails watching real users — and if something breaks, Fireweave pauses or rolls it back before most users ever see it. It's the only way to ship as fast as your agents write code, without the fear of breaking production.
20
+
21
+ ## Quick start · Node.js · Bun · Deno
22
+
23
+ ```bash
24
+ npm install @fireweaveai/server-sdk
25
+ # bun add @fireweaveai/server-sdk · deno add npm:@fireweaveai/server-sdk
26
+ ```
27
+
28
+ ```ts
29
+ import { initFireweave } from '@fireweaveai/server-sdk';
30
+
31
+ const fireweave = await initFireweave({
32
+ mode: 'remote',
33
+ apiUrl: process.env.FW_API_URL!,
34
+ apiKey: process.env.FW_PROJECT_API_KEY!,
35
+ });
36
+
37
+ // Once per user: the facts your targeting rules match on.
38
+ await fireweave.registerTarget('user_42', { kind: 'user', properties: { plan: 'pro' } });
39
+
40
+ // Per request: evaluate a control point.
41
+ const enabled = await fireweave.controlPoints.getBooleanValue('new-checkout', false, {
42
+ targetingKey: 'user_42',
43
+ });
44
+ console.log('new-checkout:', enabled);
45
+
46
+ await fireweave.shutdown();
47
+ ```
48
+
49
+ ## Learn more
50
+
51
+ [Concepts](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/concepts.md) · [Identity](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/identity.md) · [Testing](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/testing.md) · [Troubleshooting](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/troubleshooting.md) · [Module formats (CommonJS)](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/docs/module-formats.md) · [All SDKs](https://github.com/FireWeave-HQ/fireweave-sdk#quick-start)
52
+
53
+ ## License
54
+
55
+ [MIT](https://github.com/FireWeave-HQ/fireweave-sdk/blob/main/LICENSE)
@@ -0,0 +1,77 @@
1
+ /**
2
+ * FireweaveClient — control-point evaluation and target registration
3
+ * (spec/control-points.md): the only two v1 capabilities. Facade methods
4
+ * degrade instead of throwing.
5
+ */
6
+ import { type FireweaveErrorKind } from '../domain/errors.js';
7
+ import type { EvaluateOptions, ExpectedFlagType, FireweaveRuntime } from './runtime.js';
8
+ import type { ContextInput } from '../domain/context.js';
9
+ import type { RegisterTargetOptions, RegisterTargetResult } from './ports.js';
10
+ import type { Decision, JsonValue } from '../domain/types.js';
11
+ export interface ExtensionResult {
12
+ ok: boolean;
13
+ errorKind?: FireweaveErrorKind;
14
+ errorCode?: string;
15
+ errorMessage?: string;
16
+ degraded?: boolean;
17
+ }
18
+ /**
19
+ * Control-point evaluation on the public client surface (ruling 16):
20
+ * Decision-returning evaluation without reaching into the runtime. Never throws
21
+ * — errors surface as ERROR decisions, exactly like the OpenFeature path.
22
+ *
23
+ * "Control point" is the Fireweave product noun (ADR-0007), on the wire too
24
+ * (ADR-0013).
25
+ */
26
+ export declare class ControlPointsApi {
27
+ private readonly runtime;
28
+ constructor(runtime: FireweaveRuntime);
29
+ /** Evaluate a flag to a canonical Decision (detailed evaluation). */
30
+ evaluate(controlPointKey: string, expectedType: ExpectedFlagType, defaultValue: JsonValue, context?: ContextInput, options?: EvaluateOptions): Promise<Decision>;
31
+ getBooleanValue(controlPointKey: string, defaultValue: boolean, context?: ContextInput): Promise<boolean>;
32
+ getStringValue(controlPointKey: string, defaultValue: string, context?: ContextInput): Promise<string>;
33
+ getNumberValue(controlPointKey: string, defaultValue: number, context?: ContextInput): Promise<number>;
34
+ getObjectValue(controlPointKey: string, defaultValue: JsonValue, context?: ContextInput): Promise<JsonValue>;
35
+ /**
36
+ * Detailed reads — the whole {@link Decision} rather than just its value.
37
+ *
38
+ * Same arguments as the `*Value` pair above, so a caller upgrades from one to
39
+ * the other without restructuring the call. Required by
40
+ * `spec/control-points.md`; before ADR-0010 the only route to `reason`,
41
+ * `variant` or `error` was the OpenFeature provider's `resolve*Evaluation`,
42
+ * so detailed evaluation was unreachable without installing OpenFeature.
43
+ */
44
+ getBooleanDetails(controlPointKey: string, defaultValue: boolean, context?: ContextInput): Promise<Decision>;
45
+ getStringDetails(controlPointKey: string, defaultValue: string, context?: ContextInput): Promise<Decision>;
46
+ getNumberDetails(controlPointKey: string, defaultValue: number, context?: ContextInput): Promise<Decision>;
47
+ getObjectDetails(controlPointKey: string, defaultValue: JsonValue, context?: ContextInput): Promise<Decision>;
48
+ }
49
+ export interface FireweaveClientOptions {
50
+ }
51
+ export declare class FireweaveClient {
52
+ readonly runtime: FireweaveRuntime;
53
+ readonly controlPoints: ControlPointsApi;
54
+ constructor(runtime: FireweaveRuntime, _options?: FireweaveClientOptions);
55
+ /**
56
+ * Register durable targeting facts for a target (spec/modes.md).
57
+ *
58
+ * Resolves `{ ok: false }` rather than throwing: this runs in sign-in paths,
59
+ * where a targeting concern must not break authentication. A careful caller
60
+ * logs a false — a silently unregistered target is how targeting rules end
61
+ * up matching nobody.
62
+ *
63
+ * In local mode this records in-process and traces the call; nothing reaches
64
+ * fw-server. See `FireweaveLocalAdapter.registerTarget`.
65
+ */
66
+ registerTarget(targetingKey: string, options?: RegisterTargetOptions): Promise<RegisterTargetResult>;
67
+ /**
68
+ * Dynamic capability dispatch. Unknown capabilities — currently all of
69
+ * them, v1's SUPPORTED_CAPABILITIES is empty — degrade with
70
+ * UnsupportedCapability, never throw (fixture
71
+ * ext-unsupported-capability-degrade). Any future capability listed in
72
+ * SUPPORTED_CAPABILITIES is lifecycle-gated the same way (ruling 17).
73
+ */
74
+ invokeCapability(capability: string, _args?: Record<string, JsonValue>): ExtensionResult;
75
+ initialize(signal?: AbortSignal): Promise<void>;
76
+ shutdown(): Promise<void>;
77
+ }
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FireweaveClient = exports.ControlPointsApi = void 0;
4
+ /**
5
+ * FireweaveClient — control-point evaluation and target registration
6
+ * (spec/control-points.md): the only two v1 capabilities. Facade methods
7
+ * degrade instead of throwing.
8
+ */
9
+ const errors_js_1 = require("../domain/errors.js");
10
+ const failure = (err, degraded = false) => ({
11
+ ok: false,
12
+ errorKind: err.kind,
13
+ errorCode: err.openFeatureErrorCode,
14
+ errorMessage: err.message,
15
+ ...(degraded ? { degraded: true } : {}),
16
+ });
17
+ /**
18
+ * Lifecycle gate for extension calls (ruling 17, Go/Java model; fixture
19
+ * ext-lifecycle-gating): READY/STALE proceed; post-shutdown degrades
20
+ * AlreadyClosed; pre-ready degrades UnsupportedCapability. Gated methods never
21
+ * throw — failures come back as structured, degraded results.
22
+ */
23
+ const lifecycleGate = (runtime) => {
24
+ switch (runtime.getState()) {
25
+ case 'READY':
26
+ case 'STALE':
27
+ return undefined;
28
+ case 'SHUTDOWN':
29
+ return new errors_js_1.FireweaveError('AlreadyClosed');
30
+ default:
31
+ return new errors_js_1.FireweaveError('UnsupportedCapability');
32
+ }
33
+ };
34
+ /**
35
+ * Control-point evaluation on the public client surface (ruling 16):
36
+ * Decision-returning evaluation without reaching into the runtime. Never throws
37
+ * — errors surface as ERROR decisions, exactly like the OpenFeature path.
38
+ *
39
+ * "Control point" is the Fireweave product noun (ADR-0007), on the wire too
40
+ * (ADR-0013).
41
+ */
42
+ class ControlPointsApi {
43
+ runtime;
44
+ constructor(runtime) {
45
+ this.runtime = runtime;
46
+ }
47
+ /** Evaluate a flag to a canonical Decision (detailed evaluation). */
48
+ evaluate(controlPointKey, expectedType, defaultValue, context, options) {
49
+ return this.runtime.evaluate(controlPointKey, expectedType, defaultValue, context, options ?? {});
50
+ }
51
+ async getBooleanValue(controlPointKey, defaultValue, context) {
52
+ const decision = await this.evaluate(controlPointKey, 'boolean', defaultValue, context);
53
+ return decision.value;
54
+ }
55
+ async getStringValue(controlPointKey, defaultValue, context) {
56
+ const decision = await this.evaluate(controlPointKey, 'string', defaultValue, context);
57
+ return decision.value;
58
+ }
59
+ async getNumberValue(controlPointKey, defaultValue, context) {
60
+ const decision = await this.evaluate(controlPointKey, 'number', defaultValue, context);
61
+ return decision.value;
62
+ }
63
+ async getObjectValue(controlPointKey, defaultValue, context) {
64
+ const decision = await this.evaluate(controlPointKey, 'object', defaultValue, context);
65
+ return decision.value;
66
+ }
67
+ /**
68
+ * Detailed reads — the whole {@link Decision} rather than just its value.
69
+ *
70
+ * Same arguments as the `*Value` pair above, so a caller upgrades from one to
71
+ * the other without restructuring the call. Required by
72
+ * `spec/control-points.md`; before ADR-0010 the only route to `reason`,
73
+ * `variant` or `error` was the OpenFeature provider's `resolve*Evaluation`,
74
+ * so detailed evaluation was unreachable without installing OpenFeature.
75
+ */
76
+ getBooleanDetails(controlPointKey, defaultValue, context) {
77
+ return this.evaluate(controlPointKey, 'boolean', defaultValue, context);
78
+ }
79
+ getStringDetails(controlPointKey, defaultValue, context) {
80
+ return this.evaluate(controlPointKey, 'string', defaultValue, context);
81
+ }
82
+ getNumberDetails(controlPointKey, defaultValue, context) {
83
+ return this.evaluate(controlPointKey, 'number', defaultValue, context);
84
+ }
85
+ getObjectDetails(controlPointKey, defaultValue, context) {
86
+ return this.evaluate(controlPointKey, 'object', defaultValue, context);
87
+ }
88
+ }
89
+ exports.ControlPointsApi = ControlPointsApi;
90
+ /**
91
+ * Names invokeCapability will dispatch instead of degrading with
92
+ * UnsupportedCapability. Empty in v1: releases, exposures, signals,
93
+ * capabilities discovery, and guardrails are all out of scope
94
+ * (spec/control-points.md) and MUST NOT be exposed, so a cut namespace's
95
+ * capability string resolves exactly like any other unknown string.
96
+ */
97
+ const SUPPORTED_CAPABILITIES = Object.freeze([]);
98
+ class FireweaveClient {
99
+ runtime;
100
+ controlPoints;
101
+ constructor(runtime, _options = {}) {
102
+ this.runtime = runtime;
103
+ this.controlPoints = new ControlPointsApi(runtime);
104
+ }
105
+ /**
106
+ * Register durable targeting facts for a target (spec/modes.md).
107
+ *
108
+ * Resolves `{ ok: false }` rather than throwing: this runs in sign-in paths,
109
+ * where a targeting concern must not break authentication. A careful caller
110
+ * logs a false — a silently unregistered target is how targeting rules end
111
+ * up matching nobody.
112
+ *
113
+ * In local mode this records in-process and traces the call; nothing reaches
114
+ * fw-server. See `FireweaveLocalAdapter.registerTarget`.
115
+ */
116
+ registerTarget(targetingKey, options = {}) {
117
+ return this.runtime.registerTarget(targetingKey, options);
118
+ }
119
+ /**
120
+ * Dynamic capability dispatch. Unknown capabilities — currently all of
121
+ * them, v1's SUPPORTED_CAPABILITIES is empty — degrade with
122
+ * UnsupportedCapability, never throw (fixture
123
+ * ext-unsupported-capability-degrade). Any future capability listed in
124
+ * SUPPORTED_CAPABILITIES is lifecycle-gated the same way (ruling 17).
125
+ */
126
+ invokeCapability(capability, _args) {
127
+ if (!SUPPORTED_CAPABILITIES.includes(capability)) {
128
+ return failure(new errors_js_1.FireweaveError('UnsupportedCapability'), true);
129
+ }
130
+ if (capability !== 'capabilities.get') {
131
+ const gateError = lifecycleGate(this.runtime);
132
+ if (gateError !== undefined)
133
+ return failure(gateError, true);
134
+ }
135
+ return { ok: true };
136
+ }
137
+ async initialize(signal) {
138
+ await this.runtime.initialize(signal);
139
+ }
140
+ async shutdown() {
141
+ await this.runtime.shutdown();
142
+ }
143
+ }
144
+ exports.FireweaveClient = FireweaveClient;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * initFireweave — the single SDK entry point (spec/modes.md).
3
+ *
4
+ * `mode` is required and never inferred: a missing or mistyped credential
5
+ * must fail loudly at boot, not silently fall back to local evaluation —
6
+ * that failure mode looks like a green boot and a feature that never ramps.
7
+ * This function's only job is to validate the initialisation-time contract
8
+ * and select the matching adapter; nothing downstream branches on mode again
9
+ * (spec/modes.md "Behaviour per mode" — both adapters implement the same
10
+ * BackendAdapter port, so FireweaveClient / FireweaveRuntime stay mode-blind).
11
+ *
12
+ * Initialisation fails loudly (throws); reads on the returned client never do
13
+ * (spec/control-points.md "initialise is the exception"). The validation
14
+ * itself lives in `validateInitOptions` (validation.ts), which returns
15
+ * `Validated<T>` like every other validator — this function is what converts
16
+ * a failed `Validated` into the throw spec/modes.md requires.
17
+ */
18
+ import { FireweaveClient } from './client.js';
19
+ import type { FireweaveRemoteAdapterOptions } from '../infrastructure/adapters/remote.js';
20
+ export interface InitFireweaveRemoteOptions {
21
+ /** Evaluate against fw-server over the network (spec/remote-protocol.md). */
22
+ readonly mode: 'remote';
23
+ /** Fireweave project/runtime key (project-api-key_…). Required — never read from env. */
24
+ readonly apiKey: string;
25
+ /** fw-server base URL. Required — never read from env. */
26
+ readonly apiUrl: string;
27
+ /**
28
+ * SSRF allowlist override (spec/modes.md "apiUrl fails the host allowlist").
29
+ * Default: the canonical Fireweave hosts + loopback (`DEFAULT_ALLOWED_HOSTS`).
30
+ * A self-hosted fw-server must list its own host explicitly; `['*']` opts out.
31
+ */
32
+ readonly allowedHosts?: readonly string[];
33
+ /** Injected transport (tests). Production uses the runtime's global `fetch`. */
34
+ readonly fetch?: FireweaveRemoteAdapterOptions['fetch'];
35
+ }
36
+ export interface InitFireweaveLocalOptions {
37
+ /** Evaluate against an in-process seeded map; no network (spec/modes.md). */
38
+ readonly mode: 'local';
39
+ readonly local?: {
40
+ /**
41
+ * Per-key boolean overrides — the seeded local map. A present key
42
+ * resolves with reason `STATIC`; an absent key misses so the caller's own
43
+ * default is used. May be empty or omitted entirely.
44
+ */
45
+ readonly controlPoints?: Record<string, boolean>;
46
+ /**
47
+ * Sink for the `[fireweave:local]` registerTarget trace line
48
+ * (spec/modes.md "registerTarget in local mode"). Defaults to
49
+ * `console.info`.
50
+ */
51
+ readonly log?: (message: string) => void;
52
+ };
53
+ }
54
+ export type InitFireweaveOptions = InitFireweaveRemoteOptions | InitFireweaveLocalOptions;
55
+ /**
56
+ * Build the adapter matching `options.mode` and bring a {@link FireweaveClient}
57
+ * to READY.
58
+ *
59
+ * Throws {@link FireweaveError} (kind `Configuration`) for every row of the
60
+ * initialisation-validation table (spec/modes.md):
61
+ * - `mode` absent or unrecognised
62
+ * - `mode: 'remote'` with `apiKey` or `apiUrl` missing/blank
63
+ * - `apiUrl` fails the host allowlist
64
+ * - `mode: 'local'` with credentials supplied
65
+ *
66
+ * The first, second and fourth rows are `validateInitOptions`'s job; the
67
+ * third is validated downstream, when `runtime.initialize()` brings the
68
+ * adapter up (`FireweaveRuntime`'s own config validation, `hosts.ts`).
69
+ */
70
+ export declare function initFireweave(options: InitFireweaveOptions): Promise<FireweaveClient>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initFireweave = initFireweave;
4
+ /**
5
+ * initFireweave — the single SDK entry point (spec/modes.md).
6
+ *
7
+ * `mode` is required and never inferred: a missing or mistyped credential
8
+ * must fail loudly at boot, not silently fall back to local evaluation —
9
+ * that failure mode looks like a green boot and a feature that never ramps.
10
+ * This function's only job is to validate the initialisation-time contract
11
+ * and select the matching adapter; nothing downstream branches on mode again
12
+ * (spec/modes.md "Behaviour per mode" — both adapters implement the same
13
+ * BackendAdapter port, so FireweaveClient / FireweaveRuntime stay mode-blind).
14
+ *
15
+ * Initialisation fails loudly (throws); reads on the returned client never do
16
+ * (spec/control-points.md "initialise is the exception"). The validation
17
+ * itself lives in `validateInitOptions` (validation.ts), which returns
18
+ * `Validated<T>` like every other validator — this function is what converts
19
+ * a failed `Validated` into the throw spec/modes.md requires.
20
+ */
21
+ const client_js_1 = require("./client.js");
22
+ const runtime_js_1 = require("./runtime.js");
23
+ const local_js_1 = require("../infrastructure/adapters/local.js");
24
+ const remote_js_1 = require("../infrastructure/adapters/remote.js");
25
+ const validation_js_1 = require("../domain/validation.js");
26
+ async function initLocal(options) {
27
+ const local = options.local ?? {};
28
+ const adapter = new local_js_1.FireweaveLocalAdapter({
29
+ devFlags: local.controlPoints ?? {},
30
+ ...(local.log !== undefined ? { log: local.log } : {}),
31
+ });
32
+ const runtime = new runtime_js_1.FireweaveRuntime(adapter);
33
+ await runtime.initialize();
34
+ return new client_js_1.FireweaveClient(runtime);
35
+ }
36
+ async function initRemote(options) {
37
+ const { apiKey, apiUrl, allowedHosts, fetch } = options;
38
+ const adapter = new remote_js_1.FireweaveRemoteAdapter({
39
+ apiKey,
40
+ apiUrl,
41
+ ...(allowedHosts !== undefined ? { allowedHosts } : {}),
42
+ ...(fetch !== undefined ? { fetch } : {}),
43
+ });
44
+ const runtime = new runtime_js_1.FireweaveRuntime(adapter, {
45
+ // The same host the adapter will actually call, gated through the
46
+ // canonical allowlist (hosts.ts) before any network I/O happens.
47
+ host: apiUrl,
48
+ ...(allowedHosts !== undefined ? { allowedHosts } : {}),
49
+ });
50
+ await runtime.initialize();
51
+ return new client_js_1.FireweaveClient(runtime);
52
+ }
53
+ /**
54
+ * Build the adapter matching `options.mode` and bring a {@link FireweaveClient}
55
+ * to READY.
56
+ *
57
+ * Throws {@link FireweaveError} (kind `Configuration`) for every row of the
58
+ * initialisation-validation table (spec/modes.md):
59
+ * - `mode` absent or unrecognised
60
+ * - `mode: 'remote'` with `apiKey` or `apiUrl` missing/blank
61
+ * - `apiUrl` fails the host allowlist
62
+ * - `mode: 'local'` with credentials supplied
63
+ *
64
+ * The first, second and fourth rows are `validateInitOptions`'s job; the
65
+ * third is validated downstream, when `runtime.initialize()` brings the
66
+ * adapter up (`FireweaveRuntime`'s own config validation, `hosts.ts`).
67
+ */
68
+ async function initFireweave(options) {
69
+ const validated = (0, validation_js_1.validateInitOptions)(options);
70
+ if (!validated.ok)
71
+ throw validated.error;
72
+ const validOptions = validated.value;
73
+ return validOptions.mode === 'local' ? initLocal(validOptions) : initRemote(validOptions);
74
+ }
@@ -0,0 +1,94 @@
1
+ import type { FireweaveError } from '../domain/errors.js';
2
+ import type { CanonicalContext, DecisionReason, Exposure, FlagValueType, JsonValue, Signal } from '../domain/types.js';
3
+ import type { TargetKind } from '../domain/target.js';
4
+ export interface RegisterTargetOptions {
5
+ /** Defaults to 'user'. */
6
+ kind?: TargetKind;
7
+ /** Durable targeting facts: plan, beta membership, region, device model. */
8
+ properties?: Record<string, JsonValue>;
9
+ /** Client-declared environment (production, staging, …). */
10
+ environment?: string;
11
+ signal?: AbortSignal;
12
+ }
13
+ export interface RegisterTargetResult {
14
+ /**
15
+ * `false` means the target was NOT registered — rules that depend on its
16
+ * properties will not match until a later attempt succeeds. Callers in a
17
+ * login path normally ignore this; a careful caller logs it, because a
18
+ * silently unregistered target is exactly how targeting rules end up
19
+ * matching nobody.
20
+ */
21
+ readonly ok: boolean;
22
+ readonly error?: FireweaveError;
23
+ }
24
+ /** Result of a backend flag resolution (success path; faults throw FireweaveError). */
25
+ export interface AdapterResolution {
26
+ found: boolean;
27
+ /** Flag enabled state; false ⇒ DISABLED reason with the flag's stored value. */
28
+ enabled?: boolean;
29
+ value?: JsonValue;
30
+ variant?: string;
31
+ /** Declared flag type when known (in-memory fixtures); adapters may omit. */
32
+ flagType?: FlagValueType | 'integer' | 'float';
33
+ /**
34
+ * Adapter-suggested reason override (e.g. SPLIT, STALE) on a `found: true`
35
+ * resolution. On a `found: false` miss, `reason: 'DEFAULT'` instead signals
36
+ * the runtime to return the caller's default with reason `DEFAULT` — not an
37
+ * error — per local mode's unknown-key row (spec/modes.md; see
38
+ * FireweaveLocalAdapter.resolve).
39
+ */
40
+ reason?: DecisionReason;
41
+ /** Vendor reason code (e.g. "condition_match"). */
42
+ reasonCode?: string;
43
+ /** Vendor condition index when the vendor reports one. */
44
+ conditionIndex?: number;
45
+ /** Flag definition version. */
46
+ version?: number;
47
+ /** Vendor-side numeric flag id. */
48
+ vendorControlPointId?: number;
49
+ /** Optional flag payload (object or pre-serialized JSON string). */
50
+ payload?: JsonValue;
51
+ /** True when the /flags response reported quota limiting. */
52
+ quotaLimited?: boolean;
53
+ /** True when served from a stale/last-good cache. */
54
+ fromCache?: boolean;
55
+ }
56
+ export interface ResolveOptions {
57
+ signal?: AbortSignal;
58
+ }
59
+ export interface AdapterRuntimeFeatures {
60
+ remoteEvaluation?: boolean;
61
+ localEvaluation?: boolean;
62
+ localOnly?: boolean;
63
+ exposureEmission?: boolean;
64
+ sideEffectFreeReads?: boolean;
65
+ groupAnalytics?: boolean;
66
+ }
67
+ /**
68
+ * Backend adapter boundary. Adapters translate
69
+ * canonical requests to vendor protocols; they never see OpenFeature types.
70
+ */
71
+ export interface BackendAdapter {
72
+ /** Third-party adapters use 'other'; the vendor is fw-server's concern. */
73
+ readonly name: 'inmemory' | 'fireweave' | 'other';
74
+ /** Bring the backend to a usable state. Reject with FireweaveError on failure. */
75
+ initialize(signal?: AbortSignal): Promise<void>;
76
+ /** Resolve one flag. Throws FireweaveError for transport/auth/parse faults. */
77
+ resolve(controlPointKey: string, context: CanonicalContext, options?: ResolveOptions): Promise<AdapterResolution>;
78
+ /**
79
+ * Register a user or device so rules can target its durable properties
80
+ * (optional capability). Resolves with `ok: false` rather than throwing —
81
+ * registration sits in login paths and must not break sign-in.
82
+ */
83
+ registerTarget?(targetingKey: string, options?: RegisterTargetOptions): Promise<RegisterTargetResult>;
84
+ /** Record an exposure event (optional capability). */
85
+ recordExposure?(exposure: Exposure): void;
86
+ /** Deliver a telemetry signal to the backend sink (optional capability, ruling 17). */
87
+ recordSignal?(signal: Signal): void;
88
+ /** Flush buffered telemetry/exposures. */
89
+ flush?(): Promise<void>;
90
+ /** Release resources; must be idempotent. */
91
+ shutdown(): Promise<void>;
92
+ /** Runtime feature capabilities contributed by this adapter. */
93
+ features(): AdapterRuntimeFeatures;
94
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,101 @@
1
+ import { type ContextInput, type ContextLimits } from '../domain/context.js';
2
+ import { type ExpectedFlagType } from '../domain/validation.js';
3
+ import type { BackendAdapter, RegisterTargetOptions, RegisterTargetResult } from './ports.js';
4
+ import type { CanonicalContext, Decision, JsonValue, LifecycleState } from '../domain/types.js';
5
+ export type { ExpectedFlagType } from '../domain/validation.js';
6
+ export interface FireweaveRuntimeConfig {
7
+ /**
8
+ * Fireweave project/runtime key (`project-api-key_…`). Adapters may also read
9
+ * it from their own options.
10
+ */
11
+ projectApiKey?: string;
12
+ /** Backend host (must be http(s) and pass the allowlist). */
13
+ host?: string;
14
+ /**
15
+ * SSRF allowlist: hostnames the SDK may talk to. Empty/undefined ⇒ the
16
+ * canonical Fireweave default allowlist + loopback (DEFAULT_ALLOWED_HOSTS).
17
+ * Custom/self-hosted endpoints must be listed explicitly; ['*'] opts out.
18
+ */
19
+ allowedHosts?: readonly string[];
20
+ /** Require targetingKey on every evaluation. */
21
+ requireTargetingKey?: boolean;
22
+ /** Context bound overrides (defaults are the ratified spec bounds). */
23
+ limits?: Partial<ContextLimits>;
24
+ /** Additional reserved attribute keys. */
25
+ reservedAttributeKeys?: readonly string[];
26
+ /** Shutdown flush deadline (ms). Default DEFAULT_SHUTDOWN_TIMEOUT_MS. */
27
+ shutdownTimeoutMs?: number;
28
+ }
29
+ /** Default bound on shutdown/flush (matches capabilities.get()). */
30
+ export declare const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10000;
31
+ export interface EvaluateOptions {
32
+ /** Attach flag payload as fireweave.payload metadata (sorted-key JSON string). */
33
+ includePayload?: boolean;
34
+ /**
35
+ * When true, emit a Fireweave-owned exposure for a successful evaluation
36
+ * (H-4 / ADR-0001 §23 errata / ruling 20). Default `false` — phase-one
37
+ * evaluate is side-effect-free. Vendor `$feature_flag_called` stays
38
+ * suppressed on the local snapshot path (RB-2); Fireweave owns emission
39
+ * and dedup when opted in.
40
+ */
41
+ sendExposure?: boolean;
42
+ signal?: AbortSignal;
43
+ }
44
+ /** JSON stringify with deterministic (sorted) key order at every level. */
45
+ export declare function stableStringify(value: JsonValue): string;
46
+ export declare class FireweaveRuntime {
47
+ readonly adapter: BackendAdapter;
48
+ readonly config: FireweaveRuntimeConfig;
49
+ private readonly contextPolicy;
50
+ private state;
51
+ private globalContext;
52
+ private clientContext;
53
+ private initPromise;
54
+ private readonly stateListeners;
55
+ /** Dedup window for evaluate/OF-path exposures (cleared on flush / shutdown). */
56
+ private readonly evaluateExposureSeen;
57
+ constructor(adapter: BackendAdapter, config?: FireweaveRuntimeConfig);
58
+ /** Clear evaluate-path exposure dedup (M-2 / clear-on-flush lifecycle). */
59
+ clearEvaluateExposureDedup(): void;
60
+ getState(): LifecycleState;
61
+ onStateChange(listener: (state: LifecycleState) => void): void;
62
+ private setState;
63
+ /** Mark definitions/cache staleness (adapter-driven). */
64
+ markStale(): void;
65
+ setGlobalContext(context: ContextInput | undefined): void;
66
+ setClientContext(context: ContextInput | undefined): void;
67
+ /**
68
+ * Initialize the runtime: validate config, then bring the adapter up.
69
+ * Rejects with FireweaveError; Configuration errors put the runtime in FATAL.
70
+ */
71
+ initialize(signal?: AbortSignal): Promise<void>;
72
+ shutdown(): Promise<void>;
73
+ /** Canonicalize + validate the merged context (throws FireweaveError). */
74
+ resolveContext(invocationContext: ContextInput | undefined): CanonicalContext;
75
+ /**
76
+ * Evaluate a flag to a canonical Decision. Never throws.
77
+ *
78
+ * Validates in the fixed order spec/control-points.md "Validation, before
79
+ * any I/O" names, stopping at the first failure: (1) key, (2) default vs
80
+ * type, (3) context, (4) lifecycle. Only once all four pass does this
81
+ * reach the adapter (the one I/O call in this method).
82
+ */
83
+ evaluate(controlPointKey: string, expectedType: ExpectedFlagType, defaultValue: JsonValue, invocationContext?: ContextInput, options?: EvaluateOptions): Promise<Decision>;
84
+ /**
85
+ * Register a user or device so flag rules can target its DURABLE properties.
86
+ *
87
+ * Call once per login / device provisioning with the facts that outlive a
88
+ * request (plan, beta membership, region, device model), then send the same
89
+ * `targetingKey` on evaluation. Per-request context attributes still override
90
+ * the registered properties for a single evaluation — the two identity paths
91
+ * compose (spec/remote-protocol.md § Two identity paths).
92
+ *
93
+ * Resolves with `ok: false` instead of throwing: this runs in sign-in paths.
94
+ * Adapters without the capability (in-memory, local dev) report
95
+ * `Unsupported` so a dev harness does not silently look registered.
96
+ */
97
+ registerTarget(targetingKey: string, options?: RegisterTargetOptions): Promise<RegisterTargetResult>;
98
+ private emitEvaluateExposure;
99
+ private lifecycleError;
100
+ private errorDecision;
101
+ }