@xgsd/workers 0.1.0-beta.0 → 0.1.0-beta.2

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.
@@ -0,0 +1,221 @@
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/types.ts
9
+ var WorkerErrorCode = /* @__PURE__ */ ((WorkerErrorCode2) => {
10
+ WorkerErrorCode2["CODE_WORKER_GUARD"] = "CODE_WORKER_GUARD";
11
+ WorkerErrorCode2["CODE_INVALID_ENTRY_FILE"] = "CODE_INVALID_ENTRY_FILE";
12
+ WorkerErrorCode2["CODE_INVALID_DEFAULT_FUNCTION"] = "CODE_INVALID_DEFAULT_FUNCTION";
13
+ WorkerErrorCode2["CODE_INVALID_MIDDLEWARE_FUNCTION"] = "CODE_INVALID_MIDDLEWARE_FUNCTION";
14
+ WorkerErrorCode2["CODE_BUNDLE_ERROR"] = "CODE_BUNDLE_ERROR";
15
+ return WorkerErrorCode2;
16
+ })(WorkerErrorCode || {});
17
+
18
+ // src/util/fs.ts
19
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
20
+ import { writeFile, readFile, constants, access, mkdir } from "fs/promises";
21
+ async function pathExists(path2) {
22
+ try {
23
+ await access(path2, constants.F_OK);
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ async function ensureDir(path2) {
30
+ await mkdir(path2, { recursive: true });
31
+ }
32
+ function readJsonSync(path2) {
33
+ return JSON.parse(readFileSync(path2, "utf8"));
34
+ }
35
+ function writeJsonSync(path2, data, pretty = true) {
36
+ const json = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
37
+ writeFileSync(path2, json, "utf8");
38
+ }
39
+ function pathExistsSync(path2) {
40
+ try {
41
+ __require("fs").accessSync(path2, constants.F_OK);
42
+ return true;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ // src/bundler.ts
49
+ import { createHash, timingSafeEqual } from "crypto";
50
+ import path, { join, relative, sep } from "path";
51
+ import { readdir, readFile as readFile2, stat } from "fs/promises";
52
+ import { createRequire } from "module";
53
+ async function createBundle({
54
+ project,
55
+ dist,
56
+ cwd,
57
+ entry,
58
+ cacheStrategy,
59
+ log
60
+ }) {
61
+ const start = performance.now();
62
+ const xgsd = join(project, dist ?? ".xgsd");
63
+ const out = join(xgsd, "bundle.js");
64
+ const entryFile = join(project, entry);
65
+ const packageJsonPath = join(project, "package.json");
66
+ const outPathRel = join(dist ?? ".xgsd", "bundle.js");
67
+ const hash = await calculateProjectHash(project);
68
+ const outdir = path.dirname(out);
69
+ const packageJson = await readJsonSync(packageJsonPath);
70
+ const outPackageJsonPath = join(outdir, "package.json");
71
+ const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out);
72
+ if (cacheFilesExist && cacheStrategy === "always") {
73
+ console.log(`${outPathRel} loaded from cache (set cache.strategy = "never" if this is unintentional)`);
74
+ return out;
75
+ }
76
+ if (cacheFilesExist && cacheStrategy === "change") {
77
+ const outPackageJson = readJsonSync(outPackageJsonPath);
78
+ if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {
79
+ console.log(`${outPathRel} loaded from cache (set cache.strategy = "never" if this is unintentional)`);
80
+ return out;
81
+ }
82
+ }
83
+ const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0]);
84
+ const generated = (/* @__PURE__ */ new Date()).toISOString();
85
+ await bundle({
86
+ entry: entryFile,
87
+ out,
88
+ banner: {
89
+ generated,
90
+ hash
91
+ },
92
+ format: "esm",
93
+ dependencies
94
+ });
95
+ writeJsonSync(path.join(outdir, "package.json"), {
96
+ ...packageJson,
97
+ hash,
98
+ generated,
99
+ type: "module"
100
+ });
101
+ const ms = performance.now() - start;
102
+ console.log(`[bundler] copied package.json to ${join(dist ?? ".xgsd", "package.json")}`);
103
+ console.log(`[bundler] ${entry} bundled to ${outPathRel}`);
104
+ console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`);
105
+ if (cacheStrategy === "never") {
106
+ console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`);
107
+ }
108
+ return out;
109
+ }
110
+ function bannerLines(object) {
111
+ const lines = [];
112
+ lines.push(" * xGSD bundle.js");
113
+ for (const key of Object.keys(object)) {
114
+ lines.push(` * ${key}: ${object[key]}`);
115
+ }
116
+ lines.push(" * WARNING: this file is generated. Do not edit manually.");
117
+ return lines.join("\r\n");
118
+ }
119
+ function resolveDependency(dependency, projectRoot) {
120
+ try {
121
+ const require2 = createRequire(join(projectRoot, "package.json"));
122
+ return require2(dependency);
123
+ } catch {
124
+ }
125
+ throw new Error(
126
+ `Could not resolve ${dependency}.
127
+ Install it with \`yarn add ${dependency}\`.
128
+ Path: ${projectRoot}.`
129
+ );
130
+ }
131
+ async function calculateProjectHash(project) {
132
+ const hashes = await collectProjectHashes(project, {
133
+ ignore: ["node_modules", ".xgsd", "dist", ".git"],
134
+ filter: (path2) => path2.endsWith(".js") || path2.endsWith(".ts")
135
+ });
136
+ const normalised = hashes.map((h) => h.hash.trim().slice(0, 9)).sort().join("|");
137
+ return createHash("sha256").update(normalised).digest("hex");
138
+ }
139
+ async function collectProjectHashes(projectPath, options = {}) {
140
+ const { ignore = ["node_modules"], filter = () => true } = options;
141
+ const files = [];
142
+ const ignored = new Set(ignore);
143
+ const shouldIgnore = (target) => {
144
+ const parts = relative(projectPath, target).split(sep);
145
+ return parts.some((part) => ignored.has(part));
146
+ };
147
+ const hashFile = async (filePath) => {
148
+ const buffer = await readFile2(filePath);
149
+ return createHash("sha256").update(buffer).digest("hex");
150
+ };
151
+ const visit = async (current) => {
152
+ if (shouldIgnore(current)) {
153
+ return;
154
+ }
155
+ const entries = await readdir(current);
156
+ for (const entry of entries) {
157
+ const fullPath = join(current, entry);
158
+ if (shouldIgnore(fullPath)) {
159
+ continue;
160
+ }
161
+ const info = await stat(fullPath);
162
+ if (info.isDirectory()) {
163
+ await visit(fullPath);
164
+ continue;
165
+ }
166
+ if (!info.isFile()) {
167
+ continue;
168
+ }
169
+ const path2 = relative(projectPath, fullPath);
170
+ if (!filter(path2)) {
171
+ continue;
172
+ }
173
+ files.push({
174
+ path: path2,
175
+ hash: await hashFile(fullPath),
176
+ size: info.size
177
+ });
178
+ }
179
+ };
180
+ await visit(projectPath);
181
+ return files.sort((a, b) => a.path.localeCompare(b.path));
182
+ }
183
+ function safeHashCompare(a, b) {
184
+ const abuf = Buffer.from(a, "hex");
185
+ const bbuf = Buffer.from(b, "hex");
186
+ return timingSafeEqual(abuf, bbuf);
187
+ }
188
+ async function bundle(options) {
189
+ const { dependencies } = options;
190
+ const esbuild = resolveDependency("esbuild", path.dirname(options.entry));
191
+ if (esbuild.version) {
192
+ console.log(`[bundler] building with esbuild@${esbuild.version}`);
193
+ }
194
+ return esbuild.build({
195
+ keepNames: true,
196
+ entryPoints: [options.entry],
197
+ bundle: true,
198
+ platform: "node",
199
+ outfile: options.out,
200
+ format: options.format,
201
+ minify: false,
202
+ sourcemap: false,
203
+ external: dependencies,
204
+ banner: {
205
+ js: `
206
+ /**
207
+ ${bannerLines(options.banner)}
208
+ */
209
+ `.trim()
210
+ }
211
+ });
212
+ }
213
+
214
+ export {
215
+ WorkerErrorCode,
216
+ pathExists,
217
+ ensureDir,
218
+ createBundle,
219
+ resolveDependency
220
+ };
221
+ //# sourceMappingURL=chunk-7KEXJOGB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/util/fs.ts","../src/bundler.ts"],"sourcesContent":["export enum WorkerErrorCode {\n // thrown when limits exceeded (ttl/memory)\n CODE_WORKER_GUARD = 'CODE_WORKER_GUARD',\n\n // thrown when entry file is invalid/cannot be parsed\n CODE_INVALID_ENTRY_FILE = 'CODE_INVALID_ENTRY_FILE',\n\n // thrown when default is not a function\n CODE_INVALID_DEFAULT_FUNCTION = 'CODE_INVALID_DEFAULT_FUNCTION',\n\n CODE_INVALID_MIDDLEWARE_FUNCTION = 'CODE_INVALID_MIDDLEWARE_FUNCTION',\n\n // thrown when bundling fails\n CODE_BUNDLE_ERROR = 'CODE_BUNDLE_ERROR',\n}\n\nexport type WorkerErrorType = 'user' | 'system' | 'unknown'\nexport type WorkerError = {\n code?: WorkerErrorCode\n message?: string\n type?: WorkerErrorType\n}\n\nexport type WorkerResult<T> =\n | {\n version: 'v1'\n ok: true\n code?: number\n result: T\n error: null\n duration: number\n }\n | {\n version: 'v1'\n ok: false\n code?: number\n result: null\n error: WorkerError\n duration: number\n }\n\nexport type WorkerConfig = {\n entry: string\n dist?: string\n bundler?: {\n enabled?: boolean\n cache?: {\n strategy: 'never'\n }\n }\n http?: {\n enabled?: boolean\n }\n limits?: {\n ttl?: number\n memory?: number\n }\n}\n\nexport type WorkerContext<T = unknown> = WorkerConfig & {\n id?: string\n data: T\n cwd: string\n result?: any\n error?: any\n code?: number\n env?: Record<string, any>\n pid?: number\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","import {createHash, timingSafeEqual} from 'crypto'\nimport path, {join, relative, sep} from 'path'\nimport {readdir, readFile, stat} from 'fs/promises'\nimport {pathExistsSync, readJsonSync, writeJsonSync} from './util/fs'\nimport {createRequire} from 'module'\n\nexport async function createBundle({\n project,\n dist,\n cwd,\n entry,\n cacheStrategy,\n log,\n}: {\n project: string\n dist?: string\n cwd?: string\n entry: string\n cacheStrategy: 'always' | 'change' | 'never'\n log?: boolean\n}): Promise<string> {\n const start = performance.now()\n\n const xgsd = join(project, dist ?? '.xgsd')\n const out = join(xgsd, 'bundle.js')\n const entryFile = join(project, entry)\n const packageJsonPath = join(project, 'package.json')\n const outPathRel = join(dist ?? '.xgsd', 'bundle.js')\n\n // v0.7 note\n // dont do this as it adds 20-30MB of memory before anything even runs\n // bundling is fine but current AST parsing/traversal is unneeded\n // instead split into two concerns: dependencies (from package.json) and code changes (from hashes)\n // do this instead:\n const hash = await calculateProjectHash(project)\n const outdir = path.dirname(out)\n\n const packageJson = await readJsonSync(packageJsonPath)\n\n const outPackageJsonPath = join(outdir, 'package.json')\n const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out)\n\n if (cacheFilesExist && cacheStrategy === 'always') {\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n\n if (cacheFilesExist && cacheStrategy === 'change') {\n const outPackageJson = readJsonSync(outPackageJsonPath)\n\n if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {\n // cache hit\n\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n }\n\n const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0])\n const generated = new Date().toISOString()\n\n // for now let esbuild notify of errors\n await bundle({\n entry: entryFile,\n out,\n banner: {\n generated,\n hash,\n },\n format: 'esm',\n dependencies,\n })\n\n writeJsonSync(path.join(outdir, 'package.json'), {\n ...packageJson,\n hash,\n generated,\n type: 'module',\n })\n\n const ms = performance.now() - start\n\n console.log(`[bundler] copied package.json to ${join(dist ?? '.xgsd', 'package.json')}`)\n console.log(`[bundler] ${entry} bundled to ${outPathRel}`)\n console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`)\n\n if (cacheStrategy === 'never') {\n console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`)\n }\n\n return out\n}\n\nfunction bannerLines(object: Record<string, string>) {\n const lines = []\n lines.push(' * xGSD bundle.js')\n for (const key of Object.keys(object)) {\n lines.push(` * ${key}: ${object[key]}`)\n }\n lines.push(' * WARNING: this file is generated. Do not edit manually.')\n return lines.join('\\r\\n')\n}\n\nexport function resolvePath(moduleName: string, root: string): string {\n return require.resolve(moduleName, {\n paths: [root],\n })\n}\n\nexport function resolveDependency(dependency: string, projectRoot: string): any {\n try {\n const require = createRequire(join(projectRoot, 'package.json'))\n return require(dependency)\n } catch {}\n\n throw new Error(\n `Could not resolve ${dependency}.\\nInstall it with \\`yarn add ${dependency}\\`.\\nPath: ${projectRoot}.`,\n )\n}\n\nexport type WalkedFile = {\n path: string\n hash: string\n size: number\n}\n\ntype WalkOptions = {\n ignore?: string[]\n filter?: (path: string) => boolean\n}\n\nexport async function calculateProjectHash(project: string): Promise<string> {\n const hashes = await collectProjectHashes(project, {\n ignore: ['node_modules', '.xgsd', 'dist', '.git'],\n filter: (path) => path.endsWith('.js') || path.endsWith('.ts'),\n })\n\n const normalised = hashes\n .map((h) => h.hash.trim().slice(0, 9))\n .sort()\n .join('|')\n\n return createHash('sha256').update(normalised).digest('hex')\n}\n\nexport async function collectProjectHashes(projectPath: string, options: WalkOptions = {}): Promise<WalkedFile[]> {\n const {ignore = ['node_modules'], filter = () => true} = options\n\n const files: WalkedFile[] = []\n\n const ignored = new Set(ignore)\n\n const shouldIgnore = (target: string) => {\n const parts = relative(projectPath, target).split(sep)\n\n return parts.some((part) => ignored.has(part))\n }\n\n const hashFile = async (filePath: string) => {\n const buffer = await readFile(filePath)\n\n return createHash('sha256').update(buffer).digest('hex')\n }\n\n const visit = async (current: string): Promise<void> => {\n if (shouldIgnore(current)) {\n return\n }\n\n const entries = await readdir(current)\n\n for (const entry of entries) {\n const fullPath = join(current, entry)\n\n if (shouldIgnore(fullPath)) {\n continue\n }\n\n const info = await stat(fullPath)\n\n if (info.isDirectory()) {\n await visit(fullPath)\n continue\n }\n\n if (!info.isFile()) {\n continue\n }\n\n const path = relative(projectPath, fullPath)\n\n if (!filter(path)) {\n continue\n }\n\n files.push({\n path,\n hash: await hashFile(fullPath),\n size: info.size,\n })\n }\n }\n\n await visit(projectPath)\n\n return files.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function safeHashCompare(a: string, b: string): boolean {\n const abuf = Buffer.from(a, 'hex')\n const bbuf = Buffer.from(b, 'hex')\n\n return timingSafeEqual(abuf, bbuf)\n}\n\nexport async function bundle(options: {\n entry: string\n out: string\n format: 'esm' | 'cjs'\n banner: Record<string, string>\n dependencies: string[]\n}) {\n const {dependencies} = options\n\n const esbuild = resolveDependency('esbuild', path.dirname(options.entry))\n\n if (esbuild.version) {\n console.log(`[bundler] building with esbuild@${esbuild.version}`)\n }\n\n return esbuild.build({\n keepNames: true,\n entryPoints: [options.entry],\n bundle: true,\n platform: 'node',\n outfile: options.out,\n format: options.format,\n minify: false,\n sourcemap: false,\n external: dependencies,\n banner: {\n js: `\n/**\n${bannerLines(options.banner)}\n */\n`.trim(),\n },\n })\n}\n"],"mappings":"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","names":["WorkerErrorCode","path","path","path","readFile","require","path","readFile"]}
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,24 +17,47 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var src_exports = {};
22
32
  __export(src_exports, {
23
- createHandler: () => createHandler
33
+ WorkerErrorCode: () => WorkerErrorCode,
34
+ createHandler: () => createHandler,
35
+ resolveDependency: () => resolveDependency,
36
+ runWorker: () => runWorker
24
37
  });
