@rift-vs/rift-embedded 0.12.1-snapshot.104.g9a93306

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 (49) hide show
  1. package/dist/admin.d.ts +134 -0
  2. package/dist/admin.d.ts.map +1 -0
  3. package/dist/admin.js +310 -0
  4. package/dist/admin.js.map +1 -0
  5. package/dist/bridge.d.ts +42 -0
  6. package/dist/bridge.d.ts.map +1 -0
  7. package/dist/bridge.js +53 -0
  8. package/dist/bridge.js.map +1 -0
  9. package/dist/create.d.ts +26 -0
  10. package/dist/create.d.ts.map +1 -0
  11. package/dist/create.js +90 -0
  12. package/dist/create.js.map +1 -0
  13. package/dist/debug-trace.d.ts +2 -0
  14. package/dist/debug-trace.d.ts.map +1 -0
  15. package/dist/debug-trace.js +27 -0
  16. package/dist/debug-trace.js.map +1 -0
  17. package/dist/ffi.d.ts +41 -0
  18. package/dist/ffi.d.ts.map +1 -0
  19. package/dist/ffi.js +165 -0
  20. package/dist/ffi.js.map +1 -0
  21. package/dist/index.d.ts +28 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +21 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/intercept-backend.d.ts +31 -0
  26. package/dist/intercept-backend.d.ts.map +1 -0
  27. package/dist/intercept-backend.js +37 -0
  28. package/dist/intercept-backend.js.map +1 -0
  29. package/dist/native-binding.d.ts +53 -0
  30. package/dist/native-binding.d.ts.map +1 -0
  31. package/dist/native-binding.js +35 -0
  32. package/dist/native-binding.js.map +1 -0
  33. package/dist/native-call.d.ts +77 -0
  34. package/dist/native-call.d.ts.map +1 -0
  35. package/dist/native-call.js +118 -0
  36. package/dist/native-call.js.map +1 -0
  37. package/dist/native.d.ts +76 -0
  38. package/dist/native.d.ts.map +1 -0
  39. package/dist/native.js +304 -0
  40. package/dist/native.js.map +1 -0
  41. package/dist/protocol.d.ts +30 -0
  42. package/dist/protocol.d.ts.map +1 -0
  43. package/dist/protocol.js +7 -0
  44. package/dist/protocol.js.map +1 -0
  45. package/dist/worker.d.ts +13 -0
  46. package/dist/worker.d.ts.map +1 -0
  47. package/dist/worker.js +86 -0
  48. package/dist/worker.js.map +1 -0
  49. package/package.json +49 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The FFI call discipline (issue #8) — pure, koffi-free, unit-testable against a fake
3
+ * `NativeBinding`. Implements the last-error + decode + free contract every `librift_ffi` call
4
+ * must follow:
5
+ *
6
+ * - A per-return-kind SENTINEL (`NULL` for `char*`/handle fns, `0` for `rift_create_imposter`,
7
+ * `-1` for `int32` fns) means failure — read `rift_last_error()`; a populated slot decodes to
8
+ * the engine's diagnostic (and gets freed), an empty slot ("no diagnostic") gets a generic,
9
+ * fn-named message instead.
10
+ * - A non-sentinel `char*` success gets decoded to a JS string and freed.
11
+ * - Numeric/void successes pass through untouched — nothing to free.
12
+ *
13
+ * `rift_build_info` is deliberately NOT part of this dispatch table: it's a static, always-present
14
+ * probe read once at init via {@link readBuildInfo}, bypassing the sentinel path, and it is never
15
+ * freed (freeing a `const char*` the library owns statically would be a use-after-free/heap
16
+ * corruption bug on the native side).
17
+ */
18
+ import type { NativeBinding, NativeCallableFn, NativePtr } from './native-binding.js';
19
+ /** The worker's native state: the koffi binding, its decode fn, and the `RiftHandle*` from
20
+ * `rift_start` (worker-local — never crosses the structured-clone boundary). */
21
+ export interface WorkerNativeState {
22
+ binding: NativeBinding;
23
+ decode: Decode;
24
+ handle: NativePtr;
25
+ }
26
+ /** Decodes a raw native pointer to a JS string. In production this is `(p) => koffi.decode(p,
27
+ * 'string')`; tests inject a fake so this module never has to import koffi. */
28
+ export type Decode = (ptr: NativePtr) => string;
29
+ export interface NativeCallRequest {
30
+ id: number;
31
+ fn: NativeCallableFn;
32
+ args: unknown[];
33
+ }
34
+ export interface NativeCallError {
35
+ message: string;
36
+ fn: string;
37
+ }
38
+ export interface NativeCallOk {
39
+ id: number;
40
+ ok: true;
41
+ value: string | number | null;
42
+ }
43
+ export interface NativeCallErr {
44
+ id: number;
45
+ ok: false;
46
+ error: NativeCallError;
47
+ }
48
+ export type NativeCallResponse = NativeCallOk | NativeCallErr;
49
+ /**
50
+ * Reads and clears the last-error slot, producing the discipline's two failure shapes: the
51
+ * engine's own diagnostic when the slot is populated (freed after decode), or a generic
52
+ * "no diagnostic" message when it's empty — still a failure, just an undiagnosed one, never
53
+ * swallowed into a success. Shared by `handleCall`'s sentinel path and by the worker's
54
+ * `rift_start`-returned-NULL init failure, which needs the exact same discipline outside the
55
+ * dispatch table `handleCall` covers.
56
+ */
57
+ export declare function readLastErrorMessage(binding: NativeBinding, decode: Decode, fn: string): NativeCallError;
58
+ /** Reads the static `rift_build_info` string. Deliberately bypasses the sentinel path — it's
59
+ * always present by construction — and never frees the pointer (it's static, library-owned). */
60
+ export declare function readBuildInfo(binding: NativeBinding, decode: Decode): string;
61
+ /**
62
+ * Invokes `binding[req.fn](...req.args)` and applies the last-error + decode + free discipline
63
+ * described above. Pure and synchronous: its only I/O is calling the given `binding`/`decode`,
64
+ * which is exactly what makes it unit-testable with a FAKE binding — no worker thread, no koffi,
65
+ * no cdylib required.
66
+ */
67
+ export declare function handleCall(binding: NativeBinding, req: NativeCallRequest, decode: Decode): NativeCallResponse;
68
+ /**
69
+ * Dispatches a worker `call` message against the worker's native state: rejects a pre-init call,
70
+ * prepends the worker-local `handle` to the args, and — crucially — converts ANY throw out of the
71
+ * native call (a koffi arg/type mismatch, a bad pointer into `decode`, the exhaustiveness guards
72
+ * above) into an error response carrying `id`. Without this, a throwing call would escape the
73
+ * worker's message handler, emit `'error'` on the parent Worker, and never post a result — hanging
74
+ * the caller and risking a host-process crash. Pure and testable with a fake `WorkerNativeState`.
75
+ */
76
+ export declare function handleCallMessage(native: WorkerNativeState | null, req: NativeCallRequest): NativeCallResponse;
77
+ //# sourceMappingURL=native-call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-call.d.ts","sourceRoot":"","sources":["../src/native-call.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,SAAS,EAAc,MAAM,qBAAqB,CAAC;AAElG;gFACgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;CACnB;AAED;+EAC+E;AAC/E,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,aAAa,CAAC;AAO9D;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,eAAe,CAQxG;AAED;gGACgG;AAChG,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5E;AAmBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAyB7G;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,GAAG,EAAE,iBAAiB,GACrB,kBAAkB,CAqBpB"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The FFI call discipline (issue #8) — pure, koffi-free, unit-testable against a fake
3
+ * `NativeBinding`. Implements the last-error + decode + free contract every `librift_ffi` call
4
+ * must follow:
5
+ *
6
+ * - A per-return-kind SENTINEL (`NULL` for `char*`/handle fns, `0` for `rift_create_imposter`,
7
+ * `-1` for `int32` fns) means failure — read `rift_last_error()`; a populated slot decodes to
8
+ * the engine's diagnostic (and gets freed), an empty slot ("no diagnostic") gets a generic,
9
+ * fn-named message instead.
10
+ * - A non-sentinel `char*` success gets decoded to a JS string and freed.
11
+ * - Numeric/void successes pass through untouched — nothing to free.
12
+ *
13
+ * `rift_build_info` is deliberately NOT part of this dispatch table: it's a static, always-present
14
+ * probe read once at init via {@link readBuildInfo}, bypassing the sentinel path, and it is never
15
+ * freed (freeing a `const char*` the library owns statically would be a use-after-free/heap
16
+ * corruption bug on the native side).
17
+ */
18
+ import { RETURN_KIND } from './native-binding.js';
19
+ function invoke(binding, fn, args) {
20
+ const method = binding[fn];
21
+ return method.apply(binding, args);
22
+ }
23
+ /**
24
+ * Reads and clears the last-error slot, producing the discipline's two failure shapes: the
25
+ * engine's own diagnostic when the slot is populated (freed after decode), or a generic
26
+ * "no diagnostic" message when it's empty — still a failure, just an undiagnosed one, never
27
+ * swallowed into a success. Shared by `handleCall`'s sentinel path and by the worker's
28
+ * `rift_start`-returned-NULL init failure, which needs the exact same discipline outside the
29
+ * dispatch table `handleCall` covers.
30
+ */
31
+ export function readLastErrorMessage(binding, decode, fn) {
32
+ const errPtr = binding.rift_last_error();
33
+ if (errPtr === null) {
34
+ return { message: `${fn} failed with no engine diagnostic`, fn };
35
+ }
36
+ const message = decode(errPtr);
37
+ binding.rift_free(errPtr);
38
+ return { message, fn };
39
+ }
40
+ /** Reads the static `rift_build_info` string. Deliberately bypasses the sentinel path — it's
41
+ * always present by construction — and never frees the pointer (it's static, library-owned). */
42
+ export function readBuildInfo(binding, decode) {
43
+ return decode(binding.rift_build_info());
44
+ }
45
+ function isSentinel(kind, result) {
46
+ switch (kind) {
47
+ case 'uint16':
48
+ return result === 0;
49
+ case 'int32':
50
+ return result === -1;
51
+ case 'string':
52
+ return result === null;
53
+ case 'void':
54
+ return false;
55
+ default: {
56
+ const exhaustive = kind;
57
+ throw new Error(`native-call: unhandled return kind ${String(exhaustive)}`);
58
+ }
59
+ }
60
+ }
61
+ /**
62
+ * Invokes `binding[req.fn](...req.args)` and applies the last-error + decode + free discipline
63
+ * described above. Pure and synchronous: its only I/O is calling the given `binding`/`decode`,
64
+ * which is exactly what makes it unit-testable with a FAKE binding — no worker thread, no koffi,
65
+ * no cdylib required.
66
+ */
67
+ export function handleCall(binding, req, decode) {
68
+ const { id, fn, args } = req;
69
+ const kind = RETURN_KIND[fn];
70
+ const result = invoke(binding, fn, args);
71
+ if (isSentinel(kind, result)) {
72
+ return { id, ok: false, error: readLastErrorMessage(binding, decode, fn) };
73
+ }
74
+ switch (kind) {
75
+ case 'void':
76
+ return { id, ok: true, value: null };
77
+ case 'uint16':
78
+ case 'int32':
79
+ return { id, ok: true, value: result };
80
+ case 'string': {
81
+ const value = decode(result);
82
+ binding.rift_free(result);
83
+ return { id, ok: true, value };
84
+ }
85
+ default: {
86
+ const exhaustive = kind;
87
+ throw new Error(`native-call: unhandled return kind ${String(exhaustive)}`);
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Dispatches a worker `call` message against the worker's native state: rejects a pre-init call,
93
+ * prepends the worker-local `handle` to the args, and — crucially — converts ANY throw out of the
94
+ * native call (a koffi arg/type mismatch, a bad pointer into `decode`, the exhaustiveness guards
95
+ * above) into an error response carrying `id`. Without this, a throwing call would escape the
96
+ * worker's message handler, emit `'error'` on the parent Worker, and never post a result — hanging
97
+ * the caller and risking a host-process crash. Pure and testable with a fake `WorkerNativeState`.
98
+ */
99
+ export function handleCallMessage(native, req) {
100
+ if (native === null) {
101
+ return {
102
+ id: req.id,
103
+ ok: false,
104
+ error: { message: 'embedded worker received a call before init completed', fn: req.fn },
105
+ };
106
+ }
107
+ try {
108
+ return handleCall(native.binding, { id: req.id, fn: req.fn, args: [native.handle, ...req.args] }, native.decode);
109
+ }
110
+ catch (err) {
111
+ return {
112
+ id: req.id,
113
+ ok: false,
114
+ error: { message: err instanceof Error ? err.message : String(err), fn: req.fn },
115
+ };
116
+ }
117
+ }
118
+ //# sourceMappingURL=native-call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-call.js","sourceRoot":"","sources":["../src/native-call.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * `NativeEngine` — the embedded transport's main-thread facade (issue #8).
3
+ *
4
+ * Owns the worker_threads lifecycle and the request/response correlation on top of the protocol
5
+ * in `protocol.ts`; the actual FFI discipline lives in `native-call.ts` and runs inside
6
+ * `worker.ts`, not here. `load()` spawns the worker, sends `{type:'init', libPath}`, and awaits
7
+ * `{type:'ready'}`/`{type:'init-error'}`. `close()` is idempotent, rejects in-flight calls with a
8
+ * clear error, and force-`terminate()`s if the worker doesn't exit within the shutdown timeout.
9
+ *
10
+ * The worker transport is injectable (`createWorker`) precisely so this protocol is unit-testable
11
+ * without spawning a real `worker_threads.Worker` — see `test/unit/embedded-worker.test.ts`.
12
+ */
13
+ /** The subset of `worker_threads.Worker`'s surface `NativeEngine` depends on — small enough that
14
+ * tests can satisfy it with a plain fake, and a real `Worker` satisfies it structurally as-is. */
15
+ export interface WorkerLike {
16
+ postMessage(message: unknown): void;
17
+ on(event: string, listener: (...args: unknown[]) => void): void;
18
+ off(event: string, listener: (...args: unknown[]) => void): void;
19
+ terminate(): Promise<number>;
20
+ ref(): void;
21
+ unref(): void;
22
+ }
23
+ export interface NativeEngineLoadOptions {
24
+ /** Injectable worker transport; defaults to a real `worker_threads.Worker` running `worker.js`. */
25
+ createWorker?: () => WorkerLike;
26
+ /** Keep the worker (and therefore the process) alive while the engine is open, instead of only
27
+ * while a call is in flight — the standalone mock-server shape (#70). Default false: an idle
28
+ * engine never blocks process exit. */
29
+ keepAlive?: boolean;
30
+ }
31
+ export declare class NativeEngine {
32
+ #private;
33
+ readonly buildInfo: string;
34
+ private constructor();
35
+ /**
36
+ * Spawns the worker, performs the init handshake, and resolves once it reports `ready`. Rejects
37
+ * with a `NativeLibraryError` on `init-error` (koffi missing, cdylib missing/incompatible, ABI
38
+ * v1), terminating the worker first so a failed load never leaks a thread.
39
+ */
40
+ static load(libPath: string, opts?: NativeEngineLoadOptions): Promise<NativeEngine>;
41
+ /**
42
+ * Idempotent: a second `close()` returns the same in-flight/completed close. Rejects every
43
+ * currently-pending call with a clear "closing" error (never lets one dangle waiting on a
44
+ * response that a shutting-down worker may never send), then asks the worker to stop gracefully;
45
+ * if it hasn't exited within {@link SHUTDOWN_TIMEOUT_MS}, force-`terminate()`s it.
46
+ */
47
+ close(): Promise<void>;
48
+ createImposter(json: string): Promise<number>;
49
+ replaceStubs(port: number, json: string): Promise<number>;
50
+ deleteImposter(port: number): Promise<number>;
51
+ deleteAll(): Promise<number>;
52
+ applyConfig(json: string): Promise<string>;
53
+ recorded(port: number): Promise<string>;
54
+ stubWarnings(port: number): Promise<string>;
55
+ /** `found: false` means the key simply isn't set — NOT an error; `rift_flow_state_get` always
56
+ * succeeds structurally (a real failure, e.g. an unknown port, still goes through the sentinel
57
+ * path and rejects). */
58
+ flowStateGet(port: number, flowId: string, key: string): Promise<{
59
+ found: boolean;
60
+ value?: unknown;
61
+ }>;
62
+ flowStatePut(port: number, flowId: string, key: string, valueJson: string): Promise<number>;
63
+ flowStateDelete(port: number, flowId: string, key: string): Promise<number>;
64
+ spaceAddStub(port: number, flowId: string, json: string): Promise<number>;
65
+ spaceListStubs(port: number, flowId: string): Promise<string>;
66
+ spaceDelete(port: number, flowId: string): Promise<number>;
67
+ spaceRecorded(port: number, flowId: string): Promise<string>;
68
+ startIntercept(optionsJson: string): Promise<Record<string, unknown>>;
69
+ interceptAddRules(json: string): Promise<number>;
70
+ interceptClearRules(): Promise<number>;
71
+ interceptListRules(): Promise<string>;
72
+ interceptCaPem(): Promise<string>;
73
+ interceptExportTruststore(format: string, password: string, outPath: string): Promise<number>;
74
+ serveAdmin(optionsJson: string): Promise<Record<string, unknown>>;
75
+ }
76
+ //# sourceMappingURL=native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
package/dist/native.js ADDED
@@ -0,0 +1,304 @@
1
+ /**
2
+ * `NativeEngine` — the embedded transport's main-thread facade (issue #8).
3
+ *
4
+ * Owns the worker_threads lifecycle and the request/response correlation on top of the protocol
5
+ * in `protocol.ts`; the actual FFI discipline lives in `native-call.ts` and runs inside
6
+ * `worker.ts`, not here. `load()` spawns the worker, sends `{type:'init', libPath}`, and awaits
7
+ * `{type:'ready'}`/`{type:'init-error'}`. `close()` is idempotent, rejects in-flight calls with a
8
+ * clear error, and force-`terminate()`s if the worker doesn't exit within the shutdown timeout.
9
+ *
10
+ * The worker transport is injectable (`createWorker`) precisely so this protocol is unit-testable
11
+ * without spawning a real `worker_threads.Worker` — see `test/unit/embedded-worker.test.ts`.
12
+ */
13
+ import { Worker } from 'worker_threads';
14
+ import { EngineUnavailable, NativeLibraryError, RiftError } from '@rift-vs/rift';
15
+ const SHUTDOWN_TIMEOUT_MS = 5000;
16
+ function defaultCreateWorker() {
17
+ const url = new URL('./worker.js', import.meta.url);
18
+ return new Worker(url);
19
+ }
20
+ export class NativeEngine {
21
+ buildInfo;
22
+ #worker;
23
+ #nextId = 1;
24
+ #pending = new Map();
25
+ #state = 'open';
26
+ #closePromise = null;
27
+ #exitHandler = null;
28
+ #keepAlive;
29
+ constructor(worker, buildInfo, keepAlive) {
30
+ this.#worker = worker;
31
+ this.buildInfo = buildInfo;
32
+ this.#keepAlive = keepAlive;
33
+ worker.on('message', (raw) => this.#onMessage(raw));
34
+ worker.on('exit', () => this.#onUnexpectedExit());
35
+ // A post-init uncaught throw in the worker emits 'error'; with NO listener, Node's default is to
36
+ // rethrow on the main thread and crash the whole host process. Handle it: reject in-flight calls
37
+ // and mark the engine dead, turning a native fault into a recoverable error, not a crash.
38
+ worker.on('error', (err) => this.#onWorkerError(err));
39
+ this.#exitHandler = () => {
40
+ try {
41
+ worker.postMessage({ type: 'shutdown' });
42
+ }
43
+ catch {
44
+ // best-effort: the process is already tearing down.
45
+ }
46
+ };
47
+ process.on('exit', this.#exitHandler);
48
+ }
49
+ /**
50
+ * Spawns the worker, performs the init handshake, and resolves once it reports `ready`. Rejects
51
+ * with a `NativeLibraryError` on `init-error` (koffi missing, cdylib missing/incompatible, ABI
52
+ * v1), terminating the worker first so a failed load never leaks a thread.
53
+ */
54
+ static async load(libPath, opts = {}) {
55
+ const createWorker = opts.createWorker ?? defaultCreateWorker;
56
+ const worker = createWorker();
57
+ const handshake = new Promise((resolve, reject) => {
58
+ const onMessage = (raw) => {
59
+ const msg = raw;
60
+ if (msg.type === 'ready') {
61
+ cleanup();
62
+ resolve({ buildInfo: msg.buildInfo });
63
+ }
64
+ else if (msg.type === 'init-error') {
65
+ cleanup();
66
+ reject(new NativeLibraryError(msg.message, { path: libPath }));
67
+ }
68
+ };
69
+ const onError = (err) => {
70
+ cleanup();
71
+ reject(err instanceof Error ? err : new Error(String(err)));
72
+ };
73
+ const onExit = () => {
74
+ cleanup();
75
+ reject(new NativeLibraryError('embedded worker exited during init', { path: libPath }));
76
+ };
77
+ const cleanup = () => {
78
+ worker.off('message', onMessage);
79
+ worker.off('error', onError);
80
+ worker.off('exit', onExit);
81
+ };
82
+ worker.on('message', onMessage);
83
+ worker.on('error', onError);
84
+ worker.on('exit', onExit);
85
+ });
86
+ worker.postMessage({ type: 'init', libPath });
87
+ let ready;
88
+ try {
89
+ ready = await handshake;
90
+ }
91
+ catch (err) {
92
+ try {
93
+ await worker.terminate();
94
+ }
95
+ catch {
96
+ // best-effort cleanup of a worker that never finished initializing.
97
+ }
98
+ throw err;
99
+ }
100
+ const engine = new NativeEngine(worker, ready.buildInfo, opts.keepAlive === true);
101
+ // Idle engines must never block process exit — but ONLY idle ones: #call re-refs the worker
102
+ // while a call is in flight (an awaited call being dropped by loop-drain was #70), and
103
+ // `keepAlive` pins it for standalone mock-server processes.
104
+ if (opts.keepAlive !== true)
105
+ worker.unref();
106
+ return engine;
107
+ }
108
+ #onMessage(msg) {
109
+ if (msg.type !== 'result')
110
+ return;
111
+ const pending = this.#pending.get(msg.id);
112
+ if (!pending)
113
+ return; // late response for a call already rejected by close(), or unknown id.
114
+ this.#pending.delete(msg.id);
115
+ if (this.#pending.size === 0 && !this.#keepAlive)
116
+ this.#worker.unref();
117
+ if (msg.ok) {
118
+ pending.resolve(msg.value);
119
+ }
120
+ else {
121
+ pending.reject(new RiftError(`${msg.error.fn}: ${msg.error.message}`));
122
+ }
123
+ }
124
+ #onUnexpectedExit() {
125
+ if (this.#state !== 'open')
126
+ return; // exit is expected once close() is in progress.
127
+ this.#state = 'closed';
128
+ this.#rejectAllPending(new EngineUnavailable('embedded worker exited unexpectedly'));
129
+ this.#unregisterExitHandler();
130
+ }
131
+ #onWorkerError(err) {
132
+ if (this.#state === 'closed')
133
+ return; // a crash during/after close is moot.
134
+ this.#state = 'closed';
135
+ this.#rejectAllPending(new EngineUnavailable(`embedded worker crashed: ${err instanceof Error ? err.message : String(err)}`));
136
+ this.#unregisterExitHandler();
137
+ }
138
+ #rejectAllPending(err) {
139
+ const hadPending = this.#pending.size > 0;
140
+ for (const pending of this.#pending.values())
141
+ pending.reject(err);
142
+ this.#pending.clear();
143
+ // Drop the in-flight ref the drained calls were holding (a no-op on a terminated worker).
144
+ if (hadPending && !this.#keepAlive)
145
+ this.#worker.unref();
146
+ }
147
+ #unregisterExitHandler() {
148
+ if (this.#exitHandler) {
149
+ process.off('exit', this.#exitHandler);
150
+ this.#exitHandler = null;
151
+ }
152
+ }
153
+ #call(fn, args) {
154
+ if (this.#state !== 'open') {
155
+ return Promise.reject(new EngineUnavailable(`NativeEngine is ${this.#state}; cannot call ${fn}`));
156
+ }
157
+ const id = this.#nextId++;
158
+ return new Promise((resolve, reject) => {
159
+ // 0→1 transition holds the event loop for the duration of the in-flight window (#70): a bare
160
+ // script awaiting this call must not have Node drain the loop and exit with it unsettled.
161
+ if (this.#pending.size === 0 && !this.#keepAlive)
162
+ this.#worker.ref();
163
+ this.#pending.set(id, { fn, resolve: resolve, reject });
164
+ try {
165
+ this.#worker.postMessage({ type: 'call', id, fn, args });
166
+ }
167
+ catch (err) {
168
+ // A main-side postMessage throw (e.g. DataCloneError) never reaches the worker, so no
169
+ // response will ever drain this entry — undo the bookkeeping or the ref leaks forever.
170
+ this.#pending.delete(id);
171
+ if (this.#pending.size === 0 && !this.#keepAlive)
172
+ this.#worker.unref();
173
+ throw err;
174
+ }
175
+ });
176
+ }
177
+ /**
178
+ * Idempotent: a second `close()` returns the same in-flight/completed close. Rejects every
179
+ * currently-pending call with a clear "closing" error (never lets one dangle waiting on a
180
+ * response that a shutting-down worker may never send), then asks the worker to stop gracefully;
181
+ * if it hasn't exited within {@link SHUTDOWN_TIMEOUT_MS}, force-`terminate()`s it.
182
+ */
183
+ close() {
184
+ if (this.#state === 'closed')
185
+ return Promise.resolve();
186
+ if (this.#closePromise)
187
+ return this.#closePromise;
188
+ this.#state = 'closing';
189
+ this.#rejectAllPending(new EngineUnavailable('NativeEngine is closing'));
190
+ this.#closePromise = this.#doClose();
191
+ return this.#closePromise;
192
+ }
193
+ async #doClose() {
194
+ const exited = new Promise((resolve) => {
195
+ const onExit = () => {
196
+ this.#worker.off('exit', onExit);
197
+ resolve();
198
+ };
199
+ this.#worker.on('exit', onExit);
200
+ });
201
+ try {
202
+ this.#worker.postMessage({ type: 'shutdown' });
203
+ }
204
+ catch {
205
+ // worker channel already gone (e.g. it crashed) — fall through to the timeout/terminate path.
206
+ }
207
+ const TIMED_OUT = Symbol('shutdown-timeout');
208
+ // An explicit, clearable timer — a bare `sleep().then()` would leak a live 5s timer on the
209
+ // (common) fast-close path where `exited` wins the race, delaying host process exit.
210
+ let timer;
211
+ const timeout = new Promise((resolve) => {
212
+ timer = setTimeout(() => resolve(TIMED_OUT), SHUTDOWN_TIMEOUT_MS);
213
+ });
214
+ try {
215
+ const outcome = await Promise.race([exited.then(() => 'exited'), timeout]);
216
+ if (outcome === TIMED_OUT) {
217
+ try {
218
+ await this.#worker.terminate();
219
+ }
220
+ catch (err) {
221
+ // Nothing more we can do, but don't claim a clean close silently: the worker thread may
222
+ // still be alive (unref'd, so it won't hold the process open, but a native handle leaks).
223
+ console.error(`rift: embedded worker did not terminate cleanly: ${String(err)}`);
224
+ }
225
+ }
226
+ }
227
+ finally {
228
+ if (timer !== undefined)
229
+ clearTimeout(timer);
230
+ }
231
+ this.#state = 'closed';
232
+ this.#unregisterExitHandler();
233
+ }
234
+ createImposter(json) {
235
+ return this.#call('rift_create_imposter', [json]);
236
+ }
237
+ replaceStubs(port, json) {
238
+ return this.#call('rift_replace_stubs', [port, json]);
239
+ }
240
+ deleteImposter(port) {
241
+ return this.#call('rift_delete_imposter', [port]);
242
+ }
243
+ deleteAll() {
244
+ return this.#call('rift_delete_all', []);
245
+ }
246
+ applyConfig(json) {
247
+ return this.#call('rift_apply_config', [json]);
248
+ }
249
+ recorded(port) {
250
+ return this.#call('rift_recorded', [port]);
251
+ }
252
+ stubWarnings(port) {
253
+ return this.#call('rift_stub_warnings', [port]);
254
+ }
255
+ /** `found: false` means the key simply isn't set — NOT an error; `rift_flow_state_get` always
256
+ * succeeds structurally (a real failure, e.g. an unknown port, still goes through the sentinel
257
+ * path and rejects). */
258
+ async flowStateGet(port, flowId, key) {
259
+ const raw = await this.#call('rift_flow_state_get', [port, flowId, key]);
260
+ return JSON.parse(raw);
261
+ }
262
+ flowStatePut(port, flowId, key, valueJson) {
263
+ return this.#call('rift_flow_state_put', [port, flowId, key, valueJson]);
264
+ }
265
+ flowStateDelete(port, flowId, key) {
266
+ return this.#call('rift_flow_state_delete', [port, flowId, key]);
267
+ }
268
+ spaceAddStub(port, flowId, json) {
269
+ return this.#call('rift_space_add_stub', [port, flowId, json]);
270
+ }
271
+ spaceListStubs(port, flowId) {
272
+ return this.#call('rift_space_list_stubs', [port, flowId]);
273
+ }
274
+ spaceDelete(port, flowId) {
275
+ return this.#call('rift_space_delete', [port, flowId]);
276
+ }
277
+ spaceRecorded(port, flowId) {
278
+ return this.#call('rift_space_recorded', [port, flowId]);
279
+ }
280
+ async startIntercept(optionsJson) {
281
+ const raw = await this.#call('rift_start_intercept', [optionsJson]);
282
+ return JSON.parse(raw);
283
+ }
284
+ interceptAddRules(json) {
285
+ return this.#call('rift_intercept_add_rules', [json]);
286
+ }
287
+ interceptClearRules() {
288
+ return this.#call('rift_intercept_clear_rules', []);
289
+ }
290
+ interceptListRules() {
291
+ return this.#call('rift_intercept_list_rules', []);
292
+ }
293
+ interceptCaPem() {
294
+ return this.#call('rift_intercept_ca_pem', []);
295
+ }
296
+ interceptExportTruststore(format, password, outPath) {
297
+ return this.#call('rift_intercept_export_truststore', [format, password, outPath]);
298
+ }
299
+ async serveAdmin(optionsJson) {
300
+ const raw = await this.#call('rift_serve_admin', [optionsJson]);
301
+ return JSON.parse(raw);
302
+ }
303
+ }
304
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Message protocol between `native.ts` (the main-thread `NativeEngine` facade) and `worker.ts`
3
+ * (the worker_threads-side thin wrapper). Kept as plain, structurally-clonable data — no class
4
+ * instances, no pointers — since it crosses the worker `postMessage` boundary.
5
+ */
6
+ import type { NativeCallableFn } from './native-binding.js';
7
+ import type { NativeCallResponse } from './native-call.js';
8
+ export type ToWorkerMessage = {
9
+ type: 'init';
10
+ libPath: string;
11
+ } | {
12
+ type: 'call';
13
+ id: number;
14
+ fn: NativeCallableFn;
15
+ args: unknown[];
16
+ } | {
17
+ type: 'shutdown';
18
+ };
19
+ export type FromWorkerMessage = {
20
+ type: 'ready';
21
+ buildInfo: string;
22
+ } | {
23
+ type: 'init-error';
24
+ message: string;
25
+ } | ({
26
+ type: 'result';
27
+ } & NativeCallResponse) | {
28
+ type: 'shutdown-ack';
29
+ };
30
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvC,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,kBAAkB,CAAC,GACzC;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Message protocol between `native.ts` (the main-thread `NativeEngine` facade) and `worker.ts`
3
+ * (the worker_threads-side thin wrapper). Kept as plain, structurally-clonable data — no class
4
+ * instances, no pointers — since it crosses the worker `postMessage` boundary.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=protocol.js.map