@shotkit/shotium 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -39
- package/dist/daemon_main.js +25 -42
- package/dist/daemon_main.js.map +1 -1
- package/dist/engine-Xe7nH-1i.js +267 -0
- package/dist/engine-Xe7nH-1i.js.map +1 -0
- package/dist/index.d.ts +181 -48
- package/dist/index.js +60 -56
- package/dist/index.js.map +1 -1
- package/package.json +7 -11
- package/src/index.ts +59 -81
- package/src/lib/binding.ts +89 -0
- package/src/lib/client.ts +8 -12
- package/src/lib/config.ts +11 -66
- package/src/lib/daemon.ts +70 -58
- package/src/lib/endpoint.ts +19 -12
- package/src/lib/engine.ts +168 -0
- package/src/lib/platform.ts +1 -7
- package/src/lib/request.ts +4 -15
- package/src/types.ts +19 -45
- package/dist/native.d.ts +0 -66
- package/dist/native.js +0 -127
- package/dist/native.js.map +0 -1
- package/dist/platform-DU8DYqmA.js +0 -32
- package/dist/platform-DU8DYqmA.js.map +0 -1
- package/dist/pool-BSgS6vkr.js +0 -356
- package/dist/pool-BSgS6vkr.js.map +0 -1
- package/dist/request-qZXS3N9f.js +0 -43
- package/dist/request-qZXS3N9f.js.map +0 -1
- package/dist/types-x9HtkzeE.d.ts +0 -156
- package/src/lib/pool.ts +0 -243
- package/src/lib/worker.ts +0 -220
- package/src/native.ts +0 -234
package/dist/native.d.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { i as NativeStartOptions, o as PurgeOptions, s as ScreenshotOptions } from "./types-x9HtkzeE.js";
|
|
2
|
-
//#region src/native.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* The engine, in this process, and the queue in front of it.
|
|
5
|
-
*
|
|
6
|
-
* Same options and same output as `runtime`, and a different set of trades.
|
|
7
|
-
* There is no worker process, so there is nothing to start, nothing to find on
|
|
8
|
-
* disk and no pipe: a screenshot costs about a third less than through the
|
|
9
|
-
* pool, and the whole thing is one process instead of five.
|
|
10
|
-
*
|
|
11
|
-
* What it gives up is what a separate process was providing for free. One
|
|
12
|
-
* renderer, because blink is a process-wide singleton and `worker_threads`
|
|
13
|
-
* share the process, so requests are serialised however many callers there
|
|
14
|
-
* are. And no crash isolation: a renderer that dies takes the host program
|
|
15
|
-
* with it, where the pool would have retried.
|
|
16
|
-
*
|
|
17
|
-
* The queue is not about fairness. Each capture occupies a libuv thread pool
|
|
18
|
-
* thread for as long as the render takes, and there are four of those by
|
|
19
|
-
* default, shared with fs and dns -- so letting four screenshots go at once
|
|
20
|
-
* would stall the host's file reads for a fifth of a second at a time while
|
|
21
|
-
* gaining nothing, since the engine serialises them anyway.
|
|
22
|
-
*/
|
|
23
|
-
declare class NativeRuntime {
|
|
24
|
-
private engine;
|
|
25
|
-
private tail;
|
|
26
|
-
get running(): boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Starts the engine. Safe to call twice; the second call is a no-op.
|
|
29
|
-
*
|
|
30
|
-
* `cacheDir` is the HTTP disk cache and `null` disables it, which is the
|
|
31
|
-
* default here. `resourceDir` is where `shotium_data.pak` and
|
|
32
|
-
* `shotium_strings.pak` are, and defaults to the directory the addon was
|
|
33
|
-
* loaded from, which is where they ship.
|
|
34
|
-
*/
|
|
35
|
-
start(options?: NativeStartOptions): this;
|
|
36
|
-
/** Stops the engine, after whatever is queued. */
|
|
37
|
-
stop(): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Hands back what the engine is holding but can rebuild.
|
|
40
|
-
* `releaseWorkingSet` additionally asks the OS for the pages, which the next
|
|
41
|
-
* screenshot pays back in soft faults -- worth it when there may not be a
|
|
42
|
-
* next one soon.
|
|
43
|
-
*
|
|
44
|
-
* The resident worker does this for itself on a timer because it can watch
|
|
45
|
-
* its own request stream go quiet. Here the queue belongs to the caller, so
|
|
46
|
-
* the caller is the one who knows a batch has ended.
|
|
47
|
-
*/
|
|
48
|
-
purge({ releaseWorkingSet }?: PurgeOptions): void;
|
|
49
|
-
/**
|
|
50
|
-
* Renders one screenshot. Resolves to the encoded image, or to `null` when
|
|
51
|
-
* `path` was given and the engine wrote the file itself.
|
|
52
|
-
*/
|
|
53
|
-
screenshot(options: ScreenshotOptions): Promise<Buffer | null>;
|
|
54
|
-
}
|
|
55
|
-
/** The shared in-process engine, started on first use. */
|
|
56
|
-
declare const native: NativeRuntime;
|
|
57
|
-
/** One screenshot through the shared in-process engine. */
|
|
58
|
-
declare const screenshot: (options: ScreenshotOptions) => Promise<Buffer | null>;
|
|
59
|
-
declare const _default: {
|
|
60
|
-
NativeRuntime: typeof NativeRuntime;
|
|
61
|
-
native: NativeRuntime;
|
|
62
|
-
screenshot: (options: ScreenshotOptions) => Promise<Buffer | null>;
|
|
63
|
-
};
|
|
64
|
-
//#endregion
|
|
65
|
-
export { NativeRuntime, type NativeStartOptions, type PurgeOptions, type ScreenshotOptions, _default as default, native, screenshot };
|
|
66
|
-
//# sourceMappingURL=native.d.ts.map
|
package/dist/native.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { n as packageDir, r as packageName } from "./platform-DU8DYqmA.js";
|
|
2
|
-
import { r as toRequest } from "./request-qZXS3N9f.js";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
|
|
8
|
-
//#region src/native.ts
|
|
9
|
-
const require = createRequire(import.meta.url);
|
|
10
|
-
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
function candidates() {
|
|
12
|
-
const found = [];
|
|
13
|
-
const dir = packageDir();
|
|
14
|
-
if (dir) found.push(path.join(dir, "shotium.node"));
|
|
15
|
-
found.push(path.join(HERE, "..", "native", "build", "Release", "shotium.node"));
|
|
16
|
-
return found;
|
|
17
|
-
}
|
|
18
|
-
let binding = null;
|
|
19
|
-
let bindingDir = null;
|
|
20
|
-
function load() {
|
|
21
|
-
if (binding) return binding;
|
|
22
|
-
const tried = candidates();
|
|
23
|
-
for (const candidate of tried) {
|
|
24
|
-
if (!fs.existsSync(candidate)) continue;
|
|
25
|
-
binding = require(candidate);
|
|
26
|
-
bindingDir = path.dirname(candidate);
|
|
27
|
-
return binding;
|
|
28
|
-
}
|
|
29
|
-
const expected = packageName();
|
|
30
|
-
throw new Error(`shotium: no native engine for this platform.
|
|
31
|
-
looked in:\n ${tried.join("\n ")}\n` + (expected ? ` It ships in ${expected}, which npm installs as an optional dependency of this package.
|
|
32
|
-
` : ` There is no build for ${process.platform}-${process.arch}.\n`) + " import(\"@shotkit/shotium\") uses worker processes instead and needs no addon.");
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The engine, in this process, and the queue in front of it.
|
|
36
|
-
*
|
|
37
|
-
* Same options and same output as `runtime`, and a different set of trades.
|
|
38
|
-
* There is no worker process, so there is nothing to start, nothing to find on
|
|
39
|
-
* disk and no pipe: a screenshot costs about a third less than through the
|
|
40
|
-
* pool, and the whole thing is one process instead of five.
|
|
41
|
-
*
|
|
42
|
-
* What it gives up is what a separate process was providing for free. One
|
|
43
|
-
* renderer, because blink is a process-wide singleton and `worker_threads`
|
|
44
|
-
* share the process, so requests are serialised however many callers there
|
|
45
|
-
* are. And no crash isolation: a renderer that dies takes the host program
|
|
46
|
-
* with it, where the pool would have retried.
|
|
47
|
-
*
|
|
48
|
-
* The queue is not about fairness. Each capture occupies a libuv thread pool
|
|
49
|
-
* thread for as long as the render takes, and there are four of those by
|
|
50
|
-
* default, shared with fs and dns -- so letting four screenshots go at once
|
|
51
|
-
* would stall the host's file reads for a fifth of a second at a time while
|
|
52
|
-
* gaining nothing, since the engine serialises them anyway.
|
|
53
|
-
*/
|
|
54
|
-
var NativeRuntime = class {
|
|
55
|
-
engine = null;
|
|
56
|
-
tail = Promise.resolve();
|
|
57
|
-
get running() {
|
|
58
|
-
return this.engine !== null;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Starts the engine. Safe to call twice; the second call is a no-op.
|
|
62
|
-
*
|
|
63
|
-
* `cacheDir` is the HTTP disk cache and `null` disables it, which is the
|
|
64
|
-
* default here. `resourceDir` is where `shotium_data.pak` and
|
|
65
|
-
* `shotium_strings.pak` are, and defaults to the directory the addon was
|
|
66
|
-
* loaded from, which is where they ship.
|
|
67
|
-
*/
|
|
68
|
-
start(options = {}) {
|
|
69
|
-
if (this.engine) return this;
|
|
70
|
-
const native = load();
|
|
71
|
-
const engineOptions = {};
|
|
72
|
-
if (options.cacheDir !== null && options.cacheDir !== void 0) engineOptions.cacheDir = options.cacheDir;
|
|
73
|
-
if (options.userAgent !== void 0) engineOptions.userAgent = options.userAgent;
|
|
74
|
-
engineOptions.resourceDir = options.resourceDir || bindingDir;
|
|
75
|
-
this.engine = native.create(JSON.stringify(engineOptions));
|
|
76
|
-
return this;
|
|
77
|
-
}
|
|
78
|
-
/** Stops the engine, after whatever is queued. */
|
|
79
|
-
async stop() {
|
|
80
|
-
if (!this.engine) return;
|
|
81
|
-
const engine = this.engine;
|
|
82
|
-
this.engine = null;
|
|
83
|
-
await this.tail.catch(() => {});
|
|
84
|
-
load().destroy(engine);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Hands back what the engine is holding but can rebuild.
|
|
88
|
-
* `releaseWorkingSet` additionally asks the OS for the pages, which the next
|
|
89
|
-
* screenshot pays back in soft faults -- worth it when there may not be a
|
|
90
|
-
* next one soon.
|
|
91
|
-
*
|
|
92
|
-
* The resident worker does this for itself on a timer because it can watch
|
|
93
|
-
* its own request stream go quiet. Here the queue belongs to the caller, so
|
|
94
|
-
* the caller is the one who knows a batch has ended.
|
|
95
|
-
*/
|
|
96
|
-
purge({ releaseWorkingSet = false } = {}) {
|
|
97
|
-
if (!this.engine) return;
|
|
98
|
-
load().purge(this.engine, releaseWorkingSet);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Renders one screenshot. Resolves to the encoded image, or to `null` when
|
|
102
|
-
* `path` was given and the engine wrote the file itself.
|
|
103
|
-
*/
|
|
104
|
-
async screenshot(options) {
|
|
105
|
-
const request = toRequest(options);
|
|
106
|
-
if (!this.engine) this.start();
|
|
107
|
-
const engine = this.engine;
|
|
108
|
-
const native = load();
|
|
109
|
-
const result = this.tail.catch(() => {}).then(() => native.capture(engine, JSON.stringify(request)));
|
|
110
|
-
this.tail = result.catch(() => {});
|
|
111
|
-
const image = await result;
|
|
112
|
-
return request.path ? null : image;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
/** The shared in-process engine, started on first use. */
|
|
116
|
-
const native = new NativeRuntime();
|
|
117
|
-
/** One screenshot through the shared in-process engine. */
|
|
118
|
-
const screenshot = (options) => native.screenshot(options);
|
|
119
|
-
var native_default = {
|
|
120
|
-
NativeRuntime,
|
|
121
|
-
native,
|
|
122
|
-
screenshot
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
//#endregion
|
|
126
|
-
export { NativeRuntime, native_default as default, native, screenshot };
|
|
127
|
-
//# sourceMappingURL=native.js.map
|
package/dist/native.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"native.js","names":["platformPackage.packageDir","platformPackage.packageName"],"sources":["../src/native.ts"],"sourcesContent":["import fs from 'node:fs';\nimport {createRequire} from 'node:module';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nimport * as platformPackage from './lib/platform.js';\nimport {toRequest} from './lib/request.js';\nimport type {\n NativeStartOptions,\n PurgeOptions,\n ScreenshotOptions,\n} from './types.js';\n\nexport type {\n NativeStartOptions,\n PurgeOptions,\n ScreenshotOptions,\n} from './types.js';\n\n// A .node addon is a CommonJS artefact: there is no ESM loader for one.\nconst require = createRequire(import.meta.url);\n\n// ESM has no __dirname. This is the same thing, from the module's own URL.\nconst HERE = path.dirname(fileURLToPath(import.meta.url));\n\n// The engine handle the addon hands back. It is opaque on purpose: everything\n// that can be done with it is a call on the binding below.\ntype Engine = unknown;\n\n// What native/binding.cc exports. See shot/shot_api.h for the C ABI under it.\ninterface NativeBinding {\n create(optionsJson: string): Engine;\n destroy(engine: Engine): void;\n purge(engine: Engine, releaseWorkingSet: boolean): void;\n capture(engine: Engine, requestJson: string): Promise<Buffer>;\n}\n\n// shot in this process, instead of in workers beside it.\n//\n// The difference from `runtime` is not the API, which is the same\n// screenshot(options), and not the request format, which is byte for byte the\n// same JSON. It is where blink is:\n//\n// runtime N worker processes, one screenshot each at a time, a crash is a\n// retry, memory is N copies of an engine\n// native one engine in this process, one screenshot at a time ever, a\n// crash takes the program with it, memory is one copy\n//\n// One at a time is not a limitation of this file. Blink is a process-wide\n// singleton -- it is initialised once and there is no path to a second one --\n// so an in-process engine is one renderer no matter how it is driven, and\n// worker_threads do not change that because they share the process. A caller\n// who wants four screenshots at once wants four processes, which is what the\n// pool is for.\n//\n// What it buys is that there is no process to start, nothing to find on disk,\n// no pipe, and no supervisor: a program that takes a handful of screenshots\n// and exits pays for one engine and talks to it directly.\n\n// Where the addon and the library beside it live.\n//\n// The platform package is what ships -- the .node sits next to the shared\n// library it is linked against, which is the whole reason the two travel in\n// one package rather than two. native/build/Release is where node-gyp puts a\n// local build; it exists in a checkout and not in an install, so the two never\n// compete in practice. Both paths are relative to this file's build output,\n// which is one directory below the package root.\nfunction candidates(): string[] {\n const found: string[] = [];\n const dir = platformPackage.packageDir();\n if (dir) {\n found.push(path.join(dir, 'shotium.node'));\n }\n found.push(\n path.join(HERE, '..', 'native', 'build', 'Release', 'shotium.node'));\n return found;\n}\n\nlet binding: NativeBinding|null = null;\nlet bindingDir: string|null = null;\n\nfunction load(): NativeBinding {\n if (binding) {\n return binding;\n }\n const tried = candidates();\n for (const candidate of tried) {\n if (!fs.existsSync(candidate)) {\n continue;\n }\n // Not wrapped in a try: a .node that is there and will not load is a\n // broken installation, and the loader's own message -- a missing\n // dependency, an architecture mismatch -- says more than anything that\n // could be substituted for it.\n binding = require(candidate) as NativeBinding;\n bindingDir = path.dirname(candidate);\n return binding;\n }\n const expected = platformPackage.packageName();\n throw new Error(\n 'shotium: no native engine for this platform.\\n' +\n ` looked in:\\n ${tried.join('\\n ')}\\n` +\n (expected ?\n ` It ships in ${expected}, which npm installs as an optional ` +\n 'dependency of this package.\\n' :\n ` There is no build for ${process.platform}-${process.arch}.\\n`) +\n ' import(\"@shotkit/shotium\") uses worker processes instead and needs ' +\n 'no addon.');\n}\n\n/**\n * The engine, in this process, and the queue in front of it.\n *\n * Same options and same output as `runtime`, and a different set of trades.\n * There is no worker process, so there is nothing to start, nothing to find on\n * disk and no pipe: a screenshot costs about a third less than through the\n * pool, and the whole thing is one process instead of five.\n *\n * What it gives up is what a separate process was providing for free. One\n * renderer, because blink is a process-wide singleton and `worker_threads`\n * share the process, so requests are serialised however many callers there\n * are. And no crash isolation: a renderer that dies takes the host program\n * with it, where the pool would have retried.\n *\n * The queue is not about fairness. Each capture occupies a libuv thread pool\n * thread for as long as the render takes, and there are four of those by\n * default, shared with fs and dns -- so letting four screenshots go at once\n * would stall the host's file reads for a fifth of a second at a time while\n * gaining nothing, since the engine serialises them anyway.\n */\nexport class NativeRuntime {\n private engine: Engine|null = null;\n private tail: Promise<unknown> = Promise.resolve();\n\n get running(): boolean {\n return this.engine !== null;\n }\n\n /**\n * Starts the engine. Safe to call twice; the second call is a no-op.\n *\n * `cacheDir` is the HTTP disk cache and `null` disables it, which is the\n * default here. `resourceDir` is where `shotium_data.pak` and\n * `shotium_strings.pak` are, and defaults to the directory the addon was\n * loaded from, which is where they ship.\n */\n start(options: NativeStartOptions = {}): this {\n if (this.engine) {\n return this;\n }\n const native = load();\n\n const engineOptions: Record<string, unknown> = {};\n if (options.cacheDir !== null && options.cacheDir !== undefined) {\n engineOptions.cacheDir = options.cacheDir;\n }\n if (options.userAgent !== undefined) {\n engineOptions.userAgent = options.userAgent;\n }\n // The packs sit beside the library, and the library cannot find itself on\n // Linux -- the path the engine resolves for \"this module\" goes through\n // /proc/self/exe, which names node. Saying it here is cheaper than\n // teaching the engine a second way to look. See shot_api.h.\n engineOptions.resourceDir = options.resourceDir || bindingDir;\n\n this.engine = native.create(JSON.stringify(engineOptions));\n return this;\n }\n\n /** Stops the engine, after whatever is queued. */\n async stop(): Promise<void> {\n if (!this.engine) {\n return;\n }\n // After the queue, not before: destroy() waits for a capture in flight\n // anyway, and doing it in order means a caller's last screenshot resolves\n // rather than racing the shutdown.\n const engine = this.engine;\n this.engine = null;\n await this.tail.catch(() => {});\n load().destroy(engine);\n }\n\n /**\n * Hands back what the engine is holding but can rebuild.\n * `releaseWorkingSet` additionally asks the OS for the pages, which the next\n * screenshot pays back in soft faults -- worth it when there may not be a\n * next one soon.\n *\n * The resident worker does this for itself on a timer because it can watch\n * its own request stream go quiet. Here the queue belongs to the caller, so\n * the caller is the one who knows a batch has ended.\n */\n purge({releaseWorkingSet = false}: PurgeOptions = {}): void {\n if (!this.engine) {\n return;\n }\n load().purge(this.engine, releaseWorkingSet);\n }\n\n /**\n * Renders one screenshot. Resolves to the encoded image, or to `null` when\n * `path` was given and the engine wrote the file itself.\n */\n async screenshot(options: ScreenshotOptions): Promise<Buffer|null> {\n // Before anything else, and before the queue: a malformed request should\n // be a rejection now rather than one that waits its turn.\n const request = toRequest(options);\n if (!this.engine) {\n this.start();\n }\n const engine = this.engine;\n const native = load();\n\n // Chain onto the tail so that captures run one at a time. The catch keeps\n // one failure from poisoning everything queued behind it.\n const result = this.tail.catch(() => {}).then(\n () => native.capture(engine, JSON.stringify(request)));\n this.tail = result.catch(() => {});\n const image = await result;\n return request.path ? null : image;\n }\n}\n\n/** The shared in-process engine, started on first use. */\nconst native = new NativeRuntime();\n\n/** One screenshot through the shared in-process engine. */\nconst screenshot = (options: ScreenshotOptions): Promise<Buffer|null> =>\n native.screenshot(options);\n\nexport {native, screenshot};\n\nexport default {NativeRuntime, native, screenshot};\n"],"mappings":";;;;;;;;AAoBA,MAAM,UAAU,cAAc,YAAY,GAAG;AAG7C,MAAM,OAAO,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AA4CxD,SAAS,aAAuB;CAC9B,MAAM,QAAkB,CAAC;CACzB,MAAM,MAAMA,WAA2B;CACvC,IAAI,KACF,MAAM,KAAK,KAAK,KAAK,KAAK,cAAc,CAAC;CAE3C,MAAM,KACF,KAAK,KAAK,MAAM,MAAM,UAAU,SAAS,WAAW,cAAc,CAAC;CACvE,OAAO;AACT;AAEA,IAAI,UAA8B;AAClC,IAAI,aAA0B;AAE9B,SAAS,OAAsB;CAC7B,IAAI,SACF,OAAO;CAET,MAAM,QAAQ,WAAW;CACzB,KAAK,MAAM,aAAa,OAAO;EAC7B,IAAI,CAAC,GAAG,WAAW,SAAS,GAC1B;EAMF,UAAU,QAAQ,SAAS;EAC3B,aAAa,KAAK,QAAQ,SAAS;EACnC,OAAO;CACT;CACA,MAAM,WAAWC,YAA4B;CAC7C,MAAM,IAAI,MACN;oBACqB,MAAM,KAAK,QAAQ,EAAE,OACzC,WACI,iBAAiB,SAAS;IAE1B,2BAA2B,QAAQ,SAAS,GAAG,QAAQ,KAAK,QACjE,kFACW;AACjB;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,SAAsB;CAC9B,AAAQ,OAAyB,QAAQ,QAAQ;CAEjD,IAAI,UAAmB;EACrB,OAAO,KAAK,WAAW;CACzB;;;;;;;;;CAUA,MAAM,UAA8B,CAAC,GAAS;EAC5C,IAAI,KAAK,QACP,OAAO;EAET,MAAM,SAAS,KAAK;EAEpB,MAAM,gBAAyC,CAAC;EAChD,IAAI,QAAQ,aAAa,QAAQ,QAAQ,aAAa,QACpD,cAAc,WAAW,QAAQ;EAEnC,IAAI,QAAQ,cAAc,QACxB,cAAc,YAAY,QAAQ;EAMpC,cAAc,cAAc,QAAQ,eAAe;EAEnD,KAAK,SAAS,OAAO,OAAO,KAAK,UAAU,aAAa,CAAC;EACzD,OAAO;CACT;;CAGA,MAAM,OAAsB;EAC1B,IAAI,CAAC,KAAK,QACR;EAKF,MAAM,SAAS,KAAK;EACpB,KAAK,SAAS;EACd,MAAM,KAAK,KAAK,YAAY,CAAC,CAAC;EAC9B,KAAK,CAAC,CAAC,QAAQ,MAAM;CACvB;;;;;;;;;;;CAYA,MAAM,EAAC,oBAAoB,UAAuB,CAAC,GAAS;EAC1D,IAAI,CAAC,KAAK,QACR;EAEF,KAAK,CAAC,CAAC,MAAM,KAAK,QAAQ,iBAAiB;CAC7C;;;;;CAMA,MAAM,WAAW,SAAkD;EAGjE,MAAM,UAAU,UAAU,OAAO;EACjC,IAAI,CAAC,KAAK,QACR,KAAK,MAAM;EAEb,MAAM,SAAS,KAAK;EACpB,MAAM,SAAS,KAAK;EAIpB,MAAM,SAAS,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,WAC/B,OAAO,QAAQ,QAAQ,KAAK,UAAU,OAAO,CAAC,CAAC;EACzD,KAAK,OAAO,OAAO,YAAY,CAAC,CAAC;EACjC,MAAM,QAAQ,MAAM;EACpB,OAAO,QAAQ,OAAO,OAAO;CAC/B;AACF;;AAGA,MAAM,SAAS,IAAI,cAAc;;AAGjC,MAAM,cAAc,YAChB,OAAO,WAAW,OAAO;AAI7B,qBAAe;CAAC;CAAe;CAAQ;AAAU"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
//#region src/lib/platform.ts
|
|
5
|
-
const require = createRequire(import.meta.url);
|
|
6
|
-
const PACKAGES = {
|
|
7
|
-
"win32-x64": "@shotkit/shotium-win32-x64",
|
|
8
|
-
"win32-arm64": "@shotkit/shotium-win32-arm64",
|
|
9
|
-
"darwin-x64": "@shotkit/shotium-darwin-x64",
|
|
10
|
-
"darwin-arm64": "@shotkit/shotium-darwin-arm64",
|
|
11
|
-
"linux-x64": "@shotkit/shotium-linux-x64",
|
|
12
|
-
"linux-arm64": "@shotkit/shotium-linux-arm64"
|
|
13
|
-
};
|
|
14
|
-
function packageName(platform = process.platform, arch = process.arch) {
|
|
15
|
-
return PACKAGES[`${platform}-${arch}`] ?? null;
|
|
16
|
-
}
|
|
17
|
-
function packageDir() {
|
|
18
|
-
const name = packageName();
|
|
19
|
-
if (!name) return null;
|
|
20
|
-
try {
|
|
21
|
-
return path.dirname(require.resolve(`${name}/package.json`));
|
|
22
|
-
} catch {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function binaryName() {
|
|
27
|
-
return process.platform === "win32" ? "shotium.exe" : "shotium";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
//#endregion
|
|
31
|
-
export { packageDir as n, packageName as r, binaryName as t };
|
|
32
|
-
//# sourceMappingURL=platform-DU8DYqmA.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"platform-DU8DYqmA.js","names":[],"sources":["../src/lib/platform.ts"],"sourcesContent":["import {createRequire} from 'node:module';\nimport path from 'node:path';\n\n// require.resolve is the resolver, and ESM has no synchronous equivalent\n// that answers for a package that may not be installed at all.\nconst require = createRequire(import.meta.url);\n\n// Which package carries the engine for this machine.\n//\n// The engine is not in this package and cannot be: it is a Chromium build,\n// 41 MB per platform and architecture, six of them, and `npm install` is never\n// going to produce one. So the bytes live in six packages of their own and\n// this one depends on all six as optionalDependencies with `os` and `cpu` set,\n// which is npm's way of saying \"install the one that matches this machine and\n// skip the other five\". A machine nobody builds for installs none of them and\n// still gets a working package -- it just has to be pointed at an engine.\n//\n// The alternative, a postinstall script that downloads a tarball, was not\n// chosen. It defeats a lockfile, which is supposed to pin what you get; it\n// fails behind a registry mirror, which is the one place a large dependency\n// most needs to work; and it runs code at install time in exchange for saving\n// nothing that npm was not already doing.\n//\n// Key and name are both `${process.platform}-${process.arch}`, so the table is\n// the identity map with a prefix on it. That is deliberate: the value npm\n// matches `os` and `cpu` against is process.platform, and a package named for\n// anything else makes the reader hold two spellings of one machine in their\n// head. It is also what every other package of this shape does -- esbuild,\n// swc, lightningcss all publish darwin-arm64 and win32-x64.\n//\n// The release archives spell it win/mac instead -- shotium-mac-arm64.7z --\n// and that is not going to change either. They are downloaded by people, and\n// `mac` is what people call it. So the two spellings do differ, in the one\n// place where each is right: the registry gets node's, the download page gets\n// the reader's.\nconst PACKAGES: Readonly<Record<string, string>> = {\n 'win32-x64': '@shotkit/shotium-win32-x64',\n 'win32-arm64': '@shotkit/shotium-win32-arm64',\n 'darwin-x64': '@shotkit/shotium-darwin-x64',\n 'darwin-arm64': '@shotkit/shotium-darwin-arm64',\n 'linux-x64': '@shotkit/shotium-linux-x64',\n 'linux-arm64': '@shotkit/shotium-linux-arm64',\n};\n\nfunction packageName(\n platform: string = process.platform,\n arch: string = process.arch): string|null {\n return PACKAGES[`${platform}-${arch}`] ?? null;\n}\n\n// Where the matching platform package unpacked, or null if it is not installed.\n//\n// require.resolve rather than a path built from the module's own location: the\n// package can be hoisted to a workspace root, nested under this one, or left\n// in a pnpm store with a symlink pointing at it, and the resolver is the only\n// thing that knows which of those happened.\nfunction packageDir(): string|null {\n const name = packageName();\n if (!name) {\n return null;\n }\n try {\n return path.dirname(require.resolve(`${name}/package.json`));\n } catch {\n return null;\n }\n}\n\n// What the engine executable is called, which is not what the platform calls\n// it: Windows wants the extension and nothing else does.\nfunction binaryName(): string {\n return process.platform === 'win32' ? 'shotium.exe' : 'shotium';\n}\n\nexport {PACKAGES, binaryName, packageDir, packageName};\n"],"mappings":";;;;AAKA,MAAM,UAAU,cAAc,YAAY,GAAG;AA8B7C,MAAM,WAA6C;CACjD,aAAa;CACb,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,eAAe;AACjB;AAEA,SAAS,YACL,WAAmB,QAAQ,UAC3B,OAAe,QAAQ,MAAmB;CAC5C,OAAO,SAAS,GAAG,SAAS,GAAG,WAAW;AAC5C;AAQA,SAAS,aAA0B;CACjC,MAAM,OAAO,YAAY;CACzB,IAAI,CAAC,MACH,OAAO;CAET,IAAI;EACF,OAAO,KAAK,QAAQ,QAAQ,QAAQ,GAAG,KAAK,cAAc,CAAC;CAC7D,QAAQ;EACN,OAAO;CACT;AACF;AAIA,SAAS,aAAqB;CAC5B,OAAO,QAAQ,aAAa,UAAU,gBAAgB;AACxD"}
|
package/dist/pool-BSgS6vkr.js
DELETED
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
import { n as packageDir, t as binaryName } from "./platform-DU8DYqmA.js";
|
|
2
|
-
import { EventEmitter } from "node:events";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import crypto from "node:crypto";
|
|
9
|
-
|
|
10
|
-
//#region src/lib/config.ts
|
|
11
|
-
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
function defaultBinary() {
|
|
13
|
-
if (process.env.SHOTIUM_BINARY) return process.env.SHOTIUM_BINARY;
|
|
14
|
-
const dir = packageDir();
|
|
15
|
-
if (dir) return path.join(dir, binaryName());
|
|
16
|
-
return path.join(HERE, "..", "bin", binaryName());
|
|
17
|
-
}
|
|
18
|
-
const MAXIMUM_DEFAULT_WORKERS = 4;
|
|
19
|
-
function defaultWorkers() {
|
|
20
|
-
const half = Math.floor((os.cpus().length || 2) / 2);
|
|
21
|
-
return Math.max(1, Math.min(MAXIMUM_DEFAULT_WORKERS, half));
|
|
22
|
-
}
|
|
23
|
-
function defaultCacheDir() {
|
|
24
|
-
return path.join(os.tmpdir(), "shotium-cache");
|
|
25
|
-
}
|
|
26
|
-
function resolveStartOptions(options = {}) {
|
|
27
|
-
return {
|
|
28
|
-
binary: options.binary || defaultBinary(),
|
|
29
|
-
workers: options.workers || defaultWorkers(),
|
|
30
|
-
cacheDir: options.cacheDir === null ? null : options.cacheDir || defaultCacheDir(),
|
|
31
|
-
args: options.args || []
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region src/lib/endpoint.ts
|
|
37
|
-
function endpointKey(options) {
|
|
38
|
-
if (options.name) return String(options.name);
|
|
39
|
-
const identity = JSON.stringify([
|
|
40
|
-
path.resolve(options.binary || ""),
|
|
41
|
-
options.workers,
|
|
42
|
-
options.cacheDir === null ? null : path.resolve(options.cacheDir || ""),
|
|
43
|
-
options.args || []
|
|
44
|
-
]);
|
|
45
|
-
return crypto.createHash("sha256").update(identity).digest("hex").slice(0, 16);
|
|
46
|
-
}
|
|
47
|
-
function endpointFor(options = {}) {
|
|
48
|
-
if (options.endpoint) return options.endpoint;
|
|
49
|
-
if (process.env.SHOTIUM_ENDPOINT) return process.env.SHOTIUM_ENDPOINT;
|
|
50
|
-
const key = endpointKey(options);
|
|
51
|
-
if (process.platform === "win32") return `\\\\.\\pipe\\shotium-${key}`;
|
|
52
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
53
|
-
return path.join(os.tmpdir(), `shotium-${uid}-${key}.sock`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/lib/protocol.ts
|
|
58
|
-
const HEADER_BYTES = 4;
|
|
59
|
-
function encodeFrame(payload) {
|
|
60
|
-
const header = Buffer.allocUnsafe(4);
|
|
61
|
-
header.writeUInt32LE(payload.length, 0);
|
|
62
|
-
return Buffer.concat([header, payload]);
|
|
63
|
-
}
|
|
64
|
-
function encodeRequest(request) {
|
|
65
|
-
return encodeFrame(Buffer.from(JSON.stringify(request), "utf8"));
|
|
66
|
-
}
|
|
67
|
-
var FrameReader = class {
|
|
68
|
-
buffer = Buffer.alloc(0);
|
|
69
|
-
push(chunk) {
|
|
70
|
-
this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
71
|
-
}
|
|
72
|
-
next() {
|
|
73
|
-
if (this.buffer.length < 4) return null;
|
|
74
|
-
const length = this.buffer.readUInt32LE(0);
|
|
75
|
-
if (this.buffer.length < 4 + length) return null;
|
|
76
|
-
const frame = this.buffer.subarray(4, 4 + length);
|
|
77
|
-
this.buffer = this.buffer.subarray(4 + length);
|
|
78
|
-
return frame;
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/lib/worker.ts
|
|
84
|
-
var Worker = class extends EventEmitter {
|
|
85
|
-
id;
|
|
86
|
-
served = 0;
|
|
87
|
-
binary;
|
|
88
|
-
args;
|
|
89
|
-
process = null;
|
|
90
|
-
pending = null;
|
|
91
|
-
stopping = false;
|
|
92
|
-
reader = new FrameReader();
|
|
93
|
-
header = null;
|
|
94
|
-
stderr = "";
|
|
95
|
-
constructor(options) {
|
|
96
|
-
super();
|
|
97
|
-
this.id = options.id;
|
|
98
|
-
this.binary = options.binary;
|
|
99
|
-
this.args = options.args || [];
|
|
100
|
-
this.start();
|
|
101
|
-
}
|
|
102
|
-
get busy() {
|
|
103
|
-
return this.pending !== null;
|
|
104
|
-
}
|
|
105
|
-
get alive() {
|
|
106
|
-
return this.process !== null && this.process.exitCode === null && !this.stopping;
|
|
107
|
-
}
|
|
108
|
-
start() {
|
|
109
|
-
const stdio = [
|
|
110
|
-
"pipe",
|
|
111
|
-
"pipe",
|
|
112
|
-
"pipe"
|
|
113
|
-
];
|
|
114
|
-
const child = spawn(this.binary, ["--serve", ...this.args], {
|
|
115
|
-
stdio,
|
|
116
|
-
windowsHide: true,
|
|
117
|
-
detached: true
|
|
118
|
-
});
|
|
119
|
-
this.process = child;
|
|
120
|
-
child.stdout?.on("data", (chunk) => this.onStdout(chunk));
|
|
121
|
-
child.stderr?.on("data", (chunk) => this.onStderr(chunk));
|
|
122
|
-
child.on("error", (error) => this.onGone(null, null, error));
|
|
123
|
-
child.on("exit", (code, signal) => this.onGone(code, signal, null));
|
|
124
|
-
this.emit("ready");
|
|
125
|
-
}
|
|
126
|
-
onStdout(chunk) {
|
|
127
|
-
this.reader.push(chunk);
|
|
128
|
-
for (;;) {
|
|
129
|
-
const frame = this.reader.next();
|
|
130
|
-
if (frame === null) return;
|
|
131
|
-
if (this.header === null) {
|
|
132
|
-
try {
|
|
133
|
-
this.header = JSON.parse(frame.toString("utf8"));
|
|
134
|
-
} catch {
|
|
135
|
-
this.fail(/* @__PURE__ */ new Error(`shotium: worker ${this.id} sent a header that is not JSON`));
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
const header = this.header;
|
|
141
|
-
this.header = null;
|
|
142
|
-
this.settle(header, frame);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
onStderr(chunk) {
|
|
146
|
-
this.stderr += chunk.toString("utf8");
|
|
147
|
-
const lines = this.stderr.split(/\r?\n/);
|
|
148
|
-
this.stderr = lines.pop() ?? "";
|
|
149
|
-
for (const line of lines) if (line.length > 0) this.emit("stderr", {
|
|
150
|
-
worker: this.id,
|
|
151
|
-
line
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
onGone(code, signal, error) {
|
|
155
|
-
const wasOwed = this.pending !== null;
|
|
156
|
-
this.process = null;
|
|
157
|
-
if (wasOwed) {
|
|
158
|
-
this.fail(error || /* @__PURE__ */ new Error(`shotium: worker ${this.id} exited (code ${code}, signal ${signal}) with a request in flight`));
|
|
159
|
-
this.emit("crash", {
|
|
160
|
-
worker: this.id,
|
|
161
|
-
code,
|
|
162
|
-
signal
|
|
163
|
-
});
|
|
164
|
-
} else if (error) this.emit("error", error);
|
|
165
|
-
this.emit("exit", {
|
|
166
|
-
worker: this.id,
|
|
167
|
-
code,
|
|
168
|
-
signal
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
settle(header, payload) {
|
|
172
|
-
const pending = this.pending;
|
|
173
|
-
if (!pending) return;
|
|
174
|
-
this.pending = null;
|
|
175
|
-
this.served += 1;
|
|
176
|
-
if (header.ok) pending.resolve({
|
|
177
|
-
header,
|
|
178
|
-
image: header.path ? null : payload
|
|
179
|
-
});
|
|
180
|
-
else pending.reject(new Error(header.error || "shotium: request failed"));
|
|
181
|
-
}
|
|
182
|
-
fail(error) {
|
|
183
|
-
const pending = this.pending;
|
|
184
|
-
if (!pending) return;
|
|
185
|
-
this.pending = null;
|
|
186
|
-
pending.reject(error);
|
|
187
|
-
}
|
|
188
|
-
send(request) {
|
|
189
|
-
if (this.pending) return Promise.reject(/* @__PURE__ */ new Error(`shotium: worker ${this.id} is already busy`));
|
|
190
|
-
if (!this.alive) return Promise.reject(/* @__PURE__ */ new Error(`shotium: worker ${this.id} is not up`));
|
|
191
|
-
return new Promise((resolve, reject) => {
|
|
192
|
-
this.pending = {
|
|
193
|
-
resolve,
|
|
194
|
-
reject
|
|
195
|
-
};
|
|
196
|
-
this.process?.stdin?.write(encodeRequest(request), (error) => {
|
|
197
|
-
if (error) this.fail(error);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
stop() {
|
|
202
|
-
this.stopping = true;
|
|
203
|
-
this.process?.stdin?.end();
|
|
204
|
-
}
|
|
205
|
-
kill() {
|
|
206
|
-
this.stopping = true;
|
|
207
|
-
this.process?.kill();
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
//#endregion
|
|
212
|
-
//#region src/lib/pool.ts
|
|
213
|
-
const FAST_FAILURE_MS = 1e3;
|
|
214
|
-
const RESPAWN_DELAY_MS = 100;
|
|
215
|
-
const MAX_RESPAWN_DELAY_MS = 5e3;
|
|
216
|
-
var Pool = class extends EventEmitter {
|
|
217
|
-
binary;
|
|
218
|
-
size;
|
|
219
|
-
args;
|
|
220
|
-
cacheDir;
|
|
221
|
-
slots = [];
|
|
222
|
-
failures = [];
|
|
223
|
-
queue = [];
|
|
224
|
-
stopping = false;
|
|
225
|
-
nextId = 0;
|
|
226
|
-
constructor(options) {
|
|
227
|
-
super();
|
|
228
|
-
this.binary = options.binary;
|
|
229
|
-
this.size = options.workers;
|
|
230
|
-
this.args = options.args || [];
|
|
231
|
-
this.cacheDir = options.cacheDir || null;
|
|
232
|
-
}
|
|
233
|
-
start() {
|
|
234
|
-
if (this.slots.length > 0) return;
|
|
235
|
-
for (let slot = 0; slot < this.size; ++slot) this.slots[slot] = this.spawn(slot);
|
|
236
|
-
this.emit("ready", { workers: this.size });
|
|
237
|
-
}
|
|
238
|
-
spawn(slot) {
|
|
239
|
-
const id = this.nextId++;
|
|
240
|
-
const args = [...this.args];
|
|
241
|
-
if (this.cacheDir) {
|
|
242
|
-
const dir = path.join(this.cacheDir, `worker-${slot}`);
|
|
243
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
244
|
-
args.push(`--cache-dir=${dir}`);
|
|
245
|
-
}
|
|
246
|
-
const startedAt = Date.now();
|
|
247
|
-
const worker = new Worker({
|
|
248
|
-
id,
|
|
249
|
-
binary: this.binary,
|
|
250
|
-
args
|
|
251
|
-
});
|
|
252
|
-
worker.on("stderr", (event) => this.emit("stderr", event));
|
|
253
|
-
worker.on("crash", (event) => this.emit("crash", event));
|
|
254
|
-
worker.on("error", (error) => this.emit("worker-error", {
|
|
255
|
-
worker: id,
|
|
256
|
-
error
|
|
257
|
-
}));
|
|
258
|
-
worker.on("exit", (event) => {
|
|
259
|
-
this.emit("exit", event);
|
|
260
|
-
if (this.stopping || this.slots[slot] !== worker) return;
|
|
261
|
-
const started = worker.served > 0 || Date.now() - startedAt >= FAST_FAILURE_MS;
|
|
262
|
-
if (started) this.failures[slot] = 0;
|
|
263
|
-
const failures = this.failures[slot] || 0;
|
|
264
|
-
const delay = started ? 0 : Math.min(MAX_RESPAWN_DELAY_MS, RESPAWN_DELAY_MS * 2 ** failures);
|
|
265
|
-
this.failures[slot] = failures + 1;
|
|
266
|
-
const refill = () => {
|
|
267
|
-
if (this.stopping || this.slots[slot] !== worker) return;
|
|
268
|
-
const replacement = this.spawn(slot);
|
|
269
|
-
this.slots[slot] = replacement;
|
|
270
|
-
this.emit("worker-restart", {
|
|
271
|
-
worker: replacement.id,
|
|
272
|
-
reason: "exit",
|
|
273
|
-
delay
|
|
274
|
-
});
|
|
275
|
-
this.pump();
|
|
276
|
-
};
|
|
277
|
-
if (delay === 0) {
|
|
278
|
-
refill();
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
setTimeout(refill, delay).unref();
|
|
282
|
-
});
|
|
283
|
-
return worker;
|
|
284
|
-
}
|
|
285
|
-
submit(request, { timeout, retry }) {
|
|
286
|
-
return new Promise((resolve, reject) => {
|
|
287
|
-
this.queue.push({
|
|
288
|
-
request,
|
|
289
|
-
timeout,
|
|
290
|
-
attemptsLeft: Math.max(0, retry) + 1,
|
|
291
|
-
resolve,
|
|
292
|
-
reject
|
|
293
|
-
});
|
|
294
|
-
this.pump();
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
pump() {
|
|
298
|
-
while (this.queue.length > 0) {
|
|
299
|
-
const slot = this.slots.findIndex((w) => w && w.alive && !w.busy);
|
|
300
|
-
if (slot < 0) return;
|
|
301
|
-
this.dispatch(this.slots[slot], this.queue.shift());
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
dispatch(worker, job) {
|
|
305
|
-
job.attemptsLeft -= 1;
|
|
306
|
-
let settled = false;
|
|
307
|
-
const timer = setTimeout(() => {
|
|
308
|
-
if (settled) return;
|
|
309
|
-
settled = true;
|
|
310
|
-
this.emit("timeout", {
|
|
311
|
-
worker: worker.id,
|
|
312
|
-
timeout: job.timeout
|
|
313
|
-
});
|
|
314
|
-
worker.kill();
|
|
315
|
-
this.retryOrFail(job, /* @__PURE__ */ new Error(`shotium: no answer within ${job.timeout}ms`));
|
|
316
|
-
}, job.timeout);
|
|
317
|
-
worker.send(job.request).then((result) => {
|
|
318
|
-
if (settled) return;
|
|
319
|
-
settled = true;
|
|
320
|
-
clearTimeout(timer);
|
|
321
|
-
job.resolve(result);
|
|
322
|
-
this.pump();
|
|
323
|
-
}).catch((error) => {
|
|
324
|
-
if (settled) return;
|
|
325
|
-
settled = true;
|
|
326
|
-
clearTimeout(timer);
|
|
327
|
-
this.retryOrFail(job, error);
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
retryOrFail(job, error) {
|
|
331
|
-
if (job.attemptsLeft > 0 && !this.stopping) {
|
|
332
|
-
this.queue.unshift(job);
|
|
333
|
-
this.pump();
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
job.reject(error);
|
|
337
|
-
this.pump();
|
|
338
|
-
}
|
|
339
|
-
async stop() {
|
|
340
|
-
this.stopping = true;
|
|
341
|
-
for (const job of this.queue.splice(0)) job.reject(/* @__PURE__ */ new Error("shotium: the runtime was stopped"));
|
|
342
|
-
await Promise.all(this.slots.map((worker) => new Promise((resolve) => {
|
|
343
|
-
if (!worker || !worker.alive) {
|
|
344
|
-
resolve();
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
worker.once("exit", () => resolve());
|
|
348
|
-
worker.stop();
|
|
349
|
-
})));
|
|
350
|
-
this.slots = [];
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
//#endregion
|
|
355
|
-
export { resolveStartOptions as a, endpointFor as i, FrameReader as n, encodeFrame as r, Pool as t };
|
|
356
|
-
//# sourceMappingURL=pool-BSgS6vkr.js.map
|