25
38
  module.exports = __toCommonJS(src_exports);
26
39
 
27
40
  // src/worker.ts
28
41
  var import_child_process = require("child_process");
29
42
  var import_path = require("path");
43
+
44
+ // src/types.ts
45
+ var WorkerErrorCode = /* @__PURE__ */ ((WorkerErrorCode2) => {
46
+ WorkerErrorCode2["CODE_WORKER_GUARD"] = "CODE_WORKER_GUARD";
47
+ WorkerErrorCode2["CODE_INVALID_ENTRY_FILE"] = "CODE_INVALID_ENTRY_FILE";
48
+ WorkerErrorCode2["CODE_INVALID_DEFAULT_FUNCTION"] = "CODE_INVALID_DEFAULT_FUNCTION";
49
+ WorkerErrorCode2["CODE_INVALID_MIDDLEWARE_FUNCTION"] = "CODE_INVALID_MIDDLEWARE_FUNCTION";
50
+ WorkerErrorCode2["CODE_BUNDLE_ERROR"] = "CODE_BUNDLE_ERROR";
51
+ return WorkerErrorCode2;
52
+ })(WorkerErrorCode || {});
53
+
54
+ // src/worker.ts
30
55
  var import_fs = require("fs");
31
56
 
32
57
  // src/util/fs.ts
33
58
  var import_promises = require("fs/promises");
34
- async function ensureDir(path) {
35
- await (0, import_promises.mkdir)(path, { recursive: true });
59
+ async function ensureDir(path2) {
60
+ await (0, import_promises.mkdir)(path2, { recursive: true });
36
61
  }
37
62
 
38
63
  // src/worker.ts
@@ -92,8 +117,8 @@ async function runWorker(context) {
92
117
  const id = (0, import_crypto.randomUUID)();
93
118
  const ctx = { ...context, id };
94
119
  const start = performance.now();
95
- const path = (0, import_path.join)(ctx.cwd, ctx.dist ?? ".xgsd");
96
- await ensureDir(path);
120
+ const path2 = (0, import_path.join)(ctx.cwd, ctx.dist ?? ".xgsd");
121
+ await ensureDir(path2);
97
122
  let started = false;
98
123
  let completed = false;
99
124
  let res;
@@ -106,7 +131,7 @@ async function runWorker(context) {
106
131
  XGSD_CTX: contextStr
107
132
  }
108
133
  });
