@xgsd/workers 0.1.0-beta.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Palmer
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,57 @@
1
+ # @xgsd/workers
2
+
3
+ [![Version](https://img.shields.io/npm/v/@xgsd/workers.svg)](https://npmjs.org/package/@xgsd/workers)
4
+ [![CI & Release](https://github.com/Isolated-/xgsd-workers/actions/workflows/release.yml/badge.svg)](https://github.com/Isolated-/xgsd-workers/actions/workflows/release.yml)
5
+
6
+ This runtime is designed as a simplified alternative to the full xGSD engine — focusing on fast execution, low memory usage, and deterministic behaviour.
7
+
8
+ ## Documentation
9
+
10
+ Read the [**Documentation**](https://isolated-.github.io/xgsd-userdocs/labs/workers).
11
+
12
+ ## Install
13
+
14
+ Install this package with:
15
+
16
+ ```bash
17
+ yarn add @xgsd/workers
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```javascript
23
+ export default async function (data) {
24
+ const url = data.url ?? 'https://timeapi.io/api/Time/current/zone?timeZone=Europe/London'
25
+
26
+ const res = await fetch(url)
27
+ const json = await res.json()
28
+
29
+ return json
30
+ }
31
+ ```
32
+
33
+ Run a worker:
34
+
35
+ ```javascript
36
+ import {createHandler} from '@xgsd/workers'
37
+
38
+ const config = getWorkerConfig()
39
+ const handler = createHandler(config)
40
+
41
+ // inside your transport (e.g. Express route):
42
+ async function callback(req, res) {
43
+ const data = req.body
44
+
45
+ const result = await handler({
46
+ data,
47
+ env: {
48
+ // env vars
49
+ },
50
+ cwd: 'path/to/worker',
51
+ })
52
+ }
53
+ ```
54
+
55
+ ## Testing
56
+
57
+ TBD
@@ -0,0 +1,45 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/util/fs.ts
9
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
10
+ import { writeFile, readFile, constants, access, mkdir } from "fs/promises";
11
+ async function pathExists(path) {
12
+ try {
13
+ await access(path, constants.F_OK);
14
+ return true;
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+ async function ensureDir(path) {
20
+ await mkdir(path, { recursive: true });
21
+ }
22
+ function readJsonSync(path) {
23
+ return JSON.parse(readFileSync(path, "utf8"));
24
+ }
25
+ function writeJsonSync(path, data, pretty = true) {
26
+ const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
27
+ writeFileSync(path, json, "utf8");
28
+ }
29
+ function pathExistsSync(path) {
30
+ try {
31
+ __require("fs").accessSync(path, constants.F_OK);
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ export {
39
+ pathExists,
40
+ ensureDir,
41
+ readJsonSync,
42
+ writeJsonSync,
43
+ pathExistsSync
44
+ };
45
+ //# sourceMappingURL=chunk-QLD3WJX5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/fs.ts"],"sourcesContent":["import {readFileSync, writeFileSync, mkdirSync} from 'fs'\nimport {writeFile, readFile, constants, access, mkdir} from 'fs/promises'\nimport {dirname} from 'path'\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await access(path, constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\n// ensureDir\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, {recursive: true})\n}\n\n// ensureDirSync\nexport function ensureDirSync(path: string): void {\n mkdirSync(path, {recursive: true})\n}\n\n// ensurePath\n// Ensures parent directory exists for a file path\nexport async function ensurePath(path: string): Promise<void> {\n await mkdir(dirname(path), {recursive: true})\n}\n\n// ensurePathSync\nexport function ensurePathSync(path: string): void {\n mkdirSync(dirname(path), {recursive: true})\n}\n\nexport async function readJson<T = any>(path: string): Promise<T> {\n const content = await readFile(path, 'utf8')\n return JSON.parse(content)\n}\n\nexport function readJsonSync<T = any>(path: string): T {\n return JSON.parse(readFileSync(path, 'utf8'))\n}\n\nexport async function writeJson(path: string, data: unknown, pretty = true): Promise<void> {\n const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n\n await writeFile(path, json, 'utf8')\n}\n\nexport function writeJsonSync(path: string, data: unknown, pretty = true): void {\n const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n\n writeFileSync(path, json, 'utf8')\n}\n\nexport function pathExistsSync(path: string): boolean {\n try {\n require('fs').accessSync(path, constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n"],"mappings":";;;;;;;;AAAA,SAAQ,cAAc,eAAe,iBAAgB;AACrD,SAAQ,WAAW,UAAU,WAAW,QAAQ,aAAY;AAG5D,eAAsB,WAAW,MAAgC;AAC/D,MAAI;AACF,UAAM,OAAO,MAAM,UAAU,IAAI;AACjC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,UAAU,MAA6B;AAC3D,QAAM,MAAM,MAAM,EAAC,WAAW,KAAI,CAAC;AACrC;AAuBO,SAAS,aAAsB,MAAiB;AACrD,SAAO,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAC9C;AAQO,SAAS,cAAc,MAAc,MAAe,SAAS,MAAY;AAC9E,QAAM,OAAO,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI;AAEzE,gBAAc,MAAM,MAAM,MAAM;AAClC;AAEO,SAAS,eAAe,MAAuB;AACpD,MAAI;AACF,cAAQ,IAAI,EAAE,WAAW,MAAM,UAAU,IAAI;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createHandler: () => createHandler
24
+ });
25
+ module.exports = __toCommonJS(src_exports);
26
+
27
+ // src/worker.ts
28
+ var import_child_process = require("child_process");
29
+ var import_path = require("path");
30
+ var import_fs = require("fs");
31
+
32
+ // src/util/fs.ts
33
+ var import_promises = require("fs/promises");
34
+ async function ensureDir(path) {
35
+ await (0, import_promises.mkdir)(path, { recursive: true });
36
+ }
37
+
38
+ // src/worker.ts
39
+ var import_crypto = require("crypto");
40
+ function startWorkerGuard(child, opts, suspended) {
41
+ const { ttl = 5e3, memory = 128 } = opts;
42
+ let ttlTimer = null;
43
+ let killed = false;
44
+ const kill = (reason) => {
45
+ if (killed) return;
46
+ killed = true;
47
+ if (ttlTimer) clearTimeout(ttlTimer);
48
+ child.kill("SIGKILL");
49
+ suspended?.(reason);
50
+ };
51
+ ttlTimer = setTimeout(() => {
52
+ kill(`ttl exceeded limit (limit: ${ttl.toFixed(2)}ms)`);
53
+ }, ttl);
54
+ child.on("message", (msg) => {
55
+ if (msg.type !== "ALIVE") {
56
+ return;
57
+ }
58
+ const heapUsed = msg.memory?.heapUsed ?? 0;
59
+ const memMB = heapUsed / 1024 / 1024;
60
+ if (memMB > memory) {
61
+ kill(`memory limit exceeded: ${memMB.toFixed(2)}MB/${memory.toFixed(2)}MB`);
62
+ }
63
+ });
64
+ child.on("exit", () => {
65
+ if (ttlTimer) clearTimeout(ttlTimer);
66
+ });
67
+ }
68
+ function normaliseKeys(value) {
69
+ if (Array.isArray(value)) {
70
+ return value.map(normaliseKeys);
71
+ }
72
+ if (value && typeof value === "object" && value.constructor === Object) {
73
+ const sorted = {};
74
+ for (const key of Object.keys(value).sort()) {
75
+ sorted[key] = normaliseKeys(value[key]);
76
+ }
77
+ return sorted;
78
+ }
79
+ return value;
80
+ }
81
+ function formatWorkerResult(opts) {
82
+ return {
83
+ version: "v1",
84
+ ok: !opts.error,
85
+ result: opts.result ?? null,
86
+ error: opts.error ?? null,
87
+ duration: opts.duration
88
+ };
89
+ }
90
+ async function runWorker(context) {
91
+ return new Promise(async (resolve, reject) => {
92
+ const id = (0, import_crypto.randomUUID)();
93
+ const ctx = { ...context, id };
94
+ const start = performance.now();
95
+ const path = (0, import_path.join)(ctx.cwd, ctx.dist ?? ".xgsd");
96
+ await ensureDir(path);
97
+ let started = false;
98
+ let completed = false;
99
+ let res;
100
+ const contextStr = JSON.stringify(ctx);
101
+ const child = (0, import_child_process.fork)((0, import_path.join)(__dirname, "process", "workers.process.js"), {
102
+ stdio: ["inherit", "pipe", "pipe", "ipc"],
103
+ //execArgv: [`--max-old-space-size=${ctx.limits?.memory ?? 128}`],
104
+ env: {
105
+ ...ctx.env,
106
+ XGSD_CTX: contextStr
107
+ }
108
+ });
109
+ const events = (0, import_fs.createWriteStream)((0, import_path.join)(path, "events.jsonl"), { flags: "a" });
110
+ const startGuard = () => {
111
+ startWorkerGuard(child, ctx.limits ?? {}, (reason) => {
112
+ if (completed) return;
113
+ const err = {
114
+ code: "CODE_WORKER_GUARD" /* CODE_WORKER_GUARD */,
115
+ message: `${reason}`,
116
+ type: "system"
117
+ };
118
+ console.warn(`[guard] worker suspended (reason: ${reason})`);
119
+ writeEvent({
120
+ type: "error",
121
+ message: err.message,
122
+ guard: true,
123
+ timestamp: Date.now()
124
+ });
125
+ cleanup();
126
+ resolve(formatWorkerResult({ error: err, duration: performance.now() - start }));
127
+ });
128
+ };
129
+ const cleanup = () => {
130
+ if (child.connected) {
131
+ child.removeAllListeners("message");
132
+ child.disconnect();
133
+ }
134
+ };
135
+ const writeEvent = (data) => {
136
+ const normalised = normaliseKeys(data);
137
+ events.write(JSON.stringify({ ...normalised, id }) + "\n");
138
+ };
139
+ child.stdout?.on("data", (chunk) => {
140
+ const lines = chunk.toString().split("\n").filter(Boolean);
141
+ for (const line of lines) {
142
+ console.log(`${line}`);
143
+ try {
144
+ writeEvent(JSON.parse(line));
145
+ } catch {
146
+ writeEvent({
147
+ type: "log",
148
+ message: line,
149
+ timestamp: Date.now()
150
+ });
151
+ }
152
+ }
153
+ });
154
+ child.stderr?.on("data", (chunk) => {
155
+ const e = { type: "error", message: chunk.toString(), timestamp: Date.now() };
156
+ console.error(e.message);
157
+ writeEvent(e);
158
+ });
159
+ child.on("message", (msg) => {
160
+ if (msg.type !== "ALIVE" && msg.type !== "DONE" && msg.type !== "ERROR") return;
161
+ if (msg.type === "ALIVE") {
162
+ if (!started) {
163
+ started = true;
164
+ startGuard();
165
+ }
166
+ return;
167
+ }
168
+ if (msg.type === "ERROR") {
169
+ const { error } = msg;
170
+ res = formatWorkerResult({ error, duration: performance.now() - start });
171
+ }
172
+ if (msg.type === "DONE") {
173
+ res = msg.result;
174
+ }
175
+ res.duration = performance.now() - start;
176
+ (0, import_fs.appendFileSync)(
177
+ (0, import_path.join)(path, "activations.jsonl"),
178
+ JSON.stringify({
179
+ id,
180
+ ok: res.ok,
181
+ code: res.code,
182
+ duration: res.duration,
183
+ error: res.error?.code ?? res.error?.message,
184
+ result: res.result !== null,
185
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
186
+ }) + "\n"
187
+ );
188
+ completed = true;
189
+ resolve(res);
190
+ cleanup();
191
+ });
192
+ });
193
+ }
194
+
195
+ // src/index.ts
196
+ function createHandler(config) {
197
+ return async function handler(activation) {
198
+ return runWorker({
199
+ ...config,
200
+ id: activation.id,
201
+ cwd: activation.cwd,
202
+ data: activation.data,
203
+ env: activation.env
204
+ });
205
+ };
206
+ }
207
+ // Annotate the CommonJS export names for ESM import in node:
208
+ 0 && (module.exports = {
209
+ createHandler
210
+ });
211
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/worker.ts","../src/util/fs.ts"],"sourcesContent":["import {WorkerResult, WorkerConfig} from './types'\nimport {runWorker} from './worker'\n\nexport type Activation<T = unknown> = {\n id?: string\n data?: T\n env?: Record<string, unknown>\n cwd: string\n}\n\nexport type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>\n\nexport function createHandler(config: WorkerConfig): ActivationHandler {\n return async function handler(activation) {\n return runWorker({\n ...config,\n id: activation.id,\n cwd: activation.cwd,\n data: activation.data,\n env: activation.env,\n })\n }\n}\n","import {fork} from 'child_process'\nimport {join} from 'path'\nimport {WorkerContext, WorkerError, WorkerErrorCode, WorkerResult} from './types.js'\nimport {createWriteStream, appendFileSync} from 'fs'\nimport {ensureDir} from './util/fs.js'\nimport {randomUUID} from 'crypto'\n\nexport function startWorkerGuard(\n child: any,\n opts: {\n ttl?: number\n memory?: number\n },\n suspended?: (reason: string) => void,\n) {\n const {ttl = 5000, memory = 128} = opts\n\n let ttlTimer: NodeJS.Timeout | null = null\n let killed = false\n\n const kill = (reason: string) => {\n if (killed) return\n killed = true\n\n if (ttlTimer) clearTimeout(ttlTimer)\n\n child.kill('SIGKILL')\n suspended?.(reason)\n }\n\n // TTL watchdog\n ttlTimer = setTimeout(() => {\n kill(`ttl exceeded limit (limit: ${ttl.toFixed(2)}ms)`)\n }, ttl)\n\n child.on('message', (msg: any) => {\n if (msg.type !== 'ALIVE') {\n return\n }\n\n // (v0.1.0) this isn't set in stone\n // may be worth using RSS\n const heapUsed = msg.memory?.heapUsed ?? 0\n const memMB = heapUsed / 1024 / 1024\n\n if (memMB > memory) {\n kill(`memory limit exceeded: ${memMB.toFixed(2)}MB/${memory.toFixed(2)}MB`)\n }\n })\n\n child.on('exit', () => {\n if (ttlTimer) clearTimeout(ttlTimer)\n })\n}\n\ntype ChildMessage<T> =\n | {type: 'ALIVE'; error: undefined; result: undefined}\n | {type: 'DONE'; result: WorkerResult<T>; error: undefined | null}\n | {type: 'ERROR'; result: undefined | null; error: WorkerError}\n\nexport function normaliseKeys(value: any): any {\n if (Array.isArray(value)) {\n return value.map(normaliseKeys)\n }\n\n if (value && typeof value === 'object' && value.constructor === Object) {\n const sorted: Record<string, any> = {}\n\n for (const key of Object.keys(value).sort()) {\n sorted[key] = normaliseKeys(value[key])\n }\n\n return sorted\n }\n\n return value\n}\n\nexport function formatWorkerResult(opts: {result?: any; error?: any; duration: number}): WorkerResult<any> {\n return {\n version: 'v1',\n ok: !opts.error,\n result: opts.result ?? null,\n error: opts.error ?? null,\n duration: opts.duration,\n }\n}\n\nexport async function runWorker<T>(context: WorkerContext): Promise<WorkerResult<T>> {\n return new Promise(async (resolve, reject) => {\n const id = randomUUID()\n\n const ctx = {...context, id}\n const start = performance.now()\n\n const path = join(ctx.cwd!, ctx.dist ?? '.xgsd')\n await ensureDir(path)\n\n let started = false\n let completed = false\n let res: WorkerResult<unknown>\n\n const contextStr = JSON.stringify(ctx)\n\n // TODO: remove hardcoded worker path\n const child = fork(join(__dirname, 'process', 'workers.process.js'), {\n stdio: ['inherit', 'pipe', 'pipe', 'ipc'],\n //execArgv: [`--max-old-space-size=${ctx.limits?.memory ?? 128}`],\n env: {\n ...ctx.env,\n XGSD_CTX: contextStr,\n },\n })\n\n const events = createWriteStream(join(path, 'events.jsonl'), {flags: 'a'})\n\n const startGuard = () => {\n startWorkerGuard(child, ctx.limits ?? {}, (reason: string) => {\n if (completed) return\n\n // normalise system/watch dog error\n // then *reject*\n const err: WorkerError = {\n code: WorkerErrorCode.CODE_WORKER_GUARD,\n message: `${reason}`,\n type: 'system',\n }\n\n console.warn(`[guard] worker suspended (reason: ${reason})`)\n\n writeEvent({\n type: 'error',\n message: err.message,\n guard: true,\n timestamp: Date.now(),\n })\n\n cleanup()\n\n resolve(formatWorkerResult({error: err, duration: performance.now() - start}))\n })\n }\n\n const cleanup = () => {\n if (child.connected) {\n child.removeAllListeners('message')\n\n child.disconnect()\n }\n }\n\n const writeEvent = (data: any) => {\n const normalised = normaliseKeys(data)\n events.write(JSON.stringify({...normalised, id}) + '\\n')\n }\n\n child.stdout?.on('data', (chunk) => {\n const lines = chunk.toString().split('\\n').filter(Boolean)\n\n for (const line of lines) {\n // log child process messages (typically from usercode)\n console.log(`${line}`)\n\n try {\n writeEvent(JSON.parse(line))\n } catch {\n // optionally fallback for non-json logs\n writeEvent({\n type: 'log',\n message: line,\n timestamp: Date.now(),\n })\n }\n }\n })\n\n child.stderr?.on('data', (chunk) => {\n const e = {type: 'error', message: chunk.toString(), timestamp: Date.now()}\n console.error(e.message)\n writeEvent(e)\n })\n\n child.on('message', (msg: ChildMessage<unknown>) => {\n if (msg.type !== 'ALIVE' && msg.type !== 'DONE' && msg.type !== 'ERROR') return\n\n if (msg.type === 'ALIVE') {\n if (!started) {\n started = true\n startGuard()\n }\n return\n }\n\n if (msg.type === 'ERROR') {\n const {error} = msg\n\n res = formatWorkerResult({error, duration: performance.now() - start})\n }\n\n if (msg.type === 'DONE') {\n // do something with result\n res = msg.result\n }\n\n res.duration = performance.now() - start\n\n // log activation\n appendFileSync(\n join(path, 'activations.jsonl'),\n JSON.stringify({\n id,\n ok: res.ok,\n code: res.code,\n duration: res.duration,\n error: res.error?.code ?? res.error?.message,\n result: res.result !== null,\n timestamp: new Date().toISOString(),\n }) + '\\n',\n )\n\n completed = true\n\n resolve(res as any)\n cleanup()\n })\n })\n}\n","import {readFileSync, writeFileSync, mkdirSync} from 'fs'\nimport {writeFile, readFile, constants, access, mkdir} from 'fs/promises'\nimport {dirname} from 'path'\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await access(path, constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\n// ensureDir\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, {recursive: true})\n}\n\n// ensureDirSync\nexport function ensureDirSync(path: string): void {\n mkdirSync(path, {recursive: true})\n}\n\n// ensurePath\n// Ensures parent directory exists for a file path\nexport async function ensurePath(path: string): Promise<void> {\n await mkdir(dirname(path), {recursive: true})\n}\n\n// ensurePathSync\nexport function ensurePathSync(path: string): void {\n mkdirSync(dirname(path), {recursive: true})\n}\n\nexport async function readJson<T = any>(path: string): Promise<T> {\n const content = await readFile(path, 'utf8')\n return JSON.parse(content)\n}\n\nexport function readJsonSync<T = any>(path: string): T {\n return JSON.parse(readFileSync(path, 'utf8'))\n}\n\nexport async function writeJson(path: string, data: unknown, pretty = true): Promise<void> {\n const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n\n await writeFile(path, json, 'utf8')\n}\n\nexport function writeJsonSync(path: string, data: unknown, pretty = true): void {\n const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n\n writeFileSync(path, json, 'utf8')\n}\n\nexport function pathExistsSync(path: string): boolean {\n try {\n require('fs').accessSync(path, constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,12 @@
1
+ import { W as WorkerResult, a as WorkerConfig } from './types-Buhg0r3s.cjs';
2
+
3
+ type Activation<T = unknown> = {
4
+ id?: string;
5
+ data?: T;
6
+ env?: Record<string, unknown>;
7
+ cwd: string;
8
+ };
9
+ type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>;
10
+ declare function createHandler(config: WorkerConfig): ActivationHandler;
11
+
12
+ export { type Activation, type ActivationHandler, createHandler };
@@ -0,0 +1,12 @@
1
+ import { W as WorkerResult, a as WorkerConfig } from './types-Buhg0r3s.js';
2
+
3
+ type Activation<T = unknown> = {
4
+ id?: string;
5
+ data?: T;
6
+ env?: Record<string, unknown>;
7
+ cwd: string;
8
+ };
9
+ type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>;
10
+ declare function createHandler(config: WorkerConfig): ActivationHandler;
11
+
12
+ export { type Activation, type ActivationHandler, createHandler };
package/dist/index.js ADDED
@@ -0,0 +1,180 @@
1
+ import {
2
+ ensureDir
3
+ } from "./chunk-QLD3WJX5.js";
4
+
5
+ // src/worker.ts
6
+ import { fork } from "child_process";
7
+ import { join } from "path";
8
+ import { createWriteStream, appendFileSync } from "fs";
9
+ import { randomUUID } from "crypto";
10
+ function startWorkerGuard(child, opts, suspended) {
11
+ const { ttl = 5e3, memory = 128 } = opts;
12
+ let ttlTimer = null;
13
+ let killed = false;
14
+ const kill = (reason) => {
15
+ if (killed) return;
16
+ killed = true;
17
+ if (ttlTimer) clearTimeout(ttlTimer);
18
+ child.kill("SIGKILL");
19
+ suspended?.(reason);
20
+ };
21
+ ttlTimer = setTimeout(() => {
22
+ kill(`ttl exceeded limit (limit: ${ttl.toFixed(2)}ms)`);
23
+ }, ttl);
24
+ child.on("message", (msg) => {
25
+ if (msg.type !== "ALIVE") {
26
+ return;
27
+ }
28
+ const heapUsed = msg.memory?.heapUsed ?? 0;
29
+ const memMB = heapUsed / 1024 / 1024;
30
+ if (memMB > memory) {
31
+ kill(`memory limit exceeded: ${memMB.toFixed(2)}MB/${memory.toFixed(2)}MB`);
32
+ }
33
+ });
34
+ child.on("exit", () => {
35
+ if (ttlTimer) clearTimeout(ttlTimer);
36
+ });
37
+ }
38
+ function normaliseKeys(value) {
39
+ if (Array.isArray(value)) {
40
+ return value.map(normaliseKeys);
41
+ }
42
+ if (value && typeof value === "object" && value.constructor === Object) {
43
+ const sorted = {};
44
+ for (const key of Object.keys(value).sort()) {
45
+ sorted[key] = normaliseKeys(value[key]);
46
+ }
47
+ return sorted;
48
+ }
49
+ return value;
50
+ }
51
+ function formatWorkerResult(opts) {
52
+ return {
53
+ version: "v1",
54
+ ok: !opts.error,
55
+ result: opts.result ?? null,
56
+ error: opts.error ?? null,
57
+ duration: opts.duration
58
+ };
59
+ }
60
+ async function runWorker(context) {
61
+ return new Promise(async (resolve, reject) => {
62
+ const id = randomUUID();
63
+ const ctx = { ...context, id };
64
+ const start = performance.now();
65
+ const path = join(ctx.cwd, ctx.dist ?? ".xgsd");
66
+ await ensureDir(path);
67
+ let started = false;
68
+ let completed = false;
69
+ let res;
70
+ const contextStr = JSON.stringify(ctx);
71
+ const child = fork(join(__dirname, "process", "workers.process.js"), {
72
+ stdio: ["inherit", "pipe", "pipe", "ipc"],
73
+ //execArgv: [`--max-old-space-size=${ctx.limits?.memory ?? 128}`],
74
+ env: {
75
+ ...ctx.env,
76
+ XGSD_CTX: contextStr
77
+ }
78
+ });
79
+ const events = createWriteStream(join(path, "events.jsonl"), { flags: "a" });
80
+ const startGuard = () => {
81
+ startWorkerGuard(child, ctx.limits ?? {}, (reason) => {
82
+ if (completed) return;
83
+ const err = {
84
+ code: "CODE_WORKER_GUARD" /* CODE_WORKER_GUARD */,
85
+ message: `${reason}`,
86
+ type: "system"
87
+ };
88
+ console.warn(`[guard] worker suspended (reason: ${reason})`);
89
+ writeEvent({
90
+ type: "error",
91
+ message: err.message,
92
+ guard: true,
93
+ timestamp: Date.now()
94
+ });
95
+ cleanup();
96
+ resolve(formatWorkerResult({ error: err, duration: performance.now() - start }));
97
+ });
98
+ };
99
+ const cleanup = () => {
100
+ if (child.connected) {
101
+ child.removeAllListeners("message");
102
+ child.disconnect();
103
+ }
104
+ };
105
+ const writeEvent = (data) => {
106
+ const normalised = normaliseKeys(data);
107
+ events.write(JSON.stringify({ ...normalised, id }) + "\n");
108
+ };
109
+ child.stdout?.on("data", (chunk) => {
110
+ const lines = chunk.toString().split("\n").filter(Boolean);
111
+ for (const line of lines) {
112
+ console.log(`${line}`);
113
+ try {
114
+ writeEvent(JSON.parse(line));
115
+ } catch {
116
+ writeEvent({
117
+ type: "log",
118
+ message: line,
119
+ timestamp: Date.now()
120
+ });
121
+ }
122
+ }
123
+ });
124
+ child.stderr?.on("data", (chunk) => {
125
+ const e = { type: "error", message: chunk.toString(), timestamp: Date.now() };
126
+ console.error(e.message);
127
+ writeEvent(e);
128
+ });
129
+ child.on("message", (msg) => {
130
+ if (msg.type !== "ALIVE" && msg.type !== "DONE" && msg.type !== "ERROR") return;
131
+ if (msg.type === "ALIVE") {
132
+ if (!started) {
133
+ started = true;
134
+ startGuard();
135
+ }
136
+ return;
137
+ }
138
+ if (msg.type === "ERROR") {
139
+ const { error } = msg;
140
+ res = formatWorkerResult({ error, duration: performance.now() - start });
141
+ }
142
+ if (msg.type === "DONE") {
143
+ res = msg.result;
144
+ }
145
+ res.duration = performance.now() - start;
146
+ appendFileSync(
147
+ join(path, "activations.jsonl"),
148
+ JSON.stringify({
149
+ id,
150
+ ok: res.ok,
151
+ code: res.code,
152
+ duration: res.duration,
153
+ error: res.error?.code ?? res.error?.message,
154
+ result: res.result !== null,
155
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
156
+ }) + "\n"
157
+ );
158
+ completed = true;
159
+ resolve(res);
160
+ cleanup();
161
+ });
162
+ });
163
+ }
164
+
165
+ // src/index.ts
166
+ function createHandler(config) {
167
+ return async function handler(activation) {
168
+ return runWorker({
169
+ ...config,
170
+ id: activation.id,
171
+ cwd: activation.cwd,
172
+ data: activation.data,
173
+ env: activation.env
174
+ });
175
+ };
176
+ }
177
+ export {
178
+ createHandler
179
+ };
180
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/worker.ts","../src/index.ts"],"sourcesContent":["import {fork} from 'child_process'\nimport {join} from 'path'\nimport {WorkerContext, WorkerError, WorkerErrorCode, WorkerResult} from './types.js'\nimport {createWriteStream, appendFileSync} from 'fs'\nimport {ensureDir} from './util/fs.js'\nimport {randomUUID} from 'crypto'\n\nexport function startWorkerGuard(\n child: any,\n opts: {\n ttl?: number\n memory?: number\n },\n suspended?: (reason: string) => void,\n) {\n const {ttl = 5000, memory = 128} = opts\n\n let ttlTimer: NodeJS.Timeout | null = null\n let killed = false\n\n const kill = (reason: string) => {\n if (killed) return\n killed = true\n\n if (ttlTimer) clearTimeout(ttlTimer)\n\n child.kill('SIGKILL')\n suspended?.(reason)\n }\n\n // TTL watchdog\n ttlTimer = setTimeout(() => {\n kill(`ttl exceeded limit (limit: ${ttl.toFixed(2)}ms)`)\n }, ttl)\n\n child.on('message', (msg: any) => {\n if (msg.type !== 'ALIVE') {\n return\n }\n\n // (v0.1.0) this isn't set in stone\n // may be worth using RSS\n const heapUsed = msg.memory?.heapUsed ?? 0\n const memMB = heapUsed / 1024 / 1024\n\n if (memMB > memory) {\n kill(`memory limit exceeded: ${memMB.toFixed(2)}MB/${memory.toFixed(2)}MB`)\n }\n })\n\n child.on('exit', () => {\n if (ttlTimer) clearTimeout(ttlTimer)\n })\n}\n\ntype ChildMessage<T> =\n | {type: 'ALIVE'; error: undefined; result: undefined}\n | {type: 'DONE'; result: WorkerResult<T>; error: undefined | null}\n | {type: 'ERROR'; result: undefined | null; error: WorkerError}\n\nexport function normaliseKeys(value: any): any {\n if (Array.isArray(value)) {\n return value.map(normaliseKeys)\n }\n\n if (value && typeof value === 'object' && value.constructor === Object) {\n const sorted: Record<string, any> = {}\n\n for (const key of Object.keys(value).sort()) {\n sorted[key] = normaliseKeys(value[key])\n }\n\n return sorted\n }\n\n return value\n}\n\nexport function formatWorkerResult(opts: {result?: any; error?: any; duration: number}): WorkerResult<any> {\n return {\n version: 'v1',\n ok: !opts.error,\n result: opts.result ?? null,\n error: opts.error ?? null,\n duration: opts.duration,\n }\n}\n\nexport async function runWorker<T>(context: WorkerContext): Promise<WorkerResult<T>> {\n return new Promise(async (resolve, reject) => {\n const id = randomUUID()\n\n const ctx = {...context, id}\n const start = performance.now()\n\n const path = join(ctx.cwd!, ctx.dist ?? '.xgsd')\n await ensureDir(path)\n\n let started = false\n let completed = false\n let res: WorkerResult<unknown>\n\n const contextStr = JSON.stringify(ctx)\n\n // TODO: remove hardcoded worker path\n const child = fork(join(__dirname, 'process', 'workers.process.js'), {\n stdio: ['inherit', 'pipe', 'pipe', 'ipc'],\n //execArgv: [`--max-old-space-size=${ctx.limits?.memory ?? 128}`],\n env: {\n ...ctx.env,\n XGSD_CTX: contextStr,\n },\n })\n\n const events = createWriteStream(join(path, 'events.jsonl'), {flags: 'a'})\n\n const startGuard = () => {\n startWorkerGuard(child, ctx.limits ?? {}, (reason: string) => {\n if (completed) return\n\n // normalise system/watch dog error\n // then *reject*\n const err: WorkerError = {\n code: WorkerErrorCode.CODE_WORKER_GUARD,\n message: `${reason}`,\n type: 'system',\n }\n\n console.warn(`[guard] worker suspended (reason: ${reason})`)\n\n writeEvent({\n type: 'error',\n message: err.message,\n guard: true,\n timestamp: Date.now(),\n })\n\n cleanup()\n\n resolve(formatWorkerResult({error: err, duration: performance.now() - start}))\n })\n }\n\n const cleanup = () => {\n if (child.connected) {\n child.removeAllListeners('message')\n\n child.disconnect()\n }\n }\n\n const writeEvent = (data: any) => {\n const normalised = normaliseKeys(data)\n events.write(JSON.stringify({...normalised, id}) + '\\n')\n }\n\n child.stdout?.on('data', (chunk) => {\n const lines = chunk.toString().split('\\n').filter(Boolean)\n\n for (const line of lines) {\n // log child process messages (typically from usercode)\n console.log(`${line}`)\n\n try {\n writeEvent(JSON.parse(line))\n } catch {\n // optionally fallback for non-json logs\n writeEvent({\n type: 'log',\n message: line,\n timestamp: Date.now(),\n })\n }\n }\n })\n\n child.stderr?.on('data', (chunk) => {\n const e = {type: 'error', message: chunk.toString(), timestamp: Date.now()}\n console.error(e.message)\n writeEvent(e)\n })\n\n child.on('message', (msg: ChildMessage<unknown>) => {\n if (msg.type !== 'ALIVE' && msg.type !== 'DONE' && msg.type !== 'ERROR') return\n\n if (msg.type === 'ALIVE') {\n if (!started) {\n started = true\n startGuard()\n }\n return\n }\n\n if (msg.type === 'ERROR') {\n const {error} = msg\n\n res = formatWorkerResult({error, duration: performance.now() - start})\n }\n\n if (msg.type === 'DONE') {\n // do something with result\n res = msg.result\n }\n\n res.duration = performance.now() - start\n\n // log activation\n appendFileSync(\n join(path, 'activations.jsonl'),\n JSON.stringify({\n id,\n ok: res.ok,\n code: res.code,\n duration: res.duration,\n error: res.error?.code ?? res.error?.message,\n result: res.result !== null,\n timestamp: new Date().toISOString(),\n }) + '\\n',\n )\n\n completed = true\n\n resolve(res as any)\n cleanup()\n })\n })\n}\n","import {WorkerResult, WorkerConfig} from './types'\nimport {runWorker} from './worker'\n\nexport type Activation<T = unknown> = {\n id?: string\n data?: T\n env?: Record<string, unknown>\n cwd: string\n}\n\nexport type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>\n\nexport function createHandler(config: WorkerConfig): ActivationHandler {\n return async function handler(activation) {\n return runWorker({\n ...config,\n id: activation.id,\n cwd: activation.cwd,\n data: activation.data,\n env: activation.env,\n })\n }\n}\n"],"mappings":";;;;;AAAA,SAAQ,YAAW;AACnB,SAAQ,YAAW;AAEnB,SAAQ,mBAAmB,sBAAqB;AAEhD,SAAQ,kBAAiB;AAElB,SAAS,iBACd,OACA,MAIA,WACA;AACA,QAAM,EAAC,MAAM,KAAM,SAAS,IAAG,IAAI;AAEnC,MAAI,WAAkC;AACtC,MAAI,SAAS;AAEb,QAAM,OAAO,CAAC,WAAmB;AAC/B,QAAI,OAAQ;AACZ,aAAS;AAET,QAAI,SAAU,cAAa,QAAQ;AAEnC,UAAM,KAAK,SAAS;AACpB,gBAAY,MAAM;AAAA,EACpB;AAGA,aAAW,WAAW,MAAM;AAC1B,SAAK,8BAA8B,IAAI,QAAQ,CAAC,CAAC,KAAK;AAAA,EACxD,GAAG,GAAG;AAEN,QAAM,GAAG,WAAW,CAAC,QAAa;AAChC,QAAI,IAAI,SAAS,SAAS;AACxB;AAAA,IACF;AAIA,UAAM,WAAW,IAAI,QAAQ,YAAY;AACzC,UAAM,QAAQ,WAAW,OAAO;AAEhC,QAAI,QAAQ,QAAQ;AAClB,WAAK,0BAA0B,MAAM,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC,IAAI;AAAA,IAC5E;AAAA,EACF,CAAC;AAED,QAAM,GAAG,QAAQ,MAAM;AACrB,QAAI,SAAU,cAAa,QAAQ;AAAA,EACrC,CAAC;AACH;AAOO,SAAS,cAAc,OAAiB;AAC7C,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,aAAa;AAAA,EAChC;AAEA,MAAI,SAAS,OAAO,UAAU,YAAY,MAAM,gBAAgB,QAAQ;AACtE,UAAM,SAA8B,CAAC;AAErC,eAAW,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,GAAG;AAC3C,aAAO,GAAG,IAAI,cAAc,MAAM,GAAG,CAAC;AAAA,IACxC;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,MAAwE;AACzG,SAAO;AAAA,IACL,SAAS;AAAA,IACT,IAAI,CAAC,KAAK;AAAA,IACV,QAAQ,KAAK,UAAU;AAAA,IACvB,OAAO,KAAK,SAAS;AAAA,IACrB,UAAU,KAAK;AAAA,EACjB;AACF;AAEA,eAAsB,UAAa,SAAkD;AACnF,SAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAC5C,UAAM,KAAK,WAAW;AAEtB,UAAM,MAAM,EAAC,GAAG,SAAS,GAAE;AAC3B,UAAM,QAAQ,YAAY,IAAI;AAE9B,UAAM,OAAO,KAAK,IAAI,KAAM,IAAI,QAAQ,OAAO;AAC/C,UAAM,UAAU,IAAI;AAEpB,QAAI,UAAU;AACd,QAAI,YAAY;AAChB,QAAI;AAEJ,UAAM,aAAa,KAAK,UAAU,GAAG;AAGrC,UAAM,QAAQ,KAAK,KAAK,WAAW,WAAW,oBAAoB,GAAG;AAAA,MACnE,OAAO,CAAC,WAAW,QAAQ,QAAQ,KAAK;AAAA;AAAA,MAExC,KAAK;AAAA,QACH,GAAG,IAAI;AAAA,QACP,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAED,UAAM,SAAS,kBAAkB,KAAK,MAAM,cAAc,GAAG,EAAC,OAAO,IAAG,CAAC;AAEzE,UAAM,aAAa,MAAM;AACvB,uBAAiB,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,WAAmB;AAC5D,YAAI,UAAW;AAIf,cAAM,MAAmB;AAAA,UACvB;AAAA,UACA,SAAS,GAAG,MAAM;AAAA,UAClB,MAAM;AAAA,QACR;AAEA,gBAAQ,KAAK,qCAAqC,MAAM,GAAG;AAE3D,mBAAW;AAAA,UACT,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,OAAO;AAAA,UACP,WAAW,KAAK,IAAI;AAAA,QACtB,CAAC;AAED,gBAAQ;AAER,gBAAQ,mBAAmB,EAAC,OAAO,KAAK,UAAU,YAAY,IAAI,IAAI,MAAK,CAAC,CAAC;AAAA,MAC/E,CAAC;AAAA,IACH;AAEA,UAAM,UAAU,MAAM;AACpB,UAAI,MAAM,WAAW;AACnB,cAAM,mBAAmB,SAAS;AAElC,cAAM,WAAW;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,aAAa,CAAC,SAAc;AAChC,YAAM,aAAa,cAAc,IAAI;AACrC,aAAO,MAAM,KAAK,UAAU,EAAC,GAAG,YAAY,GAAE,CAAC,IAAI,IAAI;AAAA,IACzD;AAEA,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,YAAM,QAAQ,MAAM,SAAS,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEzD,iBAAW,QAAQ,OAAO;AAExB,gBAAQ,IAAI,GAAG,IAAI,EAAE;AAErB,YAAI;AACF,qBAAW,KAAK,MAAM,IAAI,CAAC;AAAA,QAC7B,QAAQ;AAEN,qBAAW;AAAA,YACT,MAAM;AAAA,YACN,SAAS;AAAA,YACT,WAAW,KAAK,IAAI;AAAA,UACtB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,YAAM,IAAI,EAAC,MAAM,SAAS,SAAS,MAAM,SAAS,GAAG,WAAW,KAAK,IAAI,EAAC;AAC1E,cAAQ,MAAM,EAAE,OAAO;AACvB,iBAAW,CAAC;AAAA,IACd,CAAC;AAED,UAAM,GAAG,WAAW,CAAC,QAA+B;AAClD,UAAI,IAAI,SAAS,WAAW,IAAI,SAAS,UAAU,IAAI,SAAS,QAAS;AAEzE,UAAI,IAAI,SAAS,SAAS;AACxB,YAAI,CAAC,SAAS;AACZ,oBAAU;AACV,qBAAW;AAAA,QACb;AACA;AAAA,MACF;AAEA,UAAI,IAAI,SAAS,SAAS;AACxB,cAAM,EAAC,MAAK,IAAI;AAEhB,cAAM,mBAAmB,EAAC,OAAO,UAAU,YAAY,IAAI,IAAI,MAAK,CAAC;AAAA,MACvE;AAEA,UAAI,IAAI,SAAS,QAAQ;AAEvB,cAAM,IAAI;AAAA,MACZ;AAEA,UAAI,WAAW,YAAY,IAAI,IAAI;AAGnC;AAAA,QACE,KAAK,MAAM,mBAAmB;AAAA,QAC9B,KAAK,UAAU;AAAA,UACb;AAAA,UACA,IAAI,IAAI;AAAA,UACR,MAAM,IAAI;AAAA,UACV,UAAU,IAAI;AAAA,UACd,OAAO,IAAI,OAAO,QAAQ,IAAI,OAAO;AAAA,UACrC,QAAQ,IAAI,WAAW;AAAA,UACvB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC,IAAI;AAAA,MACP;AAEA,kBAAY;AAEZ,cAAQ,GAAU;AAClB,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;;;ACtNO,SAAS,cAAc,QAAyC;AACrE,SAAO,eAAe,QAAQ,YAAY;AACxC,WAAO,UAAU;AAAA,MACf,GAAG;AAAA,MACH,IAAI,WAAW;AAAA,MACf,KAAK,WAAW;AAAA,MAChB,MAAM,WAAW;AAAA,MACjB,KAAK,WAAW;AAAA,IAClB,CAAC;AAAA,EACH;AACF;","names":[]}