@evolu/nodejs 3.0.0-next.2 → 3.0.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/dist/src/Cli.d.ts +29 -0
- package/dist/src/Cli.d.ts.map +1 -0
- package/dist/src/Cli.js +49 -0
- package/dist/src/Platform.d.ts +15 -0
- package/dist/src/Platform.d.ts.map +1 -0
- package/dist/src/Platform.js +9 -0
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +125 -35
- package/dist/src/Task.d.ts +69 -24
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +148 -52
- package/dist/src/TestBundle.d.ts +113 -0
- package/dist/src/TestBundle.d.ts.map +1 -0
- package/dist/src/TestBundle.js +503 -0
- package/dist/src/Time.d.ts +28 -0
- package/dist/src/Time.d.ts.map +1 -0
- package/dist/src/Time.js +25 -0
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/Worker.d.ts +3 -1
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +93 -1
- package/dist/src/index.d.ts +13 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -1
- package/dist/src/local-first/Relay.d.ts +13 -20
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +42 -48
- package/package.json +30 -6
- package/src/Cli.ts +78 -0
- package/src/Platform.ts +20 -0
- package/src/Sqlite.ts +30 -11
- package/src/Task.ts +172 -63
- package/src/TestBundle.ts +674 -0
- package/src/Time.ts +55 -0
- package/src/Worker.ts +44 -0
- package/src/index.ts +14 -5
- package/src/local-first/Relay.ts +54 -58
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abort-aware CLI process utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { type Task, type Typed } from "@evolu/common";
|
|
7
|
+
/** Runs a command with inherited stdio. */
|
|
8
|
+
export type Spawn = (file: string, args: ReadonlyArray<string>, options?: {
|
|
9
|
+
readonly cwd?: string | URL;
|
|
10
|
+
}) => Task<void, SpawnError>;
|
|
11
|
+
/** Failure to start a command or an unsuccessful command exit. */
|
|
12
|
+
export interface SpawnError extends Typed<"SpawnError"> {
|
|
13
|
+
readonly command: string;
|
|
14
|
+
readonly exitCode: number | null;
|
|
15
|
+
readonly signal: NodeJS.Signals | null;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
}
|
|
18
|
+
/** Dependency wrapper for {@link spawn}. */
|
|
19
|
+
export interface SpawnDep {
|
|
20
|
+
readonly spawn: Spawn;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Runs a command with inherited stdio and aborts it with the current Run.
|
|
24
|
+
*
|
|
25
|
+
* A zero exit code succeeds. A start failure, non-zero exit code, or signal
|
|
26
|
+
* exit returns {@link SpawnError}.
|
|
27
|
+
*/
|
|
28
|
+
export declare const spawn: Spawn;
|
|
29
|
+
//# sourceMappingURL=Cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cli.d.ts","sourceRoot":"","sources":["../../src/Cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAqB,KAAK,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAGzE,2CAA2C;AAC3C,MAAM,MAAM,KAAK,GAAG,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAC7B,KACE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AAE5B,kEAAkE;AAClE,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,YAAY,CAAC;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,KAwCnB,CAAC"}
|
package/dist/src/Cli.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abort-aware CLI process utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { callback, err, ok } from "@evolu/common";
|
|
7
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
8
|
+
/**
|
|
9
|
+
* Runs a command with inherited stdio and aborts it with the current Run.
|
|
10
|
+
*
|
|
11
|
+
* A zero exit code succeeds. A start failure, non-zero exit code, or signal
|
|
12
|
+
* exit returns {@link SpawnError}.
|
|
13
|
+
*/
|
|
14
|
+
export const spawn = (file, args, { cwd } = {}) => {
|
|
15
|
+
const command = [file, ...args].join(" ");
|
|
16
|
+
return callback(({ run, resolve }) => {
|
|
17
|
+
const child = nodeSpawn(file, args, {
|
|
18
|
+
cwd,
|
|
19
|
+
signal: run.signal,
|
|
20
|
+
stdio: "inherit",
|
|
21
|
+
});
|
|
22
|
+
child.once("error", (error) => {
|
|
23
|
+
if (run.signal.aborted)
|
|
24
|
+
return;
|
|
25
|
+
resolve(err({
|
|
26
|
+
type: "SpawnError",
|
|
27
|
+
command,
|
|
28
|
+
exitCode: null,
|
|
29
|
+
signal: null,
|
|
30
|
+
message: `Failed to start ${command}: ${error.message}`,
|
|
31
|
+
}));
|
|
32
|
+
});
|
|
33
|
+
child.once("close", (exitCode, signal) => {
|
|
34
|
+
if (run.signal.aborted)
|
|
35
|
+
return;
|
|
36
|
+
resolve(exitCode === 0
|
|
37
|
+
? ok()
|
|
38
|
+
: err({
|
|
39
|
+
type: "SpawnError",
|
|
40
|
+
command,
|
|
41
|
+
exitCode,
|
|
42
|
+
signal,
|
|
43
|
+
message: signal == null
|
|
44
|
+
? `${command} exited with code ${exitCode}.`
|
|
45
|
+
: `${command} exited from ${signal}.`,
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js platform utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { PositiveInt } from "@evolu/common";
|
|
7
|
+
/** Returns the recommended amount of parallelism available to this process. */
|
|
8
|
+
export type AvailableParallelism = () => PositiveInt;
|
|
9
|
+
/** Dependency wrapper for {@link availableParallelism}. */
|
|
10
|
+
export interface AvailableParallelismDep {
|
|
11
|
+
readonly availableParallelism: AvailableParallelism;
|
|
12
|
+
}
|
|
13
|
+
/** Returns the recommended amount of parallelism available to this process. */
|
|
14
|
+
export declare const availableParallelism: AvailableParallelism;
|
|
15
|
+
//# sourceMappingURL=Platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Platform.d.ts","sourceRoot":"","sources":["../../src/Platform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,+EAA+E;AAC/E,MAAM,MAAM,oBAAoB,GAAG,MAAM,WAAW,CAAC;AAErD,2DAA2D;AAC3D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;CACrD;AAED,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,oBACc,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js platform utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { PositiveInt } from "@evolu/common";
|
|
7
|
+
import { availableParallelism as nodeAvailableParallelism } from "node:os";
|
|
8
|
+
/** Returns the recommended amount of parallelism available to this process. */
|
|
9
|
+
export const availableParallelism = () => PositiveInt.orThrow(nodeAvailableParallelism());
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AAIvB,eAAO,MAAM,wBAAwB,EAAE,kBAoEpC,CAAC"}
|
package/dist/src/Sqlite.js
CHANGED
|
@@ -1,38 +1,128 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
29
43
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
stack.dispose();
|
|
35
|
-
},
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
36
48
|
};
|
|
37
|
-
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { constVoid, createPreparedStatementsCache, ok, } from "@evolu/common";
|
|
54
|
+
import BetterSQLite, {} from "better-sqlite3";
|
|
55
|
+
import { rmSync } from "fs";
|
|
56
|
+
export const createBetterSqliteDriver = (name, options) => () => {
|
|
57
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
58
|
+
try {
|
|
59
|
+
const filename = options?.mode === "memory" ? ":memory:" : `${name}.db`;
|
|
60
|
+
const filenamesToDelete = options?.mode === "memory"
|
|
61
|
+
? []
|
|
62
|
+
: [
|
|
63
|
+
filename,
|
|
64
|
+
`${filename}-shm`,
|
|
65
|
+
`${filename}-wal`,
|
|
66
|
+
`${filename}-journal`,
|
|
67
|
+
];
|
|
68
|
+
const disposer = __addDisposableResource(env_1, new DisposableStack(), false);
|
|
69
|
+
const db = disposer.adopt(new BetterSQLite(filename), (db) => {
|
|
70
|
+
db.close();
|
|
71
|
+
});
|
|
72
|
+
const cache = disposer.use(createPreparedStatementsCache((sql) => db.prepare(sql),
|
|
73
|
+
// Not needed.
|
|
74
|
+
// https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md#class-statement
|
|
75
|
+
constVoid));
|
|
76
|
+
const disposables = disposer.move();
|
|
77
|
+
return ok({
|
|
78
|
+
exec: (query) => {
|
|
79
|
+
// Always prepare is recommended for better-sqlite3
|
|
80
|
+
const prepared = cache.get(query, true);
|
|
81
|
+
if (prepared.reader) {
|
|
82
|
+
const rows = prepared.all(query.parameters);
|
|
83
|
+
return { rows, changes: 0 };
|
|
84
|
+
}
|
|
85
|
+
const changes = prepared.run(query.parameters).changes;
|
|
86
|
+
return { rows: [], changes };
|
|
87
|
+
},
|
|
88
|
+
export: () => {
|
|
89
|
+
const file = db.serialize();
|
|
90
|
+
const { buffer } = file;
|
|
91
|
+
if (buffer instanceof ArrayBuffer) {
|
|
92
|
+
return new Uint8Array(buffer, file.byteOffset, file.byteLength);
|
|
93
|
+
}
|
|
94
|
+
// Ensure export uses transferable ArrayBuffer backing.
|
|
95
|
+
return new Uint8Array(file);
|
|
96
|
+
},
|
|
97
|
+
deleteDatabase: () => {
|
|
98
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
99
|
+
try {
|
|
100
|
+
const deleteDisposer = __addDisposableResource(env_2, new DisposableStack(), false);
|
|
101
|
+
for (const filename of filenamesToDelete) {
|
|
102
|
+
deleteDisposer.defer(() => {
|
|
103
|
+
rmSync(filename, { force: true });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
deleteDisposer.use(disposables);
|
|
107
|
+
}
|
|
108
|
+
catch (e_2) {
|
|
109
|
+
env_2.error = e_2;
|
|
110
|
+
env_2.hasError = true;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
__disposeResources(env_2);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
[Symbol.dispose]: () => {
|
|
117
|
+
disposables.dispose();
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (e_1) {
|
|
122
|
+
env_1.error = e_1;
|
|
123
|
+
env_1.hasError = true;
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
__disposeResources(env_1);
|
|
127
|
+
}
|
|
38
128
|
};
|
package/dist/src/Task.d.ts
CHANGED
|
@@ -3,43 +3,88 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import { type
|
|
6
|
+
import { type Resource, type RunCustomDeps, type Task, type Typed } from "@evolu/common";
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* An abort requested by a Node.js termination signal.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* `SIGHUP` (console close/terminal disconnect), or `SIGBREAK` (Windows
|
|
12
|
-
* Ctrl-Break).
|
|
13
|
-
*
|
|
14
|
-
* @group Node.js Run
|
|
10
|
+
* @group Node.js Task
|
|
15
11
|
*/
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
export interface NodeSignalAbortReason extends Typed<"NodeSignalAbortReason"> {
|
|
13
|
+
readonly signal: NodeSignal;
|
|
14
|
+
}
|
|
15
|
+
/** A Node.js termination signal handled by {@link runMain}. */
|
|
16
|
+
export type NodeSignal = "SIGINT" | "SIGTERM" | "SIGBREAK";
|
|
17
|
+
/** Process lifecycle behavior for {@link runMain}. */
|
|
18
|
+
export type RunMainMode = "service" | "command";
|
|
19
|
+
/** Options for {@link runMain}. */
|
|
20
|
+
export interface RunMainOptions {
|
|
21
|
+
/**
|
|
22
|
+
* How termination signals affect the process exit status.
|
|
23
|
+
*
|
|
24
|
+
* Services treat a gracefully handled signal as a successful shutdown.
|
|
25
|
+
* Commands use the conventional `128 + signal number` exit status unless a
|
|
26
|
+
* reported defect has already set a failure status.
|
|
27
|
+
*
|
|
28
|
+
* @default "service"
|
|
29
|
+
*/
|
|
30
|
+
readonly mode?: RunMainMode;
|
|
19
31
|
}
|
|
20
32
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
33
|
+
* Runs the main Task as the Node.js program lifecycle.
|
|
34
|
+
*
|
|
35
|
+
* Creates one root {@link Run} and aborts it on:
|
|
36
|
+
*
|
|
37
|
+
* - `SIGINT`: Ctrl-C on all platforms.
|
|
38
|
+
* - `SIGTERM`: OS, service, Docker, or Kubernetes termination on Unix.
|
|
39
|
+
* - `SIGBREAK`: Ctrl-Break on Windows.
|
|
40
|
+
*
|
|
41
|
+
* The first signal logs shutdown progress, aborts the root Run, and waits for
|
|
42
|
+
* the main Task and structured cleanup to finish. A subsequent signal exits
|
|
43
|
+
* immediately with its conventional signal status, abandoning cleanup. A signal
|
|
44
|
+
* received during final cleanup still applies signal shutdown behavior.
|
|
45
|
+
*
|
|
46
|
+
* A main Task returning {@link Resource} keeps the program running until a
|
|
47
|
+
* termination signal and is disposed during shutdown. A main Task returning
|
|
48
|
+
* `void` completes the program immediately. A Resource result transfers
|
|
49
|
+
* ownership of a live resource that must remain valid after its creating Task
|
|
50
|
+
* settles.
|
|
51
|
+
*
|
|
52
|
+
* Service mode treats graceful signal shutdown as successful. Command mode
|
|
53
|
+
* preserves conventional signal exit statuses. Every defect reported through
|
|
54
|
+
* `reportDefect`, including an observer defect that does not abort the Run,
|
|
55
|
+
* sets `process.exitCode` to 1. The default reporter logs to the configured
|
|
56
|
+
* Evolu console.
|
|
23
57
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* resolves on termination signals (`SIGINT`, `SIGTERM`, `SIGHUP`). Handlers are
|
|
27
|
-
* removed when the Run is disposed.
|
|
58
|
+
* Escaped uncaught exceptions and unhandled rejections remain under Node.js
|
|
59
|
+
* native reporting and termination.
|
|
28
60
|
*
|
|
29
|
-
* ### Example
|
|
61
|
+
* ### Service Example
|
|
30
62
|
*
|
|
31
63
|
* ```ts
|
|
32
|
-
* const deps = { ...createRelayDeps(), console };
|
|
64
|
+
* const deps = { ...createRelayDeps(), console: createConsole() };
|
|
33
65
|
*
|
|
34
|
-
* await
|
|
35
|
-
*
|
|
66
|
+
* await runMain(deps)(createRelay({ port: 4000 }));
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* A Task returning `void` can keep a service alive explicitly when no Resource
|
|
70
|
+
* owns its lifetime:
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* await runMain(deps)(async (run) => {
|
|
74
|
+
* void run(processMessages);
|
|
75
|
+
* return await run(waitForAbort);
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
36
78
|
*
|
|
37
|
-
*
|
|
79
|
+
* ### Command Example
|
|
38
80
|
*
|
|
39
|
-
*
|
|
81
|
+
* ```ts
|
|
82
|
+
* await runMain(command, { mode: "command" });
|
|
40
83
|
* ```
|
|
41
84
|
*
|
|
42
|
-
* @group Node.js
|
|
85
|
+
* @group Node.js Task
|
|
43
86
|
*/
|
|
44
|
-
export declare
|
|
87
|
+
export declare function runMain<T extends void | Resource>(main: Task<T>, options?: RunMainOptions): Promise<void>;
|
|
88
|
+
/** With custom dependencies. */
|
|
89
|
+
export declare function runMain<D extends object>(deps: RunCustomDeps<D>, options?: RunMainOptions): <T extends void | Resource>(main: Task<T, never, D>) => Promise<void>;
|
|
45
90
|
//# sourceMappingURL=Task.d.ts.map
|
package/dist/src/Task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAQL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAClB,KAAK,IAAI,EACT,KAAK,KAAK,EACX,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,MAAM,WAAW,qBAAsB,SAAQ,KAAK,CAAC,uBAAuB,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAED,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE3D,sDAAsD;AACtD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhD,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,IAAI,GAAG,QAAQ,EAC/C,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAAC;AACjB,gCAAgC;AAChC,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EACtC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,cAAc,GACvB,CAAC,CAAC,SAAS,IAAI,GAAG,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/src/Task.js
CHANGED
|
@@ -3,57 +3,153 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
6
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
7
|
+
if (value !== null && value !== void 0) {
|
|
8
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
9
|
+
var dispose, inner;
|
|
10
|
+
if (async) {
|
|
11
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.asyncDispose];
|
|
13
|
+
}
|
|
14
|
+
if (dispose === void 0) {
|
|
15
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
16
|
+
dispose = value[Symbol.dispose];
|
|
17
|
+
if (async) inner = dispose;
|
|
18
|
+
}
|
|
19
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
20
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
21
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
22
|
+
}
|
|
23
|
+
else if (async) {
|
|
24
|
+
env.stack.push({ async: true });
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
29
|
+
return function (env) {
|
|
30
|
+
function fail(e) {
|
|
31
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
32
|
+
env.hasError = true;
|
|
33
|
+
}
|
|
34
|
+
var r, s = 0;
|
|
35
|
+
function next() {
|
|
36
|
+
while (r = env.stack.pop()) {
|
|
37
|
+
try {
|
|
38
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
39
|
+
if (r.dispose) {
|
|
40
|
+
var result = r.dispose.call(r.value);
|
|
41
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
42
|
+
}
|
|
43
|
+
else s |= 1;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
fail(e);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
50
|
+
if (env.hasError) throw env.error;
|
|
51
|
+
}
|
|
52
|
+
return next();
|
|
41
53
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
55
|
+
var e = new Error(message);
|
|
56
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
57
|
+
});
|
|
58
|
+
import { createConsole, createRun, isDisposable, ok, waitForAbort, } from "@evolu/common";
|
|
59
|
+
export function runMain(mainOrDeps, { mode = "service" } = {}) {
|
|
60
|
+
return typeof mainOrDeps === "function"
|
|
61
|
+
? runMainInternal(mainOrDeps, {}, mode)
|
|
62
|
+
: (main) => runMainInternal(main, mainOrDeps, mode);
|
|
63
|
+
}
|
|
64
|
+
const commandExitCodeBySignal = {
|
|
65
|
+
SIGINT: 130,
|
|
66
|
+
SIGTERM: 143,
|
|
67
|
+
SIGBREAK: 149,
|
|
68
|
+
};
|
|
69
|
+
const runMainInternal = async (main, deps, mode) => {
|
|
70
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
71
|
+
try {
|
|
72
|
+
const console = deps.console ?? createConsole();
|
|
73
|
+
const mainConsole = console.child("main");
|
|
74
|
+
let defectReported = false;
|
|
75
|
+
let receivedSignal = null;
|
|
76
|
+
const disposer = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
|
|
77
|
+
const run = disposer.use(createRun({
|
|
78
|
+
...deps,
|
|
79
|
+
console,
|
|
80
|
+
reportDefect: (reported) => {
|
|
81
|
+
defectReported = true;
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
if (deps.reportDefect)
|
|
84
|
+
deps.reportDefect(reported);
|
|
85
|
+
else
|
|
86
|
+
console.error(reported);
|
|
87
|
+
},
|
|
88
|
+
}));
|
|
89
|
+
["SIGINT", "SIGTERM", "SIGBREAK"].forEach((signal) => {
|
|
90
|
+
const handleSignal = () => {
|
|
91
|
+
if (receivedSignal !== null) {
|
|
92
|
+
mainConsole.warn("Forcing shutdown...");
|
|
93
|
+
process.exit(commandExitCodeBySignal[signal]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
receivedSignal = signal;
|
|
97
|
+
mainConsole.info("Shutting down...");
|
|
98
|
+
run.abort({ type: "NodeSignalAbortReason", signal });
|
|
99
|
+
};
|
|
100
|
+
process.on(signal, handleSignal);
|
|
101
|
+
run.defer(() => {
|
|
102
|
+
process.off(signal, handleSignal);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
try {
|
|
106
|
+
await run(async (run) => {
|
|
107
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
108
|
+
try {
|
|
109
|
+
const resource = await run.ok(main);
|
|
110
|
+
if (!isDisposable(resource))
|
|
111
|
+
return ok();
|
|
112
|
+
const _resource = __addDisposableResource(env_2, resource, true);
|
|
113
|
+
return await run(waitForAbort);
|
|
114
|
+
}
|
|
115
|
+
catch (e_2) {
|
|
116
|
+
env_2.error = e_2;
|
|
117
|
+
env_2.hasError = true;
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
const result_2 = __disposeResources(env_2);
|
|
121
|
+
if (result_2)
|
|
122
|
+
await result_2;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Aborts are control flow; defects are already handled by reportDefect.
|
|
128
|
+
}
|
|
129
|
+
// Move ownership out of the await-using setup safety net so an already
|
|
130
|
+
// reported finalizer defect can be suppressed during explicit disposal.
|
|
131
|
+
try {
|
|
132
|
+
await disposer.move().disposeAsync();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Finalizer defects are already handled by reportDefect.
|
|
136
|
+
}
|
|
137
|
+
if (receivedSignal !== null) {
|
|
138
|
+
if (defectReported)
|
|
139
|
+
mainConsole.warn("Shutdown finished with errors");
|
|
140
|
+
else
|
|
141
|
+
mainConsole.info("Shutdown complete");
|
|
142
|
+
if (mode === "command")
|
|
143
|
+
process.exitCode ??= commandExitCodeBySignal[receivedSignal];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (e_1) {
|
|
147
|
+
env_1.error = e_1;
|
|
148
|
+
env_1.hasError = true;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
const result_1 = __disposeResources(env_1);
|
|
152
|
+
if (result_1)
|
|
153
|
+
await result_1;
|
|
154
|
+
}
|
|
59
155
|
};
|