@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
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.slot = slot;
4
+ exports.warnOnce = warnOnce;
5
+ exports.start = start;
6
+ exports.startWith = startWith;
7
+ exports.ensureClient = ensureClient;
8
+ exports.currentStatus = currentStatus;
9
+ exports.instanceKeyFor = instanceKeyFor;
10
+ exports.shutdownSlot = shutdownSlot;
11
+ exports.resetForTests = resetForTests;
12
+ /**
13
+ * start() and the process-wide singleton behind `fw`.
14
+ *
15
+ * One slot per process (or worker thread) at a Symbol.for key on globalThis,
16
+ * so two bundled copies of this package share one client. start() is
17
+ * synchronous: it resolves and validates everything up front, throws a
18
+ * Configuration error for bad config, then hands off to the unchanged core
19
+ * initFireweave(). Reads await readiness and never throw.
20
+ *
21
+ * A read that happens before any start() schedules an env-only start on the
22
+ * next macrotask. An ES module graph without top-level await evaluates in one
23
+ * job, so an entrypoint that imports ./fireweave/start first always wins.
24
+ */
25
+ const index_js_1 = require("../index.js");
26
+ const build_info_js_1 = require("./build-info.js");
27
+ const env_js_1 = require("./env.js");
28
+ const control_points_js_1 = require("./control-points.js");
29
+ const instance_js_1 = require("./instance.js");
30
+ const resolve_js_1 = require("./resolve.js");
31
+ const deferred = () => {
32
+ let resolve;
33
+ const promise = new Promise((r) => {
34
+ resolve = r;
35
+ });
36
+ return { promise, resolve };
37
+ };
38
+ const SLOT_KEY = Symbol.for('@fireweaveai/server-sdk/start');
39
+ const defaultLog = (line) => {
40
+ if (line.startsWith('[fireweave:local]'))
41
+ console.info(line);
42
+ else
43
+ console.warn(line);
44
+ };
45
+ const freshSlot = () => ({
46
+ protocol: 1,
47
+ state: 'unstarted',
48
+ implicit: false,
49
+ ready: deferred(),
50
+ implicitScheduled: false,
51
+ log: defaultLog,
52
+ warned: new Set(),
53
+ diagnosed: new Set(),
54
+ });
55
+ function slot() {
56
+ const g = globalThis;
57
+ const existing = g[SLOT_KEY];
58
+ if (existing !== undefined) {
59
+ if (existing.protocol !== 1) {
60
+ throw new index_js_1.FireweaveError('Configuration', {
61
+ message: '[fireweave] Two incompatible copies of @fireweaveai/server-sdk are loaded. Deduplicate the dependency.',
62
+ });
63
+ }
64
+ return existing;
65
+ }
66
+ const created = freshSlot();
67
+ g[SLOT_KEY] = created;
68
+ return created;
69
+ }
70
+ function warnOnce(s, line) {
71
+ if (s.warned.has(line))
72
+ return;
73
+ s.warned.add(line);
74
+ s.log(line);
75
+ }
76
+ const signatureOf = (r, instanceId) => (0, index_js_1.stableStringify)({
77
+ mode: r.mode,
78
+ url: r.url ?? null,
79
+ key: r.key ?? null,
80
+ allowedHosts: r.allowedHosts !== undefined ? [...r.allowedHosts] : null,
81
+ instanceId: instanceId ?? null,
82
+ // Seeds only matter in local mode; remote ignores them, so an env-only
83
+ // implicit start followed by start({ controlPoints }) under a key is not a conflict.
84
+ ...(r.mode === 'local' ? { controlPoints: (0, control_points_js_1.toLocalControlPoints)(r.controlPoints) } : {}),
85
+ });
86
+ function localLine(r) {
87
+ const why = r.modeSource === 'option'
88
+ ? "start({ mode: 'local' })"
89
+ : `no FIREWEAVE_KEY; environment '${r.environment ?? ''}' from ${r.environmentSource ?? 'env'}`;
90
+ const n = Object.keys(r.controlPoints).length;
91
+ return `[fireweave:local] Local mode (${why}). Serving ${n} control point${n === 1 ? '' : 's'} from your control-points object; nothing is sent to fw-server.`;
92
+ }
93
+ /** The kind the core's remote adapter reports for an HTTP status, or undefined for a success. */
94
+ function kindForStatus(status) {
95
+ if (status < 400)
96
+ return undefined;
97
+ if (status === 401)
98
+ return 'Authentication';
99
+ if (status === 403)
100
+ return 'Authorization';
101
+ if (status === 429)
102
+ return 'RateLimited';
103
+ return 'BackendUnavailable';
104
+ }
105
+ /**
106
+ * SP-27: a refused key, a rate limit or an unreachable fw-server is logged
107
+ * once per group for the life of the process and kept as lastErrorKind, so a
108
+ * revoked key does not look like a rollout at 0%. Lines name the key's source
109
+ * and the host, never the key.
110
+ */
111
+ function observeFailure(s, token, r, kind, detail) {
112
+ if (s.ready !== token)
113
+ return; // a response for a client that was shut down or replaced
114
+ s.lastErrorKind = kind;
115
+ const host = r.url !== undefined ? new URL(r.url).host : 'fw-server';
116
+ let group;
117
+ let line;
118
+ switch (kind) {
119
+ case 'Authentication':
120
+ group = 'key-rejected-401';
121
+ line = `[fireweave] fw-server at ${host} rejected the key from ${r.keySource} (HTTP 401): it is wrong, revoked or from another project. Reads serve their defaults; this is not a rollout at 0%.`;
122
+ break;
123
+ case 'Authorization':
124
+ group = 'key-rejected-403';
125
+ line = `[fireweave] fw-server at ${host} refused the key from ${r.keySource} for this project or environment (HTTP 403). Reads serve their defaults; this is not a rollout at 0%.`;
126
+ break;
127
+ case 'RateLimited':
128
+ group = 'rate-limited';
129
+ line = `[fireweave] fw-server at ${host} rate-limited the key from ${r.keySource} (HTTP 429). Reads serve their defaults until a request succeeds.`;
130
+ break;
131
+ default:
132
+ group = 'unreachable';
133
+ line = `[fireweave] Could not reach fw-server at ${host} (endpoint from ${r.urlSource ?? 'the SDK channel'}; ${detail}): offline, a firewall, or the wrong endpoint. Reads serve their defaults until a request succeeds.`;
134
+ }
135
+ if (s.diagnosed.has(group))
136
+ return;
137
+ s.diagnosed.add(group);
138
+ try {
139
+ s.log(line);
140
+ }
141
+ catch {
142
+ // A faulty log sink must not turn into a transport failure.
143
+ }
144
+ }
145
+ /** The transport handed to the core, observed. The core's behaviour is unchanged. */
146
+ function observedTransport(s, token, r, base) {
147
+ return async (url, init) => {
148
+ const call = base ?? globalThis.fetch;
149
+ let response;
150
+ try {
151
+ response = await call(url, init);
152
+ }
153
+ catch (err) {
154
+ // The same split the core makes: its own deadline aborts the request.
155
+ const timedOut = err instanceof Error && err.name === 'AbortError';
156
+ observeFailure(s, token, r, timedOut ? 'Timeout' : 'Network', timedOut ? 'timed out' : 'network error');
157
+ throw err;
158
+ }
159
+ const kind = kindForStatus(response.status);
160
+ if (kind !== undefined)
161
+ observeFailure(s, token, r, kind, `HTTP ${response.status}`);
162
+ return response;
163
+ };
164
+ }
165
+ function initOptions(r, options, s, token) {
166
+ if (r.mode === 'local') {
167
+ return { mode: 'local', local: { controlPoints: (0, control_points_js_1.toLocalControlPoints)(r.controlPoints), log: (line) => s.log(line) } };
168
+ }
169
+ return {
170
+ mode: 'remote',
171
+ apiKey: r.key,
172
+ apiUrl: r.url,
173
+ ...(r.allowedHosts !== undefined ? { allowedHosts: r.allowedHosts } : {}),
174
+ fetch: observedTransport(s, token, r, options.fetch),
175
+ };
176
+ }
177
+ /** Start FireWeave for this process. Synchronous; call once, from src/fireweave/start.ts. */
178
+ function start(options = {}) {
179
+ startWith(options, false);
180
+ }
181
+ function startWith(options, implicit) {
182
+ const s = slot();
183
+ if (s.state === 'shutdown' || s.state === 'failed') {
184
+ // Warnings and fw-server failure lines are once per process, across restarts.
185
+ Object.assign(s, freshSlot(), { warned: s.warned, diagnosed: s.diagnosed });
186
+ delete s.lastErrorKind; // freshSlot() has no such key, so assign alone would keep it
187
+ }
188
+ const read = options.env !== undefined ? (0, env_js_1.envFromBag)(options.env) : (0, env_js_1.processEnv)();
189
+ const resolved = (0, resolve_js_1.resolveStart)(options, read, { version: build_info_js_1.SDK_VERSION, channel: build_info_js_1.SDK_CHANNEL });
190
+ const signature = signatureOf(resolved, options.instanceId);
191
+ if (s.state === 'starting' || s.state === 'ready') {
192
+ if (signature === s.signature)
193
+ return;
194
+ throw new index_js_1.FireweaveError('Configuration', {
195
+ message: s.implicit
196
+ ? "[fireweave] A control point was read before start() ran, so FireWeave started from the environment alone. Import './fireweave/start' as the first import of your entrypoint."
197
+ : '[fireweave] start() was already called with a different configuration. Call start() once, from src/fireweave/start.ts.',
198
+ });
199
+ }
200
+ if (options.instanceId !== undefined && s.instance !== undefined && s.instance.value !== options.instanceId) {
201
+ throw new index_js_1.FireweaveError('Configuration', {
202
+ message: '[fireweave] start({ instanceId }) differs from the instanceKey() already handed out. Pass instanceId on the first start().',
203
+ });
204
+ }
205
+ // Only a start that actually begins sets the log sink: an identical second
206
+ // start() is a no-op and a conflicting one throws, and neither may swap it.
207
+ if (!implicit && options.log !== undefined)
208
+ s.log = options.log;
209
+ s.state = 'starting';
210
+ s.signature = signature;
211
+ s.implicit = implicit;
212
+ s.resolved = resolved;
213
+ s.read = read;
214
+ if (options.instanceId !== undefined)
215
+ s.instanceIdOption = options.instanceId;
216
+ for (const w of resolved.warnings)
217
+ warnOnce(s, w);
218
+ if (resolved.mode === 'local')
219
+ s.log(localLine(resolved));
220
+ const ready = s.ready;
221
+ const pending = (0, index_js_1.initFireweave)(initOptions(resolved, options, s, ready)).then((client) => {
222
+ if (s.ready !== ready)
223
+ return undefined; // superseded by shutdown/restart
224
+ s.state = 'ready';
225
+ s.client = client;
226
+ return client;
227
+ }, (err) => {
228
+ if (s.ready !== ready)
229
+ return undefined;
230
+ s.state = 'failed';
231
+ s.error = (0, index_js_1.isFireweaveError)(err) ? err : new index_js_1.FireweaveError('Internal', { cause: err });
232
+ warnOnce(s, `[fireweave] start failed: ${s.error.message}. Reads serve their defaults.`);
233
+ return undefined;
234
+ });
235
+ ready.resolve(pending);
236
+ }
237
+ /** The client once start() settles; undefined when start failed. Schedules an implicit start if none ran. */
238
+ function ensureClient() {
239
+ const s = slot();
240
+ if (s.state === 'unstarted' && !s.implicitScheduled) {
241
+ s.implicitScheduled = true;
242
+ setTimeout(() => {
243
+ if (s.state !== 'unstarted')
244
+ return;
245
+ try {
246
+ startWith({}, true);
247
+ }
248
+ catch (err) {
249
+ s.state = 'failed';
250
+ s.error = (0, index_js_1.isFireweaveError)(err) ? err : new index_js_1.FireweaveError('Internal', { cause: err });
251
+ warnOnce(s, `${s.error.message} (FireWeave was not started; reads serve their defaults.)`);
252
+ s.ready.resolve(undefined);
253
+ }
254
+ }, 0);
255
+ }
256
+ return s.ready.promise;
257
+ }
258
+ function currentStatus() {
259
+ const s = slot();
260
+ const r = s.resolved;
261
+ return {
262
+ state: s.state,
263
+ channel: r?.channel ?? build_info_js_1.SDK_CHANNEL,
264
+ sdkVersion: r?.sdkVersion ?? build_info_js_1.SDK_VERSION,
265
+ ...(r !== undefined
266
+ ? {
267
+ mode: r.mode,
268
+ modeSource: r.modeSource,
269
+ keySource: r.keySource,
270
+ controlPointCount: Object.keys(r.controlPoints).length,
271
+ ...(r.url !== undefined ? { host: new URL(r.url).hostname, endpointSource: r.urlSource } : {}),
272
+ ...(r.environment !== undefined ? { environment: r.environment } : {}),
273
+ }
274
+ : {}),
275
+ ...(s.error !== undefined ? { error: s.error.message } : {}),
276
+ ...(s.lastErrorKind !== undefined ? { lastErrorKind: s.lastErrorKind } : {}),
277
+ };
278
+ }
279
+ function instanceKeyFor() {
280
+ const s = slot();
281
+ if (s.instance === undefined)
282
+ s.instance = (0, instance_js_1.deriveInstanceKey)(s.instanceIdOption, s.read ?? (0, env_js_1.processEnv)());
283
+ return s.instance.value;
284
+ }
285
+ async function shutdownSlot() {
286
+ const s = slot();
287
+ const client = s.state === 'starting' ? await s.ready.promise : s.client;
288
+ s.state = 'shutdown';
289
+ s.client = undefined;
290
+ s.ready = deferred();
291
+ s.ready.resolve(undefined);
292
+ s.implicitScheduled = true; // no implicit restart after an explicit shutdown
293
+ if (client !== undefined)
294
+ await client.shutdown();
295
+ }
296
+ /** Test only: shut down and forget the singleton so the next start() begins fresh. */
297
+ async function resetForTests() {
298
+ const g = globalThis;
299
+ const s = g[SLOT_KEY];
300
+ if (s?.client !== undefined)
301
+ await s.client.shutdown().catch(() => undefined);
302
+ delete g[SLOT_KEY];
303
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@fireweaveai/server-sdk-cjs",
3
+ "version": "0.0.0-reserve.0",
4
+ "description": "CommonJS build of @fireweaveai/server-sdk, for require() and toolchains without ESM support. Fireweave release-engineering SDK for server runtimes (Node, Bun, Deno): control points and target registration. Zero runtime dependencies (spec v0.1.0).",
5
+ "license": "MIT",
6
+ "engines": {
7
+ "node": ">=20.20"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/FireWeave-HQ/fireweave-sdk.git",
12
+ "directory": "sdks/node"
13
+ },
14
+ "homepage": "https://github.com/FireWeave-HQ/fireweave-sdk/tree/master/sdks/node#readme",
15
+ "bugs": "https://github.com/FireWeave-HQ/fireweave-sdk/issues",
16
+ "type": "commonjs",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "typesVersions": {
20
+ "*": {
21
+ "start": [
22
+ "./dist/start/index.d.ts"
23
+ ],
24
+ "register": [
25
+ "./dist/register.d.ts"
26
+ ]
27
+ }
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./start": {
35
+ "types": "./dist/start/index.d.ts",
36
+ "browser": "./dist/start/browser.js",
37
+ "default": "./dist/start/index.js"
38
+ },
39
+ "./register": {
40
+ "types": "./dist/register.d.ts",
41
+ "browser": "./dist/register-browser.js",
42
+ "default": "./dist/register.js"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "keywords": [
49
+ "fireweave",
50
+ "release-engineering",
51
+ "progressive-delivery",
52
+ "control-points",
53
+ "feature-flags",
54
+ "server",
55
+ "bun",
56
+ "deno"
57
+ ]
58
+ }