109
- const events = (0, import_fs.createWriteStream)((0, import_path.join)(path, "events.jsonl"), { flags: "a" });
134
+ const events = (0, import_fs.createWriteStream)((0, import_path.join)(path2, "events.jsonl"), { flags: "a" });
110
135
  const startGuard = () => {
111
136
  startWorkerGuard(child, ctx.limits ?? {}, (reason) => {
112
137
  if (completed) return;
@@ -174,7 +199,7 @@ async function runWorker(context) {
174
199
  }
175
200
  res.duration = performance.now() - start;
176
201
  (0, import_fs.appendFileSync)(
177
- (0, import_path.join)(path, "activations.jsonl"),
202
+ (0, import_path.join)(path2, "activations.jsonl"),
178
203
  JSON.stringify({
179
204
  id,
180
205
  ok: res.ok,
@@ -192,6 +217,22 @@ async function runWorker(context) {
192
217
  });
193
218
  }
194
219
 
220
+ // src/bundler.ts
221
+ var import_path2 = __toESM(require("path"), 1);
222
+ var import_module = require("module");
223
+ function resolveDependency(dependency, projectRoot) {
224
+ try {
225
+ const require2 = (0, import_module.createRequire)((0, import_path2.join)(projectRoot, "package.json"));
226
+ return require2(dependency);
227
+ } catch {
228
+ }
229
+ throw new Error(
230
+ `Could not resolve ${dependency}.
231
+ Install it with \`yarn add ${dependency}\`.
232
+ Path: ${projectRoot}.`
233
+ );
234
+ }
235
+
195
236
  // src/index.ts
196
237
  function createHandler(config) {
197
238
  return async function handler(activation) {
@@ -206,6 +247,9 @@ function createHandler(config) {
206
247
  }
207
248
  // Annotate the CommonJS export names for ESM import in node:
208
249
  0 && (module.exports = {
209
- createHandler
250
+ WorkerErrorCode,
251
+ createHandler,
252
+ resolveDependency,
253
+ runWorker
210
254
  });
211
255
  //# sourceMappingURL=index.cjs.map
@@ -1 +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":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/worker.ts","../src/types.ts","../src/util/fs.ts","../src/bundler.ts"],"sourcesContent":["import {WorkerResult, WorkerConfig} from './types.js'\nimport {runWorker} from './worker.js'\n\nexport {runWorker}\nexport * from './types.js'\n\nexport {resolveDependency} from './bundler.js'\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","export enum WorkerErrorCode {\n // thrown when limits exceeded (ttl/memory)\n CODE_WORKER_GUARD = 'CODE_WORKER_GUARD',\n\n // thrown when entry file is invalid/cannot be parsed\n CODE_INVALID_ENTRY_FILE = 'CODE_INVALID_ENTRY_FILE',\n\n // thrown when default is not a function\n CODE_INVALID_DEFAULT_FUNCTION = 'CODE_INVALID_DEFAULT_FUNCTION',\n\n CODE_INVALID_MIDDLEWARE_FUNCTION = 'CODE_INVALID_MIDDLEWARE_FUNCTION',\n\n // thrown when bundling fails\n CODE_BUNDLE_ERROR = 'CODE_BUNDLE_ERROR',\n}\n\nexport type WorkerErrorType = 'user' | 'system' | 'unknown'\nexport type WorkerError = {\n code?: WorkerErrorCode\n message?: string\n type?: WorkerErrorType\n}\n\nexport type WorkerResult<T> =\n | {\n version: 'v1'\n ok: true\n code?: number\n result: T\n error: null\n duration: number\n }\n | {\n version: 'v1'\n ok: false\n code?: number\n result: null\n error: WorkerError\n duration: number\n }\n\nexport type WorkerConfig = {\n entry: string\n dist?: string\n bundler?: {\n enabled?: boolean\n cache?: {\n strategy: 'never'\n }\n }\n http?: {\n enabled?: boolean\n }\n limits?: {\n ttl?: number\n memory?: number\n }\n}\n\nexport type WorkerContext<T = unknown> = WorkerConfig & {\n id?: string\n data: T\n cwd: string\n result?: any\n error?: any\n code?: number\n env?: Record<string, any>\n pid?: number\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","import {createHash, timingSafeEqual} from 'crypto'\nimport path, {join, relative, sep} from 'path'\nimport {readdir, readFile, stat} from 'fs/promises'\nimport {pathExistsSync, readJsonSync, writeJsonSync} from './util/fs'\nimport {createRequire} from 'module'\n\nexport async function createBundle({\n project,\n dist,\n cwd,\n entry,\n cacheStrategy,\n log,\n}: {\n project: string\n dist?: string\n cwd?: string\n entry: string\n cacheStrategy: 'always' | 'change' | 'never'\n log?: boolean\n}): Promise<string> {\n const start = performance.now()\n\n const xgsd = join(project, dist ?? '.xgsd')\n const out = join(xgsd, 'bundle.js')\n const entryFile = join(project, entry)\n const packageJsonPath = join(project, 'package.json')\n const outPathRel = join(dist ?? '.xgsd', 'bundle.js')\n\n // v0.7 note\n // dont do this as it adds 20-30MB of memory before anything even runs\n // bundling is fine but current AST parsing/traversal is unneeded\n // instead split into two concerns: dependencies (from package.json) and code changes (from hashes)\n // do this instead:\n const hash = await calculateProjectHash(project)\n const outdir = path.dirname(out)\n\n const packageJson = await readJsonSync(packageJsonPath)\n\n const outPackageJsonPath = join(outdir, 'package.json')\n const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out)\n\n if (cacheFilesExist && cacheStrategy === 'always') {\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n\n if (cacheFilesExist && cacheStrategy === 'change') {\n const outPackageJson = readJsonSync(outPackageJsonPath)\n\n if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {\n // cache hit\n\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n }\n\n const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0])\n const generated = new Date().toISOString()\n\n // for now let esbuild notify of errors\n await bundle({\n entry: entryFile,\n out,\n banner: {\n generated,\n hash,\n },\n format: 'esm',\n dependencies,\n })\n\n writeJsonSync(path.join(outdir, 'package.json'), {\n ...packageJson,\n hash,\n generated,\n type: 'module',\n })\n\n const ms = performance.now() - start\n\n console.log(`[bundler] copied package.json to ${join(dist ?? '.xgsd', 'package.json')}`)\n console.log(`[bundler] ${entry} bundled to ${outPathRel}`)\n console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`)\n\n if (cacheStrategy === 'never') {\n console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`)\n }\n\n return out\n}\n\nfunction bannerLines(object: Record<string, string>) {\n const lines = []\n lines.push(' * xGSD bundle.js')\n for (const key of Object.keys(object)) {\n lines.push(` * ${key}: ${object[key]}`)\n }\n lines.push(' * WARNING: this file is generated. Do not edit manually.')\n return lines.join('\\r\\n')\n}\n\nexport function resolvePath(moduleName: string, root: string): string {\n return require.resolve(moduleName, {\n paths: [root],\n })\n}\n\nexport function resolveDependency(dependency: string, projectRoot: string): any {\n try {\n const require = createRequire(join(projectRoot, 'package.json'))\n return require(dependency)\n } catch {}\n\n throw new Error(\n `Could not resolve ${dependency}.\\nInstall it with \\`yarn add ${dependency}\\`.\\nPath: ${projectRoot}.`,\n )\n}\n\nexport type WalkedFile = {\n path: string\n hash: string\n size: number\n}\n\ntype WalkOptions = {\n ignore?: string[]\n filter?: (path: string) => boolean\n}\n\nexport async function calculateProjectHash(project: string): Promise<string> {\n const hashes = await collectProjectHashes(project, {\n ignore: ['node_modules', '.xgsd', 'dist', '.git'],\n filter: (path) => path.endsWith('.js') || path.endsWith('.ts'),\n })\n\n const normalised = hashes\n .map((h) => h.hash.trim().slice(0, 9))\n .sort()\n .join('|')\n\n return createHash('sha256').update(normalised).digest('hex')\n}\n\nexport async function collectProjectHashes(projectPath: string, options: WalkOptions = {}): Promise<WalkedFile[]> {\n const {ignore = ['node_modules'], filter = () => true} = options\n\n const files: WalkedFile[] = []\n\n const ignored = new Set(ignore)\n\n const shouldIgnore = (target: string) => {\n const parts = relative(projectPath, target).split(sep)\n\n return parts.some((part) => ignored.has(part))\n }\n\n const hashFile = async (filePath: string) => {\n const buffer = await readFile(filePath)\n\n return createHash('sha256').update(buffer).digest('hex')\n }\n\n const visit = async (current: string): Promise<void> => {\n if (shouldIgnore(current)) {\n return\n }\n\n const entries = await readdir(current)\n\n for (const entry of entries) {\n const fullPath = join(current, entry)\n\n if (shouldIgnore(fullPath)) {\n continue\n }\n\n const info = await stat(fullPath)\n\n if (info.isDirectory()) {\n await visit(fullPath)\n continue\n }\n\n if (!info.isFile()) {\n continue\n }\n\n const path = relative(projectPath, fullPath)\n\n if (!filter(path)) {\n continue\n }\n\n files.push({\n path,\n hash: await hashFile(fullPath),\n size: info.size,\n })\n }\n }\n\n await visit(projectPath)\n\n return files.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function safeHashCompare(a: string, b: string): boolean {\n const abuf = Buffer.from(a, 'hex')\n const bbuf = Buffer.from(b, 'hex')\n\n return timingSafeEqual(abuf, bbuf)\n}\n\nexport async function bundle(options: {\n entry: string\n out: string\n format: 'esm' | 'cjs'\n banner: Record<string, string>\n dependencies: string[]\n}) {\n const {dependencies} = options\n\n const esbuild = resolveDependency('esbuild', path.dirname(options.entry))\n\n if (esbuild.version) {\n console.log(`[bundler] building with esbuild@${esbuild.version}`)\n }\n\n return esbuild.build({\n keepNames: true,\n entryPoints: [options.entry],\n bundle: true,\n platform: 'node',\n outfile: options.out,\n format: options.format,\n minify: false,\n sourcemap: false,\n external: dependencies,\n banner: {\n js: `\n/**\n${bannerLines(options.banner)}\n */\n`.trim(),\n },\n })\n}\n"],"mappings":"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","names":["WorkerErrorCode","path","path","import_path","require"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,9 @@
1
- import { W as WorkerResult, a as WorkerConfig } from './types-Buhg0r3s.cjs';
1
+ import { W as WorkerContext, a as WorkerResult, b as WorkerConfig } from './types-DL5DfJ18.cjs';
2
+ export { c as WorkerError, d as WorkerErrorCode, e as WorkerErrorType } from './types-DL5DfJ18.cjs';
3
+
4
+ declare function runWorker<T>(context: WorkerContext): Promise<WorkerResult<T>>;
5
+
6
+ declare function resolveDependency(dependency: string, projectRoot: string): any;
2
7
 
3
8
  type Activation<T = unknown> = {
4
9
  id?: string;
@@ -9,4 +14,4 @@ type Activation<T = unknown> = {
9
14
  type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>;
10
15
  declare function createHandler(config: WorkerConfig): ActivationHandler;
11
16
 
12
- export { type Activation, type ActivationHandler, createHandler };
17
+ export { type Activation, type ActivationHandler, WorkerConfig, WorkerContext, WorkerResult, createHandler, resolveDependency, runWorker };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,9 @@
1
- import { W as WorkerResult, a as WorkerConfig } from './types-Buhg0r3s.js';
1
+ import { W as WorkerContext, a as WorkerResult, b as WorkerConfig } from './types-DL5DfJ18.js';
2
+ export { c as WorkerError, d as WorkerErrorCode, e as WorkerErrorType } from './types-DL5DfJ18.js';
3
+
4
+ declare function runWorker<T>(context: WorkerContext): Promise<WorkerResult<T>>;
5
+
6
+ declare function resolveDependency(dependency: string, projectRoot: string): any;
2
7
 
3
8
  type Activation<T = unknown> = {
4
9
  id?: string;
@@ -9,4 +14,4 @@ type Activation<T = unknown> = {
9
14
  type ActivationHandler = <T = unknown>(activation: Activation<T>) => Promise<WorkerResult<T>>;
10
15
  declare function createHandler(config: WorkerConfig): ActivationHandler;
11
16
 
12
- export { type Activation, type ActivationHandler, createHandler };
17
+ export { type Activation, type ActivationHandler, WorkerConfig, WorkerContext, WorkerResult, createHandler, resolveDependency, runWorker };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import {
2
- ensureDir
3
- } from "./chunk-QLD3WJX5.js";
2
+ WorkerErrorCode,
3
+ ensureDir,
4
+ resolveDependency
5
+ } from "./chunk-7KEXJOGB.js";
4
6
 
5
7
  // src/worker.ts
6
8
  import { fork } from "child_process";
@@ -175,6 +177,9 @@ function createHandler(config) {
175
177
  };
176
178
  }
177
179
  export {
178
- createHandler
180
+ WorkerErrorCode,
181
+ createHandler,
182
+ resolveDependency,
183
+ runWorker
179
184
  };
180
185
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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":"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","names":[]}
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.js'\nimport {runWorker} from './worker.js'\n\nexport {runWorker}\nexport * from './types.js'\n\nexport {resolveDependency} from './bundler.js'\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":"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","names":[]}
@@ -137,13 +137,13 @@ function bannerLines(object) {
137
137
  }
138
138
  function resolveDependency(dependency, projectRoot) {
139
139
  try {
140
- const require2 = (0, import_module.createRequire)(projectRoot);
140
+ const require2 = (0, import_module.createRequire)((0, import_path.join)(projectRoot, "package.json"));
141
141
  return require2(dependency);
142
142
  } catch {
143
143
  }
144
144
  throw new Error(
145
145
  `Could not resolve ${dependency}.
146
- Install it with \`yarn add ${dependency}\` or re-install @xgsd/cli
146
+ Install it with \`yarn add ${dependency}\`.
147
147
  Path: ${projectRoot}.`
148
148
  );
149
149
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/process/workers.process.ts","../../src/bundler.ts","../../src/util/fs.ts","../../src/compose.ts"],"sourcesContent":["import {join} from 'path'\nimport {createBundle, resolveDependency} from '../bundler'\nimport {compose, Next} from '../compose'\nimport {WorkerContext, WorkerError, WorkerErrorCode} from '../types'\nimport {pathExists} from '../util/fs'\n\nexport type RunFn<T> = (data: T) => Promise<any>\n\nfunction dispatch(event: 'ALIVE' | 'DONE' | 'ERROR', payload: any) {\n process.send?.({\n type: event,\n ...payload,\n })\n}\n\nfunction startHeartbeat(interval = 50) {\n return setInterval(() => {\n const memory = process.memoryUsage()\n\n dispatch('ALIVE', {\n pid: process.pid,\n uptime: process.uptime(),\n memory: {\n rss: memory.rss,\n heapUsed: memory.heapUsed,\n heapTotal: memory.heapTotal,\n external: memory.external,\n },\n })\n }, interval)\n}\n\nexport function wrapper(fn: RunFn<unknown>) {\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n return async (ctx: WorkerContext, next: Next) => {\n const res = await execute(ctx.data as any, fn)\n\n ctx.result = res.data\n ctx.error = res.error\n\n await next()\n }\n}\n\nasync function main(ctx: WorkerContext) {\n const heartbeat = startHeartbeat()\n\n const {entry, cwd} = ctx\n let entryFile = join(cwd ?? '', entry)\n\n try {\n if (!(await pathExists(entryFile))) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_ENTRY_FILE,\n message: 'entry file not found',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // bundler\n if (ctx.bundler?.enabled) {\n entryFile = await createBundle({\n project: cwd!,\n dist: ctx.dist,\n entry,\n cacheStrategy: ctx.bundler?.cache?.strategy ?? 'never',\n })\n }\n\n let mod = undefined\n try {\n mod = await import(entryFile)\n } catch (error) {}\n\n if (!mod || !mod.default || typeof mod.default !== 'function') {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_DEFAULT_FUNCTION,\n message: 'default must be a function',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // load middleware\n let middleware = []\n if (mod.middleware && typeof mod.middleware === 'function') {\n const start = performance.now()\n middleware = mod.middleware() ?? []\n\n if (!Array.isArray(middleware) || middleware.filter((m) => typeof m !== 'function').length > 0) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_MIDDLEWARE_FUNCTION,\n message: 'middleware not configured correctly',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n const dt = (performance.now() - start).toFixed(2)\n console.log(`[middleware] ${middleware.length} functions registered in ${dt} ms`)\n }\n\n // runtime\n const runtime = compose([...middleware, wrapper(mod.default)])\n\n console.log(`[runtime] started running worker`)\n\n const start = performance.now()\n\n const result = await runtime(ctx)\n\n const ms = performance.now() - start\n console.log(`[runtime] finished running worker took ${ms.toFixed(2)} ms`)\n\n if (result.error) {\n console.warn(`[runtime] finished with errors (error: ${ctx.error?.message ?? 'unknown'})`)\n }\n\n dispatch('DONE', {result})\n } finally {\n clearInterval(heartbeat)\n }\n}\n\nconst ctx = JSON.parse(process.env.XGSD_CTX!) as WorkerContext\nmain(ctx)\n","import {createHash, timingSafeEqual} from 'crypto'\nimport path, {join, relative, sep} from 'path'\nimport {readdir, readFile, stat} from 'fs/promises'\nimport {pathExistsSync, readJsonSync, writeJsonSync} from './util/fs'\nimport {createRequire} from 'module'\n\nexport async function createBundle({\n project,\n dist,\n cwd,\n entry,\n cacheStrategy,\n log,\n}: {\n project: string\n dist?: string\n cwd?: string\n entry: string\n cacheStrategy: 'always' | 'change' | 'never'\n log?: boolean\n}): Promise<string> {\n const start = performance.now()\n\n const xgsd = join(project, dist ?? '.xgsd')\n const out = join(xgsd, 'bundle.js')\n const entryFile = join(project, entry)\n const packageJsonPath = join(project, 'package.json')\n const outPathRel = join(dist ?? '.xgsd', 'bundle.js')\n\n // v0.7 note\n // dont do this as it adds 20-30MB of memory before anything even runs\n // bundling is fine but current AST parsing/traversal is unneeded\n // instead split into two concerns: dependencies (from package.json) and code changes (from hashes)\n // do this instead:\n const hash = await calculateProjectHash(project)\n const outdir = path.dirname(out)\n\n const packageJson = await readJsonSync(packageJsonPath)\n\n const outPackageJsonPath = join(outdir, 'package.json')\n const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out)\n\n if (cacheFilesExist && cacheStrategy === 'always') {\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n\n if (cacheFilesExist && cacheStrategy === 'change') {\n const outPackageJson = readJsonSync(outPackageJsonPath)\n\n if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {\n // cache hit\n\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n }\n\n const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0])\n const generated = new Date().toISOString()\n\n // for now let esbuild notify of errors\n await bundle({\n entry: entryFile,\n out,\n banner: {\n generated,\n hash,\n },\n format: 'esm',\n dependencies,\n })\n\n writeJsonSync(path.join(outdir, 'package.json'), {\n ...packageJson,\n hash,\n generated,\n type: 'module',\n })\n\n const ms = performance.now() - start\n\n console.log(`[bundler] copied package.json to ${join(dist ?? '.xgsd', 'package.json')}`)\n console.log(`[bundler] ${entry} bundled to ${outPathRel}`)\n console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`)\n\n if (cacheStrategy === 'never') {\n console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`)\n }\n\n return out\n}\n\nfunction bannerLines(object: Record<string, string>) {\n const lines = []\n lines.push(' * xGSD bundle.js')\n for (const key of Object.keys(object)) {\n lines.push(` * ${key}: ${object[key]}`)\n }\n lines.push(' * WARNING: this file is generated. Do not edit manually.')\n return lines.join('\\r\\n')\n}\n\nexport function resolvePath(moduleName: string, root: string): string {\n return require.resolve(moduleName, {\n paths: [root],\n })\n}\n\nexport function resolveDependency(dependency: string, projectRoot: string): any {\n try {\n const require = createRequire(projectRoot)\n return require(dependency)\n } catch {}\n\n throw new Error(\n `Could not resolve ${dependency}.\\nInstall it with \\`yarn add ${dependency}\\` or re-install @xgsd/cli\\nPath: ${projectRoot}.`,\n )\n}\n\nexport type WalkedFile = {\n path: string\n hash: string\n size: number\n}\n\ntype WalkOptions = {\n ignore?: string[]\n filter?: (path: string) => boolean\n}\n\nexport async function calculateProjectHash(project: string): Promise<string> {\n const hashes = await collectProjectHashes(project, {\n ignore: ['node_modules', '.xgsd', 'dist', '.git'],\n filter: (path) => path.endsWith('.js') || path.endsWith('.ts'),\n })\n\n const normalised = hashes\n .map((h) => h.hash.trim().slice(0, 9))\n .sort()\n .join('|')\n\n return createHash('sha256').update(normalised).digest('hex')\n}\n\nexport async function collectProjectHashes(projectPath: string, options: WalkOptions = {}): Promise<WalkedFile[]> {\n const {ignore = ['node_modules'], filter = () => true} = options\n\n const files: WalkedFile[] = []\n\n const ignored = new Set(ignore)\n\n const shouldIgnore = (target: string) => {\n const parts = relative(projectPath, target).split(sep)\n\n return parts.some((part) => ignored.has(part))\n }\n\n const hashFile = async (filePath: string) => {\n const buffer = await readFile(filePath)\n\n return createHash('sha256').update(buffer).digest('hex')\n }\n\n const visit = async (current: string): Promise<void> => {\n if (shouldIgnore(current)) {\n return\n }\n\n const entries = await readdir(current)\n\n for (const entry of entries) {\n const fullPath = join(current, entry)\n\n if (shouldIgnore(fullPath)) {\n continue\n }\n\n const info = await stat(fullPath)\n\n if (info.isDirectory()) {\n await visit(fullPath)\n continue\n }\n\n if (!info.isFile()) {\n continue\n }\n\n const path = relative(projectPath, fullPath)\n\n if (!filter(path)) {\n continue\n }\n\n files.push({\n path,\n hash: await hashFile(fullPath),\n size: info.size,\n })\n }\n }\n\n await visit(projectPath)\n\n return files.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function safeHashCompare(a: string, b: string): boolean {\n const abuf = Buffer.from(a, 'hex')\n const bbuf = Buffer.from(b, 'hex')\n\n return timingSafeEqual(abuf, bbuf)\n}\n\nexport async function bundle(options: {\n entry: string\n out: string\n format: 'esm' | 'cjs'\n banner: Record<string, string>\n dependencies: string[]\n}) {\n const {dependencies} = options\n\n const esbuild = resolveDependency('esbuild', path.dirname(options.entry))\n\n if (esbuild.version) {\n console.log(`[bundler] building with esbuild@${esbuild.version}`)\n }\n\n return esbuild.build({\n keepNames: true,\n entryPoints: [options.entry],\n bundle: true,\n platform: 'node',\n outfile: options.out,\n format: options.format,\n minify: false,\n sourcemap: false,\n external: dependencies,\n banner: {\n js: `\n/**\n${bannerLines(options.banner)}\n */\n`.trim(),\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","import {resolveDependency} from './bundler'\nimport {WorkerContext, WorkerResult} from './types'\n\nexport type Next = () => Promise<void>\n\nexport type Middleware = (ctx: WorkerContext, next: Next) => Promise<void>\n\nexport type ComposedMiddleware = (ctx: WorkerContext) => Promise<WorkerResult<unknown>>\n\nexport function compose(middleware: Middleware[]): ComposedMiddleware {\n return async function run(ctx: WorkerContext): Promise<WorkerResult<unknown>> {\n let index = -1\n\n let res: any = {\n version: 'v1',\n ok: undefined,\n result: undefined,\n error: undefined,\n duration: undefined,\n }\n\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times')\n }\n\n index = i\n\n const fn = middleware[i]\n\n if (!fn) {\n return\n }\n\n const executeWrapper = async (ctx: WorkerContext) => {\n await fn(ctx, async () => {\n await dispatch(i + 1)\n })\n\n return ctx\n }\n\n const result = await execute(ctx, executeWrapper)\n\n if (result.error || result.data?.error) {\n res.ok = false\n res.code = ctx.code\n res.result = null\n res.error = result.error ?? result.data?.error\n }\n\n if (result.data && result.data.result) {\n res.ok = true\n res.code = ctx.code\n res.result = result.data.result\n res.error = result.error ?? result.data?.error\n }\n }\n\n await dispatch(0)\n\n return res\n }\n}\n"],"mappings":"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","names":["import_path","import_promises","path","path","path","path","require","path","ctx","dispatch","ctx","start"]}
1
+ {"version":3,"sources":["../../src/process/workers.process.ts","../../src/bundler.ts","../../src/util/fs.ts","../../src/compose.ts"],"sourcesContent":["import {join} from 'path'\nimport {createBundle, resolveDependency} from '../bundler'\nimport {compose, Next} from '../compose'\nimport {WorkerContext, WorkerError, WorkerErrorCode} from '../types'\nimport {pathExists} from '../util/fs'\n\nexport type RunFn<T> = (data: T) => Promise<any>\n\nfunction dispatch(event: 'ALIVE' | 'DONE' | 'ERROR', payload: any) {\n process.send?.({\n type: event,\n ...payload,\n })\n}\n\nfunction startHeartbeat(interval = 50) {\n return setInterval(() => {\n const memory = process.memoryUsage()\n\n dispatch('ALIVE', {\n pid: process.pid,\n uptime: process.uptime(),\n memory: {\n rss: memory.rss,\n heapUsed: memory.heapUsed,\n heapTotal: memory.heapTotal,\n external: memory.external,\n },\n })\n }, interval)\n}\n\nexport function wrapper(fn: RunFn<unknown>) {\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n return async (ctx: WorkerContext, next: Next) => {\n const res = await execute(ctx.data as any, fn)\n\n ctx.result = res.data\n ctx.error = res.error\n\n await next()\n }\n}\n\nasync function main(ctx: WorkerContext) {\n const heartbeat = startHeartbeat()\n\n const {entry, cwd} = ctx\n let entryFile = join(cwd ?? '', entry)\n\n try {\n if (!(await pathExists(entryFile))) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_ENTRY_FILE,\n message: 'entry file not found',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // bundler\n if (ctx.bundler?.enabled) {\n entryFile = await createBundle({\n project: cwd!,\n dist: ctx.dist,\n entry,\n cacheStrategy: ctx.bundler?.cache?.strategy ?? 'never',\n })\n }\n\n let mod = undefined\n try {\n mod = await import(entryFile)\n } catch (error) {}\n\n if (!mod || !mod.default || typeof mod.default !== 'function') {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_DEFAULT_FUNCTION,\n message: 'default must be a function',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // load middleware\n let middleware = []\n if (mod.middleware && typeof mod.middleware === 'function') {\n const start = performance.now()\n middleware = mod.middleware() ?? []\n\n if (!Array.isArray(middleware) || middleware.filter((m) => typeof m !== 'function').length > 0) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_MIDDLEWARE_FUNCTION,\n message: 'middleware not configured correctly',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n const dt = (performance.now() - start).toFixed(2)\n console.log(`[middleware] ${middleware.length} functions registered in ${dt} ms`)\n }\n\n // runtime\n const runtime = compose([...middleware, wrapper(mod.default)])\n\n console.log(`[runtime] started running worker`)\n\n const start = performance.now()\n\n const result = await runtime(ctx)\n\n const ms = performance.now() - start\n console.log(`[runtime] finished running worker took ${ms.toFixed(2)} ms`)\n\n if (result.error) {\n console.warn(`[runtime] finished with errors (error: ${ctx.error?.message ?? 'unknown'})`)\n }\n\n dispatch('DONE', {result})\n } finally {\n clearInterval(heartbeat)\n }\n}\n\nconst ctx = JSON.parse(process.env.XGSD_CTX!) as WorkerContext\nmain(ctx)\n","import {createHash, timingSafeEqual} from 'crypto'\nimport path, {join, relative, sep} from 'path'\nimport {readdir, readFile, stat} from 'fs/promises'\nimport {pathExistsSync, readJsonSync, writeJsonSync} from './util/fs'\nimport {createRequire} from 'module'\n\nexport async function createBundle({\n project,\n dist,\n cwd,\n entry,\n cacheStrategy,\n log,\n}: {\n project: string\n dist?: string\n cwd?: string\n entry: string\n cacheStrategy: 'always' | 'change' | 'never'\n log?: boolean\n}): Promise<string> {\n const start = performance.now()\n\n const xgsd = join(project, dist ?? '.xgsd')\n const out = join(xgsd, 'bundle.js')\n const entryFile = join(project, entry)\n const packageJsonPath = join(project, 'package.json')\n const outPathRel = join(dist ?? '.xgsd', 'bundle.js')\n\n // v0.7 note\n // dont do this as it adds 20-30MB of memory before anything even runs\n // bundling is fine but current AST parsing/traversal is unneeded\n // instead split into two concerns: dependencies (from package.json) and code changes (from hashes)\n // do this instead:\n const hash = await calculateProjectHash(project)\n const outdir = path.dirname(out)\n\n const packageJson = await readJsonSync(packageJsonPath)\n\n const outPackageJsonPath = join(outdir, 'package.json')\n const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out)\n\n if (cacheFilesExist && cacheStrategy === 'always') {\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n\n if (cacheFilesExist && cacheStrategy === 'change') {\n const outPackageJson = readJsonSync(outPackageJsonPath)\n\n if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {\n // cache hit\n\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n }\n\n const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0])\n const generated = new Date().toISOString()\n\n // for now let esbuild notify of errors\n await bundle({\n entry: entryFile,\n out,\n banner: {\n generated,\n hash,\n },\n format: 'esm',\n dependencies,\n })\n\n writeJsonSync(path.join(outdir, 'package.json'), {\n ...packageJson,\n hash,\n generated,\n type: 'module',\n })\n\n const ms = performance.now() - start\n\n console.log(`[bundler] copied package.json to ${join(dist ?? '.xgsd', 'package.json')}`)\n console.log(`[bundler] ${entry} bundled to ${outPathRel}`)\n console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`)\n\n if (cacheStrategy === 'never') {\n console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`)\n }\n\n return out\n}\n\nfunction bannerLines(object: Record<string, string>) {\n const lines = []\n lines.push(' * xGSD bundle.js')\n for (const key of Object.keys(object)) {\n lines.push(` * ${key}: ${object[key]}`)\n }\n lines.push(' * WARNING: this file is generated. Do not edit manually.')\n return lines.join('\\r\\n')\n}\n\nexport function resolvePath(moduleName: string, root: string): string {\n return require.resolve(moduleName, {\n paths: [root],\n })\n}\n\nexport function resolveDependency(dependency: string, projectRoot: string): any {\n try {\n const require = createRequire(join(projectRoot, 'package.json'))\n return require(dependency)\n } catch {}\n\n throw new Error(\n `Could not resolve ${dependency}.\\nInstall it with \\`yarn add ${dependency}\\`.\\nPath: ${projectRoot}.`,\n )\n}\n\nexport type WalkedFile = {\n path: string\n hash: string\n size: number\n}\n\ntype WalkOptions = {\n ignore?: string[]\n filter?: (path: string) => boolean\n}\n\nexport async function calculateProjectHash(project: string): Promise<string> {\n const hashes = await collectProjectHashes(project, {\n ignore: ['node_modules', '.xgsd', 'dist', '.git'],\n filter: (path) => path.endsWith('.js') || path.endsWith('.ts'),\n })\n\n const normalised = hashes\n .map((h) => h.hash.trim().slice(0, 9))\n .sort()\n .join('|')\n\n return createHash('sha256').update(normalised).digest('hex')\n}\n\nexport async function collectProjectHashes(projectPath: string, options: WalkOptions = {}): Promise<WalkedFile[]> {\n const {ignore = ['node_modules'], filter = () => true} = options\n\n const files: WalkedFile[] = []\n\n const ignored = new Set(ignore)\n\n const shouldIgnore = (target: string) => {\n const parts = relative(projectPath, target).split(sep)\n\n return parts.some((part) => ignored.has(part))\n }\n\n const hashFile = async (filePath: string) => {\n const buffer = await readFile(filePath)\n\n return createHash('sha256').update(buffer).digest('hex')\n }\n\n const visit = async (current: string): Promise<void> => {\n if (shouldIgnore(current)) {\n return\n }\n\n const entries = await readdir(current)\n\n for (const entry of entries) {\n const fullPath = join(current, entry)\n\n if (shouldIgnore(fullPath)) {\n continue\n }\n\n const info = await stat(fullPath)\n\n if (info.isDirectory()) {\n await visit(fullPath)\n continue\n }\n\n if (!info.isFile()) {\n continue\n }\n\n const path = relative(projectPath, fullPath)\n\n if (!filter(path)) {\n continue\n }\n\n files.push({\n path,\n hash: await hashFile(fullPath),\n size: info.size,\n })\n }\n }\n\n await visit(projectPath)\n\n return files.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function safeHashCompare(a: string, b: string): boolean {\n const abuf = Buffer.from(a, 'hex')\n const bbuf = Buffer.from(b, 'hex')\n\n return timingSafeEqual(abuf, bbuf)\n}\n\nexport async function bundle(options: {\n entry: string\n out: string\n format: 'esm' | 'cjs'\n banner: Record<string, string>\n dependencies: string[]\n}) {\n const {dependencies} = options\n\n const esbuild = resolveDependency('esbuild', path.dirname(options.entry))\n\n if (esbuild.version) {\n console.log(`[bundler] building with esbuild@${esbuild.version}`)\n }\n\n return esbuild.build({\n keepNames: true,\n entryPoints: [options.entry],\n bundle: true,\n platform: 'node',\n outfile: options.out,\n format: options.format,\n minify: false,\n sourcemap: false,\n external: dependencies,\n banner: {\n js: `\n/**\n${bannerLines(options.banner)}\n */\n`.trim(),\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","import {resolveDependency} from './bundler'\nimport {WorkerContext, WorkerResult} from './types'\n\nexport type Next = () => Promise<void>\n\nexport type Middleware = (ctx: WorkerContext, next: Next) => Promise<void>\n\nexport type ComposedMiddleware = (ctx: WorkerContext) => Promise<WorkerResult<unknown>>\n\nexport function compose(middleware: Middleware[]): ComposedMiddleware {\n return async function run(ctx: WorkerContext): Promise<WorkerResult<unknown>> {\n let index = -1\n\n let res: any = {\n version: 'v1',\n ok: undefined,\n result: undefined,\n error: undefined,\n duration: undefined,\n }\n\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times')\n }\n\n index = i\n\n const fn = middleware[i]\n\n if (!fn) {\n return\n }\n\n const executeWrapper = async (ctx: WorkerContext) => {\n await fn(ctx, async () => {\n await dispatch(i + 1)\n })\n\n return ctx\n }\n\n const result = await execute(ctx, executeWrapper)\n\n if (result.error || result.data?.error) {\n res.ok = false\n res.code = ctx.code\n res.result = null\n res.error = result.error ?? result.data?.error\n }\n\n if (result.data && result.data.result) {\n res.ok = true\n res.code = ctx.code\n res.result = result.data.result\n res.error = result.error ?? result.data?.error\n }\n }\n\n await dispatch(0)\n\n return res\n }\n}\n"],"mappings":"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","names":["import_path","import_promises","path","path","path","path","require","path","ctx","dispatch","ctx","start"]}
@@ -1,4 +1,4 @@
1
- import { b as WorkerContext } from '../types-Buhg0r3s.cjs';
1
+ import { W as WorkerContext } from '../types-DL5DfJ18.cjs';
2
2
 
3
3
  type Next = () => Promise<void>;
4
4
 
@@ -1,4 +1,4 @@
1
- import { b as WorkerContext } from '../types-Buhg0r3s.js';
1
+ import { W as WorkerContext } from '../types-DL5DfJ18.js';
2
2
 
3
3
  type Next = () => Promise<void>;
4
4
 
@@ -1,178 +1,11 @@
1
1
  import {
2
+ createBundle,
2
3
  pathExists,
3
- pathExistsSync,
4
- readJsonSync,
5
- writeJsonSync
6
- } from "../chunk-QLD3WJX5.js";
4
+ resolveDependency
5
+ } from "../chunk-7KEXJOGB.js";
7
6
 
8
7
  // src/process/workers.process.ts
9
- import { join as join2 } from "path";
10
-
11
- // src/bundler.ts
12
- import { createHash, timingSafeEqual } from "crypto";
13
- import path, { join, relative, sep } from "path";
14
- import { readdir, readFile, stat } from "fs/promises";
15
- import { createRequire } from "module";
16
- async function createBundle({
17
- project,
18
- dist,
19
- cwd,
20
- entry,
21
- cacheStrategy,
22
- log
23
- }) {
24
- const start = performance.now();
25
- const xgsd = join(project, dist ?? ".xgsd");
26
- const out = join(xgsd, "bundle.js");
27
- const entryFile = join(project, entry);
28
- const packageJsonPath = join(project, "package.json");
29
- const outPathRel = join(dist ?? ".xgsd", "bundle.js");
30
- const hash = await calculateProjectHash(project);
31
- const outdir = path.dirname(out);
32
- const packageJson = await readJsonSync(packageJsonPath);
33
- const outPackageJsonPath = join(outdir, "package.json");
34
- const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out);
35
- if (cacheFilesExist && cacheStrategy === "always") {
36
- console.log(`${outPathRel} loaded from cache (set cache.strategy = "never" if this is unintentional)`);
37
- return out;
38
- }
39
- if (cacheFilesExist && cacheStrategy === "change") {
40
- const outPackageJson = readJsonSync(outPackageJsonPath);
41
- if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {
42
- console.log(`${outPathRel} loaded from cache (set cache.strategy = "never" if this is unintentional)`);
43
- return out;
44
- }
45
- }
46
- const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0]);
47
- const generated = (/* @__PURE__ */ new Date()).toISOString();
48
- await bundle({
49
- entry: entryFile,
50
- out,
51
- banner: {
52
- generated,
53
- hash
54
- },
55
- format: "esm",
56
- dependencies
57
- });
58
- writeJsonSync(path.join(outdir, "package.json"), {
59
- ...packageJson,
60
- hash,
61
- generated,
62
- type: "module"
63
- });
64
- const ms = performance.now() - start;
65
- console.log(`[bundler] copied package.json to ${join(dist ?? ".xgsd", "package.json")}`);
66
- console.log(`[bundler] ${entry} bundled to ${outPathRel}`);
67
- console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`);
68
- if (cacheStrategy === "never") {
69
- console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`);
70
- }
71
- return out;
72
- }
73
- function bannerLines(object) {
74
- const lines = [];
75
- lines.push(" * xGSD bundle.js");
76
- for (const key of Object.keys(object)) {
77
- lines.push(` * ${key}: ${object[key]}`);
78
- }
79
- lines.push(" * WARNING: this file is generated. Do not edit manually.");
80
- return lines.join("\r\n");
81
- }
82
- function resolveDependency(dependency, projectRoot) {
83
- try {
84
- const require2 = createRequire(projectRoot);
85
- return require2(dependency);
86
- } catch {
87
- }
88
- throw new Error(
89
- `Could not resolve ${dependency}.
90
- Install it with \`yarn add ${dependency}\` or re-install @xgsd/cli
91
- Path: ${projectRoot}.`
92
- );
93
- }
94
- async function calculateProjectHash(project) {
95
- const hashes = await collectProjectHashes(project, {
96
- ignore: ["node_modules", ".xgsd", "dist", ".git"],
97
- filter: (path2) => path2.endsWith(".js") || path2.endsWith(".ts")
98
- });
99
- const normalised = hashes.map((h) => h.hash.trim().slice(0, 9)).sort().join("|");
100
- return createHash("sha256").update(normalised).digest("hex");
101
- }
102
- async function collectProjectHashes(projectPath, options = {}) {
103
- const { ignore = ["node_modules"], filter = () => true } = options;
104
- const files = [];
105
- const ignored = new Set(ignore);
106
- const shouldIgnore = (target) => {
107
- const parts = relative(projectPath, target).split(sep);
108
- return parts.some((part) => ignored.has(part));
109
- };
110
- const hashFile = async (filePath) => {
111
- const buffer = await readFile(filePath);
112
- return createHash("sha256").update(buffer).digest("hex");
113
- };
114
- const visit = async (current) => {
115
- if (shouldIgnore(current)) {
116
- return;
117
- }
118
- const entries = await readdir(current);
119
- for (const entry of entries) {
120
- const fullPath = join(current, entry);
121
- if (shouldIgnore(fullPath)) {
122
- continue;
123
- }
124
- const info = await stat(fullPath);
125
- if (info.isDirectory()) {
126
- await visit(fullPath);
127
- continue;
128
- }
129
- if (!info.isFile()) {
130
- continue;
131
- }
132
- const path2 = relative(projectPath, fullPath);
133
- if (!filter(path2)) {
134
- continue;
135
- }
136
- files.push({
137
- path: path2,
138
- hash: await hashFile(fullPath),
139
- size: info.size
140
- });
141
- }
142
- };
143
- await visit(projectPath);
144
- return files.sort((a, b) => a.path.localeCompare(b.path));
145
- }
146
- function safeHashCompare(a, b) {
147
- const abuf = Buffer.from(a, "hex");
148
- const bbuf = Buffer.from(b, "hex");
149
- return timingSafeEqual(abuf, bbuf);
150
- }
151
- async function bundle(options) {
152
- const { dependencies } = options;
153
- const esbuild = resolveDependency("esbuild", path.dirname(options.entry));
154
- if (esbuild.version) {
155
- console.log(`[bundler] building with esbuild@${esbuild.version}`);
156
- }
157
- return esbuild.build({
158
- keepNames: true,
159
- entryPoints: [options.entry],
160
- bundle: true,
161
- platform: "node",
162
- outfile: options.out,
163
- format: options.format,
164
- minify: false,
165
- sourcemap: false,
166
- external: dependencies,
167
- banner: {
168
- js: `
169
- /**
170
- ${bannerLines(options.banner)}
171
- */
172
- `.trim()
173
- }
174
- });
175
- }
8
+ import { join } from "path";
176
9
 
177
10
  // src/compose.ts
178
11
  function compose(middleware) {
@@ -254,7 +87,7 @@ function wrapper(fn) {
254
87
  async function main(ctx2) {
255
88
  const heartbeat = startHeartbeat();
256
89
  const { entry, cwd } = ctx2;
257
- let entryFile = join2(cwd ?? "", entry);
90
+ let entryFile = join(cwd ?? "", entry);
258
91
  try {
259
92
  if (!await pathExists(entryFile)) {
260
93
  const error = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/process/workers.process.ts","../../src/bundler.ts","../../src/compose.ts"],"sourcesContent":["import {join} from 'path'\nimport {createBundle, resolveDependency} from '../bundler'\nimport {compose, Next} from '../compose'\nimport {WorkerContext, WorkerError, WorkerErrorCode} from '../types'\nimport {pathExists} from '../util/fs'\n\nexport type RunFn<T> = (data: T) => Promise<any>\n\nfunction dispatch(event: 'ALIVE' | 'DONE' | 'ERROR', payload: any) {\n process.send?.({\n type: event,\n ...payload,\n })\n}\n\nfunction startHeartbeat(interval = 50) {\n return setInterval(() => {\n const memory = process.memoryUsage()\n\n dispatch('ALIVE', {\n pid: process.pid,\n uptime: process.uptime(),\n memory: {\n rss: memory.rss,\n heapUsed: memory.heapUsed,\n heapTotal: memory.heapTotal,\n external: memory.external,\n },\n })\n }, interval)\n}\n\nexport function wrapper(fn: RunFn<unknown>) {\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n return async (ctx: WorkerContext, next: Next) => {\n const res = await execute(ctx.data as any, fn)\n\n ctx.result = res.data\n ctx.error = res.error\n\n await next()\n }\n}\n\nasync function main(ctx: WorkerContext) {\n const heartbeat = startHeartbeat()\n\n const {entry, cwd} = ctx\n let entryFile = join(cwd ?? '', entry)\n\n try {\n if (!(await pathExists(entryFile))) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_ENTRY_FILE,\n message: 'entry file not found',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // bundler\n if (ctx.bundler?.enabled) {\n entryFile = await createBundle({\n project: cwd!,\n dist: ctx.dist,\n entry,\n cacheStrategy: ctx.bundler?.cache?.strategy ?? 'never',\n })\n }\n\n let mod = undefined\n try {\n mod = await import(entryFile)\n } catch (error) {}\n\n if (!mod || !mod.default || typeof mod.default !== 'function') {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_DEFAULT_FUNCTION,\n message: 'default must be a function',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // load middleware\n let middleware = []\n if (mod.middleware && typeof mod.middleware === 'function') {\n const start = performance.now()\n middleware = mod.middleware() ?? []\n\n if (!Array.isArray(middleware) || middleware.filter((m) => typeof m !== 'function').length > 0) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_MIDDLEWARE_FUNCTION,\n message: 'middleware not configured correctly',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n const dt = (performance.now() - start).toFixed(2)\n console.log(`[middleware] ${middleware.length} functions registered in ${dt} ms`)\n }\n\n // runtime\n const runtime = compose([...middleware, wrapper(mod.default)])\n\n console.log(`[runtime] started running worker`)\n\n const start = performance.now()\n\n const result = await runtime(ctx)\n\n const ms = performance.now() - start\n console.log(`[runtime] finished running worker took ${ms.toFixed(2)} ms`)\n\n if (result.error) {\n console.warn(`[runtime] finished with errors (error: ${ctx.error?.message ?? 'unknown'})`)\n }\n\n dispatch('DONE', {result})\n } finally {\n clearInterval(heartbeat)\n }\n}\n\nconst ctx = JSON.parse(process.env.XGSD_CTX!) as WorkerContext\nmain(ctx)\n","import {createHash, timingSafeEqual} from 'crypto'\nimport path, {join, relative, sep} from 'path'\nimport {readdir, readFile, stat} from 'fs/promises'\nimport {pathExistsSync, readJsonSync, writeJsonSync} from './util/fs'\nimport {createRequire} from 'module'\n\nexport async function createBundle({\n project,\n dist,\n cwd,\n entry,\n cacheStrategy,\n log,\n}: {\n project: string\n dist?: string\n cwd?: string\n entry: string\n cacheStrategy: 'always' | 'change' | 'never'\n log?: boolean\n}): Promise<string> {\n const start = performance.now()\n\n const xgsd = join(project, dist ?? '.xgsd')\n const out = join(xgsd, 'bundle.js')\n const entryFile = join(project, entry)\n const packageJsonPath = join(project, 'package.json')\n const outPathRel = join(dist ?? '.xgsd', 'bundle.js')\n\n // v0.7 note\n // dont do this as it adds 20-30MB of memory before anything even runs\n // bundling is fine but current AST parsing/traversal is unneeded\n // instead split into two concerns: dependencies (from package.json) and code changes (from hashes)\n // do this instead:\n const hash = await calculateProjectHash(project)\n const outdir = path.dirname(out)\n\n const packageJson = await readJsonSync(packageJsonPath)\n\n const outPackageJsonPath = join(outdir, 'package.json')\n const cacheFilesExist = pathExistsSync(outPackageJsonPath) && pathExistsSync(out)\n\n if (cacheFilesExist && cacheStrategy === 'always') {\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n\n if (cacheFilesExist && cacheStrategy === 'change') {\n const outPackageJson = readJsonSync(outPackageJsonPath)\n\n if (outPackageJson.hash && safeHashCompare(outPackageJson.hash, hash)) {\n // cache hit\n\n console.log(`${outPathRel} loaded from cache (set cache.strategy = \"never\" if this is unintentional)`)\n\n return out\n }\n }\n\n const dependencies = Object.entries(readJsonSync(packageJsonPath).dependencies).map((d) => d[0])\n const generated = new Date().toISOString()\n\n // for now let esbuild notify of errors\n await bundle({\n entry: entryFile,\n out,\n banner: {\n generated,\n hash,\n },\n format: 'esm',\n dependencies,\n })\n\n writeJsonSync(path.join(outdir, 'package.json'), {\n ...packageJson,\n hash,\n generated,\n type: 'module',\n })\n\n const ms = performance.now() - start\n\n console.log(`[bundler] copied package.json to ${join(dist ?? '.xgsd', 'package.json')}`)\n console.log(`[bundler] ${entry} bundled to ${outPathRel}`)\n console.log(`[bundler] completed in ${ms.toFixed(2)}ms.`)\n\n if (cacheStrategy === 'never') {\n console.warn(`[bundler] (warn) you can speed this up with bundler.cache.strategy = always|change.`)\n }\n\n return out\n}\n\nfunction bannerLines(object: Record<string, string>) {\n const lines = []\n lines.push(' * xGSD bundle.js')\n for (const key of Object.keys(object)) {\n lines.push(` * ${key}: ${object[key]}`)\n }\n lines.push(' * WARNING: this file is generated. Do not edit manually.')\n return lines.join('\\r\\n')\n}\n\nexport function resolvePath(moduleName: string, root: string): string {\n return require.resolve(moduleName, {\n paths: [root],\n })\n}\n\nexport function resolveDependency(dependency: string, projectRoot: string): any {\n try {\n const require = createRequire(projectRoot)\n return require(dependency)\n } catch {}\n\n throw new Error(\n `Could not resolve ${dependency}.\\nInstall it with \\`yarn add ${dependency}\\` or re-install @xgsd/cli\\nPath: ${projectRoot}.`,\n )\n}\n\nexport type WalkedFile = {\n path: string\n hash: string\n size: number\n}\n\ntype WalkOptions = {\n ignore?: string[]\n filter?: (path: string) => boolean\n}\n\nexport async function calculateProjectHash(project: string): Promise<string> {\n const hashes = await collectProjectHashes(project, {\n ignore: ['node_modules', '.xgsd', 'dist', '.git'],\n filter: (path) => path.endsWith('.js') || path.endsWith('.ts'),\n })\n\n const normalised = hashes\n .map((h) => h.hash.trim().slice(0, 9))\n .sort()\n .join('|')\n\n return createHash('sha256').update(normalised).digest('hex')\n}\n\nexport async function collectProjectHashes(projectPath: string, options: WalkOptions = {}): Promise<WalkedFile[]> {\n const {ignore = ['node_modules'], filter = () => true} = options\n\n const files: WalkedFile[] = []\n\n const ignored = new Set(ignore)\n\n const shouldIgnore = (target: string) => {\n const parts = relative(projectPath, target).split(sep)\n\n return parts.some((part) => ignored.has(part))\n }\n\n const hashFile = async (filePath: string) => {\n const buffer = await readFile(filePath)\n\n return createHash('sha256').update(buffer).digest('hex')\n }\n\n const visit = async (current: string): Promise<void> => {\n if (shouldIgnore(current)) {\n return\n }\n\n const entries = await readdir(current)\n\n for (const entry of entries) {\n const fullPath = join(current, entry)\n\n if (shouldIgnore(fullPath)) {\n continue\n }\n\n const info = await stat(fullPath)\n\n if (info.isDirectory()) {\n await visit(fullPath)\n continue\n }\n\n if (!info.isFile()) {\n continue\n }\n\n const path = relative(projectPath, fullPath)\n\n if (!filter(path)) {\n continue\n }\n\n files.push({\n path,\n hash: await hashFile(fullPath),\n size: info.size,\n })\n }\n }\n\n await visit(projectPath)\n\n return files.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function safeHashCompare(a: string, b: string): boolean {\n const abuf = Buffer.from(a, 'hex')\n const bbuf = Buffer.from(b, 'hex')\n\n return timingSafeEqual(abuf, bbuf)\n}\n\nexport async function bundle(options: {\n entry: string\n out: string\n format: 'esm' | 'cjs'\n banner: Record<string, string>\n dependencies: string[]\n}) {\n const {dependencies} = options\n\n const esbuild = resolveDependency('esbuild', path.dirname(options.entry))\n\n if (esbuild.version) {\n console.log(`[bundler] building with esbuild@${esbuild.version}`)\n }\n\n return esbuild.build({\n keepNames: true,\n entryPoints: [options.entry],\n bundle: true,\n platform: 'node',\n outfile: options.out,\n format: options.format,\n minify: false,\n sourcemap: false,\n external: dependencies,\n banner: {\n js: `\n/**\n${bannerLines(options.banner)}\n */\n`.trim(),\n },\n })\n}\n","import {resolveDependency} from './bundler'\nimport {WorkerContext, WorkerResult} from './types'\n\nexport type Next = () => Promise<void>\n\nexport type Middleware = (ctx: WorkerContext, next: Next) => Promise<void>\n\nexport type ComposedMiddleware = (ctx: WorkerContext) => Promise<WorkerResult<unknown>>\n\nexport function compose(middleware: Middleware[]): ComposedMiddleware {\n return async function run(ctx: WorkerContext): Promise<WorkerResult<unknown>> {\n let index = -1\n\n let res: any = {\n version: 'v1',\n ok: undefined,\n result: undefined,\n error: undefined,\n duration: undefined,\n }\n\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times')\n }\n\n index = i\n\n const fn = middleware[i]\n\n if (!fn) {\n return\n }\n\n const executeWrapper = async (ctx: WorkerContext) => {\n await fn(ctx, async () => {\n await dispatch(i + 1)\n })\n\n return ctx\n }\n\n const result = await execute(ctx, executeWrapper)\n\n if (result.error || result.data?.error) {\n res.ok = false\n res.code = ctx.code\n res.result = null\n res.error = result.error ?? result.data?.error\n }\n\n if (result.data && result.data.result) {\n res.ok = true\n res.code = ctx.code\n res.result = result.data.result\n res.error = result.error ?? result.data?.error\n }\n }\n\n await dispatch(0)\n\n return res\n }\n}\n"],"mappings":"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","names":["join","require","path","ctx","dispatch","ctx","join","start"]}
1
+ {"version":3,"sources":["../../src/process/workers.process.ts","../../src/compose.ts"],"sourcesContent":["import {join} from 'path'\nimport {createBundle, resolveDependency} from '../bundler'\nimport {compose, Next} from '../compose'\nimport {WorkerContext, WorkerError, WorkerErrorCode} from '../types'\nimport {pathExists} from '../util/fs'\n\nexport type RunFn<T> = (data: T) => Promise<any>\n\nfunction dispatch(event: 'ALIVE' | 'DONE' | 'ERROR', payload: any) {\n process.send?.({\n type: event,\n ...payload,\n })\n}\n\nfunction startHeartbeat(interval = 50) {\n return setInterval(() => {\n const memory = process.memoryUsage()\n\n dispatch('ALIVE', {\n pid: process.pid,\n uptime: process.uptime(),\n memory: {\n rss: memory.rss,\n heapUsed: memory.heapUsed,\n heapTotal: memory.heapTotal,\n external: memory.external,\n },\n })\n }, interval)\n}\n\nexport function wrapper(fn: RunFn<unknown>) {\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n return async (ctx: WorkerContext, next: Next) => {\n const res = await execute(ctx.data as any, fn)\n\n ctx.result = res.data\n ctx.error = res.error\n\n await next()\n }\n}\n\nasync function main(ctx: WorkerContext) {\n const heartbeat = startHeartbeat()\n\n const {entry, cwd} = ctx\n let entryFile = join(cwd ?? '', entry)\n\n try {\n if (!(await pathExists(entryFile))) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_ENTRY_FILE,\n message: 'entry file not found',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // bundler\n if (ctx.bundler?.enabled) {\n entryFile = await createBundle({\n project: cwd!,\n dist: ctx.dist,\n entry,\n cacheStrategy: ctx.bundler?.cache?.strategy ?? 'never',\n })\n }\n\n let mod = undefined\n try {\n mod = await import(entryFile)\n } catch (error) {}\n\n if (!mod || !mod.default || typeof mod.default !== 'function') {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_DEFAULT_FUNCTION,\n message: 'default must be a function',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n // load middleware\n let middleware = []\n if (mod.middleware && typeof mod.middleware === 'function') {\n const start = performance.now()\n middleware = mod.middleware() ?? []\n\n if (!Array.isArray(middleware) || middleware.filter((m) => typeof m !== 'function').length > 0) {\n const error: WorkerError = {\n code: WorkerErrorCode.CODE_INVALID_MIDDLEWARE_FUNCTION,\n message: 'middleware not configured correctly',\n type: 'user',\n }\n\n dispatch('ERROR', {error})\n return\n }\n\n const dt = (performance.now() - start).toFixed(2)\n console.log(`[middleware] ${middleware.length} functions registered in ${dt} ms`)\n }\n\n // runtime\n const runtime = compose([...middleware, wrapper(mod.default)])\n\n console.log(`[runtime] started running worker`)\n\n const start = performance.now()\n\n const result = await runtime(ctx)\n\n const ms = performance.now() - start\n console.log(`[runtime] finished running worker took ${ms.toFixed(2)} ms`)\n\n if (result.error) {\n console.warn(`[runtime] finished with errors (error: ${ctx.error?.message ?? 'unknown'})`)\n }\n\n dispatch('DONE', {result})\n } finally {\n clearInterval(heartbeat)\n }\n}\n\nconst ctx = JSON.parse(process.env.XGSD_CTX!) as WorkerContext\nmain(ctx)\n","import {resolveDependency} from './bundler'\nimport {WorkerContext, WorkerResult} from './types'\n\nexport type Next = () => Promise<void>\n\nexport type Middleware = (ctx: WorkerContext, next: Next) => Promise<void>\n\nexport type ComposedMiddleware = (ctx: WorkerContext) => Promise<WorkerResult<unknown>>\n\nexport function compose(middleware: Middleware[]): ComposedMiddleware {\n return async function run(ctx: WorkerContext): Promise<WorkerResult<unknown>> {\n let index = -1\n\n let res: any = {\n version: 'v1',\n ok: undefined,\n result: undefined,\n error: undefined,\n duration: undefined,\n }\n\n const {execute} = resolveDependency('@xgsd/engine', ctx.cwd!)\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times')\n }\n\n index = i\n\n const fn = middleware[i]\n\n if (!fn) {\n return\n }\n\n const executeWrapper = async (ctx: WorkerContext) => {\n await fn(ctx, async () => {\n await dispatch(i + 1)\n })\n\n return ctx\n }\n\n const result = await execute(ctx, executeWrapper)\n\n if (result.error || result.data?.error) {\n res.ok = false\n res.code = ctx.code\n res.result = null\n res.error = result.error ?? result.data?.error\n }\n\n if (result.data && result.data.result) {\n res.ok = true\n res.code = ctx.code\n res.result = result.data.result\n res.error = result.error ?? result.data?.error\n }\n }\n\n await dispatch(0)\n\n return res\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAQ,YAAW;;;ACSZ,SAAS,QAAQ,YAA8C;AACpE,SAAO,eAAe,IAAIA,MAAoD;AAC5E,QAAI,QAAQ;AAEZ,QAAI,MAAW;AAAA,MACb,SAAS;AAAA,MACT,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,UAAU;AAAA,IACZ;AAEA,UAAM,EAAC,QAAO,IAAI,kBAAkB,gBAAgBA,KAAI,GAAI;AAE5D,mBAAeC,UAAS,GAA0B;AAChD,UAAI,KAAK,OAAO;AACd,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAEA,cAAQ;AAER,YAAM,KAAK,WAAW,CAAC;AAEvB,UAAI,CAAC,IAAI;AACP;AAAA,MACF;AAEA,YAAM,iBAAiB,OAAOD,SAAuB;AACnD,cAAM,GAAGA,MAAK,YAAY;AACxB,gBAAMC,UAAS,IAAI,CAAC;AAAA,QACtB,CAAC;AAED,eAAOD;AAAA,MACT;AAEA,YAAM,SAAS,MAAM,QAAQA,MAAK,cAAc;AAEhD,UAAI,OAAO,SAAS,OAAO,MAAM,OAAO;AACtC,YAAI,KAAK;AACT,YAAI,OAAOA,KAAI;AACf,YAAI,SAAS;AACb,YAAI,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAA,MAC3C;AAEA,UAAI,OAAO,QAAQ,OAAO,KAAK,QAAQ;AACrC,YAAI,KAAK;AACT,YAAI,OAAOA,KAAI;AACf,YAAI,SAAS,OAAO,KAAK;AACzB,YAAI,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAA,MAC3C;AAAA,IACF;AAEA,UAAMC,UAAS,CAAC;AAEhB,WAAO;AAAA,EACT;AACF;;;ADzDA,SAAS,SAAS,OAAmC,SAAc;AACjE,UAAQ,OAAO;AAAA,IACb,MAAM;AAAA,IACN,GAAG;AAAA,EACL,CAAC;AACH;AAEA,SAAS,eAAe,WAAW,IAAI;AACrC,SAAO,YAAY,MAAM;AACvB,UAAM,SAAS,QAAQ,YAAY;AAEnC,aAAS,SAAS;AAAA,MAChB,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ,OAAO;AAAA,MACvB,QAAQ;AAAA,QACN,KAAK,OAAO;AAAA,QACZ,UAAU,OAAO;AAAA,QACjB,WAAW,OAAO;AAAA,QAClB,UAAU,OAAO;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,QAAQ;AACb;AAEO,SAAS,QAAQ,IAAoB;AAC1C,QAAM,EAAC,QAAO,IAAI,kBAAkB,gBAAgB,IAAI,GAAI;AAE5D,SAAO,OAAOC,MAAoB,SAAe;AAC/C,UAAM,MAAM,MAAM,QAAQA,KAAI,MAAa,EAAE;AAE7C,IAAAA,KAAI,SAAS,IAAI;AACjB,IAAAA,KAAI,QAAQ,IAAI;AAEhB,UAAM,KAAK;AAAA,EACb;AACF;AAEA,eAAe,KAAKA,MAAoB;AACtC,QAAM,YAAY,eAAe;AAEjC,QAAM,EAAC,OAAO,IAAG,IAAIA;AACrB,MAAI,YAAY,KAAK,OAAO,IAAI,KAAK;AAErC,MAAI;AACF,QAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,YAAM,QAAqB;AAAA,QACzB;AAAA,QACA,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAEA,eAAS,SAAS,EAAC,MAAK,CAAC;AACzB;AAAA,IACF;AAGA,QAAIA,KAAI,SAAS,SAAS;AACxB,kBAAY,MAAM,aAAa;AAAA,QAC7B,SAAS;AAAA,QACT,MAAMA,KAAI;AAAA,QACV;AAAA,QACA,eAAeA,KAAI,SAAS,OAAO,YAAY;AAAA,MACjD,CAAC;AAAA,IACH;AAEA,QAAI,MAAM;AACV,QAAI;AACF,YAAM,MAAM,OAAO;AAAA,IACrB,SAAS,OAAO;AAAA,IAAC;AAEjB,QAAI,CAAC,OAAO,CAAC,IAAI,WAAW,OAAO,IAAI,YAAY,YAAY;AAC7D,YAAM,QAAqB;AAAA,QACzB;AAAA,QACA,SAAS;AAAA,QACT,MAAM;AAAA,MACR;AAEA,eAAS,SAAS,EAAC,MAAK,CAAC;AACzB;AAAA,IACF;AAGA,QAAI,aAAa,CAAC;AAClB,QAAI,IAAI,cAAc,OAAO,IAAI,eAAe,YAAY;AAC1D,YAAMC,SAAQ,YAAY,IAAI;AAC9B,mBAAa,IAAI,WAAW,KAAK,CAAC;AAElC,UAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,OAAO,CAAC,MAAM,OAAO,MAAM,UAAU,EAAE,SAAS,GAAG;AAC9F,cAAM,QAAqB;AAAA,UACzB;AAAA,UACA,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAEA,iBAAS,SAAS,EAAC,MAAK,CAAC;AACzB;AAAA,MACF;AAEA,YAAM,MAAM,YAAY,IAAI,IAAIA,QAAO,QAAQ,CAAC;AAChD,cAAQ,IAAI,gBAAgB,WAAW,MAAM,4BAA4B,EAAE,KAAK;AAAA,IAClF;AAGA,UAAM,UAAU,QAAQ,CAAC,GAAG,YAAY,QAAQ,IAAI,OAAO,CAAC,CAAC;AAE7D,YAAQ,IAAI,kCAAkC;AAE9C,UAAM,QAAQ,YAAY,IAAI;AAE9B,UAAM,SAAS,MAAM,QAAQD,IAAG;AAEhC,UAAM,KAAK,YAAY,IAAI,IAAI;AAC/B,YAAQ,IAAI,0CAA0C,GAAG,QAAQ,CAAC,CAAC,KAAK;AAExE,QAAI,OAAO,OAAO;AAChB,cAAQ,KAAK,0CAA0CA,KAAI,OAAO,WAAW,SAAS,GAAG;AAAA,IAC3F;AAEA,aAAS,QAAQ,EAAC,OAAM,CAAC;AAAA,EAC3B,UAAE;AACA,kBAAc,SAAS;AAAA,EACzB;AACF;AAEA,IAAM,MAAM,KAAK,MAAM,QAAQ,IAAI,QAAS;AAC5C,KAAK,GAAG;","names":["ctx","dispatch","ctx","start"]}
@@ -54,4 +54,4 @@ type WorkerContext<T = unknown> = WorkerConfig & {
54
54
  pid?: number;
55
55
  };
56
56
 
57
- export type { WorkerResult as W, WorkerConfig as a, WorkerContext as b };
57
+ export { type WorkerContext as W, type WorkerResult as a, type WorkerConfig as b, type WorkerError as c, WorkerErrorCode as d, type WorkerErrorType as e };
@@ -54,4 +54,4 @@ type WorkerContext<T = unknown> = WorkerConfig & {
54
54
  pid?: number;
55
55
  };
56
56
 
57
- export type { WorkerResult as W, WorkerConfig as a, WorkerContext as b };
57
+ export { type WorkerContext as W, type WorkerResult as a, type WorkerConfig as b, type WorkerError as c, WorkerErrorCode as d, type WorkerErrorType as e };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xgsd/workers",
3
3
  "description": "Super lightweight alternative to standard xGSD runtime. Optimised for queues/serverless vs project orchestration.",
4
- "version": "0.1.0-beta.0",
4
+ "version": "0.1.0-beta.2",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -38,8 +38,8 @@
38
38
  "typescript": "^5.x"
39
39
  },
40
40
  "peerDependencies": {
41
- "esbuild": "^0.28.0",
42
- "@xgsd/engine": "^1.0.0-stable"
41
+ "@xgsd/engine": "^1.0.0-stable",
42
+ "esbuild": "^0.28.0"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "esbuild": {
@@ -1,45 +0,0 @@
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
@@ -1 +0,0 @@
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":[]}