@ricsam/isolate-server 0.0.1 → 0.2.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/README.md CHANGED
@@ -1,45 +1,55 @@
1
1
  # @ricsam/isolate-server
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
4
-
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
6
-
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
8
-
9
- ## Purpose
10
-
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@ricsam/isolate-server`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
-
16
- ## What is OIDC Trusted Publishing?
17
-
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
-
20
- ## Setup Instructions
21
-
22
- To properly configure OIDC trusted publishing for this package:
23
-
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
28
-
29
- ## DO NOT USE THIS PACKAGE
30
-
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
36
-
37
- ## More Information
38
-
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
42
-
43
- ---
44
-
45
- **Maintained for OIDC setup purposes only**
3
+ Reusable server lifecycle manager for `@ricsam/isolate-client` runtimes.
4
+
5
+ `IsolateServer` wraps namespaced runtime lifecycle (`start`, `reload`, `close`) and provides a stable
6
+ `fetch` proxy that can auto-start from the last successful configuration.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm add @ricsam/isolate-server
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```ts
17
+ import { IsolateServer } from "@ricsam/isolate-server";
18
+ import { connect } from "@ricsam/isolate-client";
19
+
20
+ const connection = await connect({ socket: "/tmp/isolate.sock" });
21
+
22
+ const server = new IsolateServer({
23
+ namespaceId: "project/main",
24
+ getConnection: async () => connection,
25
+ });
26
+
27
+ await server.start({
28
+ entry: "server.js",
29
+ runtimeOptions: {
30
+ moduleLoader: (specifier) => {
31
+ if (specifier === "server.js") {
32
+ return {
33
+ code: `serve({ fetch: () => new Response("ok") });`,
34
+ resolveDir: "/",
35
+ };
36
+ }
37
+ throw new Error(`Unknown module: ${specifier}`);
38
+ },
39
+ },
40
+ });
41
+
42
+ const response = await server.fetch.dispatchRequest(new Request("http://localhost/"));
43
+ console.log(await response.text()); // "ok"
44
+
45
+ await server.reload();
46
+ await server.close();
47
+ ```
48
+
49
+ ## API
50
+
51
+ - `start(options)` configures and starts the runtime (idempotent when already running).
52
+ - `reload()` disposes current runtime and starts again with the last start options.
53
+ - `close()` disposes current runtime (idempotent).
54
+ - `getRuntime()` returns the active runtime or `null`.
55
+ - `fetch.*` proxies to runtime fetch methods and auto-starts after an initial `start()`.
@@ -0,0 +1,210 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+
29
+ // packages/isolate-server/src/index.ts
30
+ var exports_src = {};
31
+ __export(exports_src, {
32
+ IsolateServer: () => IsolateServer
33
+ });
34
+ module.exports = __toCommonJS(exports_src);
35
+ var import_isolate_client = require("@ricsam/isolate-client");
36
+ var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
37
+ function isLinkerConflictError(error) {
38
+ const message = error instanceof Error ? error.message : String(error ?? "");
39
+ return message.includes(LINKER_CONFLICT_ERROR);
40
+ }
41
+
42
+ class IsolateServer {
43
+ namespaceId;
44
+ getConnection;
45
+ runtime = null;
46
+ lastStartOptions = null;
47
+ lifecycleLock = Promise.resolve();
48
+ closed = true;
49
+ fetch = {
50
+ dispatchRequest: (request, options) => this.dispatchRequestWithRetry(request, options),
51
+ getUpgradeRequest: async () => {
52
+ const runtime = await this.getActiveRuntime();
53
+ return runtime.fetch.getUpgradeRequest();
54
+ },
55
+ dispatchWebSocketOpen: async (connectionId) => {
56
+ const runtime = await this.getActiveRuntime();
57
+ await runtime.fetch.dispatchWebSocketOpen(connectionId);
58
+ },
59
+ dispatchWebSocketMessage: async (connectionId, message) => {
60
+ const runtime = await this.getActiveRuntime();
61
+ await runtime.fetch.dispatchWebSocketMessage(connectionId, message);
62
+ },
63
+ dispatchWebSocketClose: async (connectionId, code, reason) => {
64
+ const runtime = await this.getActiveRuntime();
65
+ await runtime.fetch.dispatchWebSocketClose(connectionId, code, reason);
66
+ },
67
+ dispatchWebSocketError: async (connectionId, error) => {
68
+ const runtime = await this.getActiveRuntime();
69
+ await runtime.fetch.dispatchWebSocketError(connectionId, error);
70
+ },
71
+ hasServeHandler: async () => {
72
+ const runtime = await this.getActiveRuntime();
73
+ return runtime.fetch.hasServeHandler();
74
+ },
75
+ hasActiveConnections: async () => {
76
+ const runtime = await this.getActiveRuntime();
77
+ return runtime.fetch.hasActiveConnections();
78
+ }
79
+ };
80
+ constructor(options) {
81
+ this.namespaceId = options.namespaceId;
82
+ this.getConnection = options.getConnection;
83
+ }
84
+ async start(options) {
85
+ this.lastStartOptions = options;
86
+ this.closed = false;
87
+ await this.withLifecycleLock(async () => {
88
+ if (this.runtime) {
89
+ return;
90
+ }
91
+ this.runtime = await this.createAndInitializeRuntime(options);
92
+ });
93
+ }
94
+ async reload() {
95
+ const startOptions = this.lastStartOptions;
96
+ if (!startOptions) {
97
+ throw new Error("Server not configured. Call start() first.");
98
+ }
99
+ this.closed = false;
100
+ await this.withLifecycleLock(async () => {
101
+ if (this.runtime) {
102
+ const runtime = this.runtime;
103
+ this.runtime = null;
104
+ await this.disposeRuntime(runtime);
105
+ }
106
+ this.runtime = await this.createAndInitializeRuntime(startOptions);
107
+ });
108
+ }
109
+ async close() {
110
+ await this.withLifecycleLock(async () => {
111
+ if (this.runtime) {
112
+ const runtime = this.runtime;
113
+ this.runtime = null;
114
+ await this.disposeRuntime(runtime);
115
+ }
116
+ this.closed = true;
117
+ });
118
+ }
119
+ getRuntime() {
120
+ return this.runtime;
121
+ }
122
+ async withLifecycleLock(operation) {
123
+ const previous = this.lifecycleLock;
124
+ let release;
125
+ this.lifecycleLock = new Promise((resolve) => {
126
+ release = resolve;
127
+ });
128
+ await previous;
129
+ try {
130
+ return await operation();
131
+ } finally {
132
+ release();
133
+ }
134
+ }
135
+ buildRuntimeOptions(options) {
136
+ if (options.onWebSocketCommand) {
137
+ return {
138
+ ...options.runtimeOptions,
139
+ onWebSocketCommand: options.onWebSocketCommand
140
+ };
141
+ }
142
+ return options.runtimeOptions;
143
+ }
144
+ async createAndInitializeRuntime(options, allowRetry = true) {
145
+ const connection = await this.getConnection();
146
+ const namespace = connection.createNamespace(this.namespaceId);
147
+ const runtimeOptions = this.buildRuntimeOptions(options);
148
+ const runtime = await namespace.createRuntime(runtimeOptions);
149
+ try {
150
+ await runtime.eval(`import ${JSON.stringify(options.entry)};`, options.entryFilename ?? "/isolate_server_entry.js");
151
+ return runtime;
152
+ } catch (error) {
153
+ await this.disposeRuntime(runtime);
154
+ if (!allowRetry || !isLinkerConflictError(error)) {
155
+ throw error;
156
+ }
157
+ const retryRuntime = await namespace.createRuntime(runtimeOptions);
158
+ try {
159
+ await retryRuntime.eval(`import ${JSON.stringify(options.entry)};`, options.entryFilename ?? "/isolate_server_entry.js");
160
+ return retryRuntime;
161
+ } catch (retryError) {
162
+ await this.disposeRuntime(retryRuntime);
163
+ throw retryError;
164
+ }
165
+ }
166
+ }
167
+ async disposeRuntime(runtime) {
168
+ try {
169
+ await runtime.dispose();
170
+ } catch (error) {
171
+ if (!import_isolate_client.isBenignDisposeError(error)) {
172
+ throw error;
173
+ }
174
+ }
175
+ }
176
+ async ensureStarted() {
177
+ if (this.runtime) {
178
+ return;
179
+ }
180
+ if (!this.lastStartOptions) {
181
+ throw new Error("Server not configured. Call start() first.");
182
+ }
183
+ if (this.closed) {
184
+ this.closed = false;
185
+ }
186
+ await this.start(this.lastStartOptions);
187
+ }
188
+ async getActiveRuntime() {
189
+ await this.ensureStarted();
190
+ if (!this.runtime) {
191
+ throw new Error("Server runtime failed to start.");
192
+ }
193
+ return this.runtime;
194
+ }
195
+ async dispatchRequestWithRetry(request, options) {
196
+ const runtime = await this.getActiveRuntime();
197
+ try {
198
+ return await runtime.fetch.dispatchRequest(request, options);
199
+ } catch (error) {
200
+ if (!isLinkerConflictError(error)) {
201
+ throw error;
202
+ }
203
+ await this.reload();
204
+ const retryRuntime = await this.getActiveRuntime();
205
+ return retryRuntime.fetch.dispatchRequest(request, options);
206
+ }
207
+ }
208
+ }
209
+
210
+ //# debugId=D8CA16D612F9756664756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n DaemonConnection,\n DispatchOptions,\n RemoteRuntime,\n RuntimeOptions,\n UpgradeRequest,\n WebSocketCommand,\n} from \"@ricsam/isolate-client\";\nimport { isBenignDisposeError } from \"@ricsam/isolate-client\";\n\nconst LINKER_CONFLICT_ERROR = \"Module is currently being linked by another linker\";\n\nfunction isLinkerConflictError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n return message.includes(LINKER_CONFLICT_ERROR);\n}\n\nexport interface IsolateServerOptions {\n namespaceId: string;\n getConnection: () => Promise<DaemonConnection>;\n}\n\nexport interface IsolateServerStartOptions {\n runtimeOptions: RuntimeOptions;\n entry: string;\n entryFilename?: string;\n onWebSocketCommand?: (cmd: WebSocketCommand) => void;\n}\n\nexport interface IsolateServerFetch {\n dispatchRequest(request: Request, options?: DispatchOptions): Promise<Response>;\n getUpgradeRequest(): Promise<UpgradeRequest | null>;\n dispatchWebSocketOpen(connectionId: string): Promise<void>;\n dispatchWebSocketMessage(connectionId: string, message: string | ArrayBuffer): Promise<void>;\n dispatchWebSocketClose(connectionId: string, code: number, reason: string): Promise<void>;\n dispatchWebSocketError(connectionId: string, error: Error): Promise<void>;\n hasServeHandler(): Promise<boolean>;\n hasActiveConnections(): Promise<boolean>;\n}\n\nexport class IsolateServer {\n private readonly namespaceId: string;\n private readonly getConnection: () => Promise<DaemonConnection>;\n private runtime: RemoteRuntime | null = null;\n private lastStartOptions: IsolateServerStartOptions | null = null;\n private lifecycleLock: Promise<void> = Promise.resolve();\n private closed = true;\n\n readonly fetch: IsolateServerFetch = {\n dispatchRequest: (request, options) => this.dispatchRequestWithRetry(request, options),\n getUpgradeRequest: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.getUpgradeRequest();\n },\n dispatchWebSocketOpen: async (connectionId) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketOpen(connectionId);\n },\n dispatchWebSocketMessage: async (connectionId, message) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketMessage(connectionId, message);\n },\n dispatchWebSocketClose: async (connectionId, code, reason) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketClose(connectionId, code, reason);\n },\n dispatchWebSocketError: async (connectionId, error) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketError(connectionId, error);\n },\n hasServeHandler: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.hasServeHandler();\n },\n hasActiveConnections: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.hasActiveConnections();\n },\n };\n\n constructor(options: IsolateServerOptions) {\n this.namespaceId = options.namespaceId;\n this.getConnection = options.getConnection;\n }\n\n async start(options: IsolateServerStartOptions): Promise<void> {\n this.lastStartOptions = options;\n this.closed = false;\n\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n return;\n }\n\n this.runtime = await this.createAndInitializeRuntime(options);\n });\n }\n\n async reload(): Promise<void> {\n const startOptions = this.lastStartOptions;\n if (!startOptions) {\n throw new Error(\"Server not configured. Call start() first.\");\n }\n\n this.closed = false;\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n const runtime = this.runtime;\n this.runtime = null;\n await this.disposeRuntime(runtime);\n }\n\n this.runtime = await this.createAndInitializeRuntime(startOptions);\n });\n }\n\n async close(): Promise<void> {\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n const runtime = this.runtime;\n this.runtime = null;\n await this.disposeRuntime(runtime);\n }\n\n this.closed = true;\n });\n }\n\n getRuntime(): RemoteRuntime | null {\n return this.runtime;\n }\n\n private async withLifecycleLock<T>(operation: () => Promise<T>): Promise<T> {\n const previous = this.lifecycleLock;\n let release!: () => void;\n this.lifecycleLock = new Promise<void>((resolve) => {\n release = resolve;\n });\n\n await previous;\n try {\n return await operation();\n } finally {\n release();\n }\n }\n\n private buildRuntimeOptions(options: IsolateServerStartOptions): RuntimeOptions {\n if (options.onWebSocketCommand) {\n return {\n ...options.runtimeOptions,\n onWebSocketCommand: options.onWebSocketCommand,\n };\n }\n\n return options.runtimeOptions;\n }\n\n private async createAndInitializeRuntime(\n options: IsolateServerStartOptions,\n allowRetry: boolean = true\n ): Promise<RemoteRuntime> {\n const connection = await this.getConnection();\n const namespace = connection.createNamespace(this.namespaceId);\n const runtimeOptions = this.buildRuntimeOptions(options);\n const runtime = await namespace.createRuntime(runtimeOptions);\n\n try {\n await runtime.eval(\n `import ${JSON.stringify(options.entry)};`,\n options.entryFilename ?? \"/isolate_server_entry.js\"\n );\n return runtime;\n } catch (error) {\n await this.disposeRuntime(runtime);\n if (!allowRetry || !isLinkerConflictError(error)) {\n throw error;\n }\n\n const retryRuntime = await namespace.createRuntime(runtimeOptions);\n try {\n await retryRuntime.eval(\n `import ${JSON.stringify(options.entry)};`,\n options.entryFilename ?? \"/isolate_server_entry.js\"\n );\n return retryRuntime;\n } catch (retryError) {\n await this.disposeRuntime(retryRuntime);\n throw retryError;\n }\n }\n }\n\n private async disposeRuntime(runtime: RemoteRuntime): Promise<void> {\n try {\n await runtime.dispose();\n } catch (error) {\n if (!isBenignDisposeError(error)) {\n throw error;\n }\n }\n }\n\n private async ensureStarted(): Promise<void> {\n if (this.runtime) {\n return;\n }\n\n if (!this.lastStartOptions) {\n throw new Error(\"Server not configured. Call start() first.\");\n }\n\n if (this.closed) {\n this.closed = false;\n }\n\n await this.start(this.lastStartOptions);\n }\n\n private async getActiveRuntime(): Promise<RemoteRuntime> {\n await this.ensureStarted();\n if (!this.runtime) {\n throw new Error(\"Server runtime failed to start.\");\n }\n return this.runtime;\n }\n\n private async dispatchRequestWithRetry(\n request: Request,\n options?: DispatchOptions\n ): Promise<Response> {\n const runtime = await this.getActiveRuntime();\n try {\n return await runtime.fetch.dispatchRequest(request, options);\n } catch (error) {\n if (!isLinkerConflictError(error)) {\n throw error;\n }\n\n await this.reload();\n const retryRuntime = await this.getActiveRuntime();\n return retryRuntime.fetch.dispatchRequest(request, options);\n }\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "D8CA16D612F9756664756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@ricsam/isolate-server",
3
+ "version": "0.2.1",
4
+ "type": "commonjs"
5
+ }
@@ -0,0 +1,180 @@
1
+ // packages/isolate-server/src/index.ts
2
+ import { isBenignDisposeError } from "@ricsam/isolate-client";
3
+ var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
4
+ function isLinkerConflictError(error) {
5
+ const message = error instanceof Error ? error.message : String(error ?? "");
6
+ return message.includes(LINKER_CONFLICT_ERROR);
7
+ }
8
+
9
+ class IsolateServer {
10
+ namespaceId;
11
+ getConnection;
12
+ runtime = null;
13
+ lastStartOptions = null;
14
+ lifecycleLock = Promise.resolve();
15
+ closed = true;
16
+ fetch = {
17
+ dispatchRequest: (request, options) => this.dispatchRequestWithRetry(request, options),
18
+ getUpgradeRequest: async () => {
19
+ const runtime = await this.getActiveRuntime();
20
+ return runtime.fetch.getUpgradeRequest();
21
+ },
22
+ dispatchWebSocketOpen: async (connectionId) => {
23
+ const runtime = await this.getActiveRuntime();
24
+ await runtime.fetch.dispatchWebSocketOpen(connectionId);
25
+ },
26
+ dispatchWebSocketMessage: async (connectionId, message) => {
27
+ const runtime = await this.getActiveRuntime();
28
+ await runtime.fetch.dispatchWebSocketMessage(connectionId, message);
29
+ },
30
+ dispatchWebSocketClose: async (connectionId, code, reason) => {
31
+ const runtime = await this.getActiveRuntime();
32
+ await runtime.fetch.dispatchWebSocketClose(connectionId, code, reason);
33
+ },
34
+ dispatchWebSocketError: async (connectionId, error) => {
35
+ const runtime = await this.getActiveRuntime();
36
+ await runtime.fetch.dispatchWebSocketError(connectionId, error);
37
+ },
38
+ hasServeHandler: async () => {
39
+ const runtime = await this.getActiveRuntime();
40
+ return runtime.fetch.hasServeHandler();
41
+ },
42
+ hasActiveConnections: async () => {
43
+ const runtime = await this.getActiveRuntime();
44
+ return runtime.fetch.hasActiveConnections();
45
+ }
46
+ };
47
+ constructor(options) {
48
+ this.namespaceId = options.namespaceId;
49
+ this.getConnection = options.getConnection;
50
+ }
51
+ async start(options) {
52
+ this.lastStartOptions = options;
53
+ this.closed = false;
54
+ await this.withLifecycleLock(async () => {
55
+ if (this.runtime) {
56
+ return;
57
+ }
58
+ this.runtime = await this.createAndInitializeRuntime(options);
59
+ });
60
+ }
61
+ async reload() {
62
+ const startOptions = this.lastStartOptions;
63
+ if (!startOptions) {
64
+ throw new Error("Server not configured. Call start() first.");
65
+ }
66
+ this.closed = false;
67
+ await this.withLifecycleLock(async () => {
68
+ if (this.runtime) {
69
+ const runtime = this.runtime;
70
+ this.runtime = null;
71
+ await this.disposeRuntime(runtime);
72
+ }
73
+ this.runtime = await this.createAndInitializeRuntime(startOptions);
74
+ });
75
+ }
76
+ async close() {
77
+ await this.withLifecycleLock(async () => {
78
+ if (this.runtime) {
79
+ const runtime = this.runtime;
80
+ this.runtime = null;
81
+ await this.disposeRuntime(runtime);
82
+ }
83
+ this.closed = true;
84
+ });
85
+ }
86
+ getRuntime() {
87
+ return this.runtime;
88
+ }
89
+ async withLifecycleLock(operation) {
90
+ const previous = this.lifecycleLock;
91
+ let release;
92
+ this.lifecycleLock = new Promise((resolve) => {
93
+ release = resolve;
94
+ });
95
+ await previous;
96
+ try {
97
+ return await operation();
98
+ } finally {
99
+ release();
100
+ }
101
+ }
102
+ buildRuntimeOptions(options) {
103
+ if (options.onWebSocketCommand) {
104
+ return {
105
+ ...options.runtimeOptions,
106
+ onWebSocketCommand: options.onWebSocketCommand
107
+ };
108
+ }
109
+ return options.runtimeOptions;
110
+ }
111
+ async createAndInitializeRuntime(options, allowRetry = true) {
112
+ const connection = await this.getConnection();
113
+ const namespace = connection.createNamespace(this.namespaceId);
114
+ const runtimeOptions = this.buildRuntimeOptions(options);
115
+ const runtime = await namespace.createRuntime(runtimeOptions);
116
+ try {
117
+ await runtime.eval(`import ${JSON.stringify(options.entry)};`, options.entryFilename ?? "/isolate_server_entry.js");
118
+ return runtime;
119
+ } catch (error) {
120
+ await this.disposeRuntime(runtime);
121
+ if (!allowRetry || !isLinkerConflictError(error)) {
122
+ throw error;
123
+ }
124
+ const retryRuntime = await namespace.createRuntime(runtimeOptions);
125
+ try {
126
+ await retryRuntime.eval(`import ${JSON.stringify(options.entry)};`, options.entryFilename ?? "/isolate_server_entry.js");
127
+ return retryRuntime;
128
+ } catch (retryError) {
129
+ await this.disposeRuntime(retryRuntime);
130
+ throw retryError;
131
+ }
132
+ }
133
+ }
134
+ async disposeRuntime(runtime) {
135
+ try {
136
+ await runtime.dispose();
137
+ } catch (error) {
138
+ if (!isBenignDisposeError(error)) {
139
+ throw error;
140
+ }
141
+ }
142
+ }
143
+ async ensureStarted() {
144
+ if (this.runtime) {
145
+ return;
146
+ }
147
+ if (!this.lastStartOptions) {
148
+ throw new Error("Server not configured. Call start() first.");
149
+ }
150
+ if (this.closed) {
151
+ this.closed = false;
152
+ }
153
+ await this.start(this.lastStartOptions);
154
+ }
155
+ async getActiveRuntime() {
156
+ await this.ensureStarted();
157
+ if (!this.runtime) {
158
+ throw new Error("Server runtime failed to start.");
159
+ }
160
+ return this.runtime;
161
+ }
162
+ async dispatchRequestWithRetry(request, options) {
163
+ const runtime = await this.getActiveRuntime();
164
+ try {
165
+ return await runtime.fetch.dispatchRequest(request, options);
166
+ } catch (error) {
167
+ if (!isLinkerConflictError(error)) {
168
+ throw error;
169
+ }
170
+ await this.reload();
171
+ const retryRuntime = await this.getActiveRuntime();
172
+ return retryRuntime.fetch.dispatchRequest(request, options);
173
+ }
174
+ }
175
+ }
176
+ export {
177
+ IsolateServer
178
+ };
179
+
180
+ //# debugId=25E2FF8F088B596A64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n DaemonConnection,\n DispatchOptions,\n RemoteRuntime,\n RuntimeOptions,\n UpgradeRequest,\n WebSocketCommand,\n} from \"@ricsam/isolate-client\";\nimport { isBenignDisposeError } from \"@ricsam/isolate-client\";\n\nconst LINKER_CONFLICT_ERROR = \"Module is currently being linked by another linker\";\n\nfunction isLinkerConflictError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n return message.includes(LINKER_CONFLICT_ERROR);\n}\n\nexport interface IsolateServerOptions {\n namespaceId: string;\n getConnection: () => Promise<DaemonConnection>;\n}\n\nexport interface IsolateServerStartOptions {\n runtimeOptions: RuntimeOptions;\n entry: string;\n entryFilename?: string;\n onWebSocketCommand?: (cmd: WebSocketCommand) => void;\n}\n\nexport interface IsolateServerFetch {\n dispatchRequest(request: Request, options?: DispatchOptions): Promise<Response>;\n getUpgradeRequest(): Promise<UpgradeRequest | null>;\n dispatchWebSocketOpen(connectionId: string): Promise<void>;\n dispatchWebSocketMessage(connectionId: string, message: string | ArrayBuffer): Promise<void>;\n dispatchWebSocketClose(connectionId: string, code: number, reason: string): Promise<void>;\n dispatchWebSocketError(connectionId: string, error: Error): Promise<void>;\n hasServeHandler(): Promise<boolean>;\n hasActiveConnections(): Promise<boolean>;\n}\n\nexport class IsolateServer {\n private readonly namespaceId: string;\n private readonly getConnection: () => Promise<DaemonConnection>;\n private runtime: RemoteRuntime | null = null;\n private lastStartOptions: IsolateServerStartOptions | null = null;\n private lifecycleLock: Promise<void> = Promise.resolve();\n private closed = true;\n\n readonly fetch: IsolateServerFetch = {\n dispatchRequest: (request, options) => this.dispatchRequestWithRetry(request, options),\n getUpgradeRequest: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.getUpgradeRequest();\n },\n dispatchWebSocketOpen: async (connectionId) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketOpen(connectionId);\n },\n dispatchWebSocketMessage: async (connectionId, message) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketMessage(connectionId, message);\n },\n dispatchWebSocketClose: async (connectionId, code, reason) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketClose(connectionId, code, reason);\n },\n dispatchWebSocketError: async (connectionId, error) => {\n const runtime = await this.getActiveRuntime();\n await runtime.fetch.dispatchWebSocketError(connectionId, error);\n },\n hasServeHandler: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.hasServeHandler();\n },\n hasActiveConnections: async () => {\n const runtime = await this.getActiveRuntime();\n return runtime.fetch.hasActiveConnections();\n },\n };\n\n constructor(options: IsolateServerOptions) {\n this.namespaceId = options.namespaceId;\n this.getConnection = options.getConnection;\n }\n\n async start(options: IsolateServerStartOptions): Promise<void> {\n this.lastStartOptions = options;\n this.closed = false;\n\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n return;\n }\n\n this.runtime = await this.createAndInitializeRuntime(options);\n });\n }\n\n async reload(): Promise<void> {\n const startOptions = this.lastStartOptions;\n if (!startOptions) {\n throw new Error(\"Server not configured. Call start() first.\");\n }\n\n this.closed = false;\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n const runtime = this.runtime;\n this.runtime = null;\n await this.disposeRuntime(runtime);\n }\n\n this.runtime = await this.createAndInitializeRuntime(startOptions);\n });\n }\n\n async close(): Promise<void> {\n await this.withLifecycleLock(async () => {\n if (this.runtime) {\n const runtime = this.runtime;\n this.runtime = null;\n await this.disposeRuntime(runtime);\n }\n\n this.closed = true;\n });\n }\n\n getRuntime(): RemoteRuntime | null {\n return this.runtime;\n }\n\n private async withLifecycleLock<T>(operation: () => Promise<T>): Promise<T> {\n const previous = this.lifecycleLock;\n let release!: () => void;\n this.lifecycleLock = new Promise<void>((resolve) => {\n release = resolve;\n });\n\n await previous;\n try {\n return await operation();\n } finally {\n release();\n }\n }\n\n private buildRuntimeOptions(options: IsolateServerStartOptions): RuntimeOptions {\n if (options.onWebSocketCommand) {\n return {\n ...options.runtimeOptions,\n onWebSocketCommand: options.onWebSocketCommand,\n };\n }\n\n return options.runtimeOptions;\n }\n\n private async createAndInitializeRuntime(\n options: IsolateServerStartOptions,\n allowRetry: boolean = true\n ): Promise<RemoteRuntime> {\n const connection = await this.getConnection();\n const namespace = connection.createNamespace(this.namespaceId);\n const runtimeOptions = this.buildRuntimeOptions(options);\n const runtime = await namespace.createRuntime(runtimeOptions);\n\n try {\n await runtime.eval(\n `import ${JSON.stringify(options.entry)};`,\n options.entryFilename ?? \"/isolate_server_entry.js\"\n );\n return runtime;\n } catch (error) {\n await this.disposeRuntime(runtime);\n if (!allowRetry || !isLinkerConflictError(error)) {\n throw error;\n }\n\n const retryRuntime = await namespace.createRuntime(runtimeOptions);\n try {\n await retryRuntime.eval(\n `import ${JSON.stringify(options.entry)};`,\n options.entryFilename ?? \"/isolate_server_entry.js\"\n );\n return retryRuntime;\n } catch (retryError) {\n await this.disposeRuntime(retryRuntime);\n throw retryError;\n }\n }\n }\n\n private async disposeRuntime(runtime: RemoteRuntime): Promise<void> {\n try {\n await runtime.dispose();\n } catch (error) {\n if (!isBenignDisposeError(error)) {\n throw error;\n }\n }\n }\n\n private async ensureStarted(): Promise<void> {\n if (this.runtime) {\n return;\n }\n\n if (!this.lastStartOptions) {\n throw new Error(\"Server not configured. Call start() first.\");\n }\n\n if (this.closed) {\n this.closed = false;\n }\n\n await this.start(this.lastStartOptions);\n }\n\n private async getActiveRuntime(): Promise<RemoteRuntime> {\n await this.ensureStarted();\n if (!this.runtime) {\n throw new Error(\"Server runtime failed to start.\");\n }\n return this.runtime;\n }\n\n private async dispatchRequestWithRetry(\n request: Request,\n options?: DispatchOptions\n ): Promise<Response> {\n const runtime = await this.getActiveRuntime();\n try {\n return await runtime.fetch.dispatchRequest(request, options);\n } catch (error) {\n if (!isLinkerConflictError(error)) {\n throw error;\n }\n\n await this.reload();\n const retryRuntime = await this.getActiveRuntime();\n return retryRuntime.fetch.dispatchRequest(request, options);\n }\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "25E2FF8F088B596A64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@ricsam/isolate-server",
3
+ "version": "0.2.1",
4
+ "type": "module"
5
+ }
@@ -0,0 +1,42 @@
1
+ import type { DaemonConnection, DispatchOptions, RemoteRuntime, RuntimeOptions, UpgradeRequest, WebSocketCommand } from "@ricsam/isolate-client";
2
+ export interface IsolateServerOptions {
3
+ namespaceId: string;
4
+ getConnection: () => Promise<DaemonConnection>;
5
+ }
6
+ export interface IsolateServerStartOptions {
7
+ runtimeOptions: RuntimeOptions;
8
+ entry: string;
9
+ entryFilename?: string;
10
+ onWebSocketCommand?: (cmd: WebSocketCommand) => void;
11
+ }
12
+ export interface IsolateServerFetch {
13
+ dispatchRequest(request: Request, options?: DispatchOptions): Promise<Response>;
14
+ getUpgradeRequest(): Promise<UpgradeRequest | null>;
15
+ dispatchWebSocketOpen(connectionId: string): Promise<void>;
16
+ dispatchWebSocketMessage(connectionId: string, message: string | ArrayBuffer): Promise<void>;
17
+ dispatchWebSocketClose(connectionId: string, code: number, reason: string): Promise<void>;
18
+ dispatchWebSocketError(connectionId: string, error: Error): Promise<void>;
19
+ hasServeHandler(): Promise<boolean>;
20
+ hasActiveConnections(): Promise<boolean>;
21
+ }
22
+ export declare class IsolateServer {
23
+ private readonly namespaceId;
24
+ private readonly getConnection;
25
+ private runtime;
26
+ private lastStartOptions;
27
+ private lifecycleLock;
28
+ private closed;
29
+ readonly fetch: IsolateServerFetch;
30
+ constructor(options: IsolateServerOptions);
31
+ start(options: IsolateServerStartOptions): Promise<void>;
32
+ reload(): Promise<void>;
33
+ close(): Promise<void>;
34
+ getRuntime(): RemoteRuntime | null;
35
+ private withLifecycleLock;
36
+ private buildRuntimeOptions;
37
+ private createAndInitializeRuntime;
38
+ private disposeRuntime;
39
+ private ensureStarted;
40
+ private getActiveRuntime;
41
+ private dispatchRequestWithRetry;
42
+ }
package/package.json CHANGED
@@ -1,10 +1,52 @@
1
1
  {
2
2
  "name": "@ricsam/isolate-server",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @ricsam/isolate-server",
3
+ "version": "0.2.1",
4
+ "main": "./dist/cjs/index.cjs",
5
+ "types": "./dist/types/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/types/index.d.ts",
9
+ "require": "./dist/cjs/index.cjs",
10
+ "import": "./dist/mjs/index.mjs"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "test": "node --test --experimental-strip-types 'src/**/*.test.ts'",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "@ricsam/isolate-client": "*"
20
+ },
21
+ "author": "ricsam <oss@ricsam.dev>",
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/ricsam/isolate.git",
26
+ "directory": "packages/isolate-server"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/ricsam/isolate/issues"
30
+ },
31
+ "homepage": "https://github.com/ricsam/isolate#readme",
5
32
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
33
+ "isolated-vm",
34
+ "sandbox",
35
+ "javascript",
36
+ "runtime",
37
+ "fetch",
38
+ "filesystem",
39
+ "streams",
40
+ "v8",
41
+ "isolate"
42
+ ],
43
+ "description": "Reusable lifecycle manager for namespaced isolate runtimes and entry-module startup",
44
+ "module": "./dist/mjs/index.mjs",
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "README.md"
9
51
  ]
10
- }
52
+ }