@evoke-build/evoke 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +74 -0
- package/core.wasm +0 -0
- package/dist/adapter.d.ts +24 -0
- package/dist/adapter.js +74 -0
- package/dist/contain.d.ts +34 -0
- package/dist/contain.js +146 -0
- package/dist/core.d.ts +34 -0
- package/dist/core.js +102 -0
- package/dist/decision.d.ts +109 -0
- package/dist/decision.js +5 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +50 -0
- package/dist/files.d.ts +13 -0
- package/dist/files.js +100 -0
- package/dist/https.d.ts +20 -0
- package/dist/https.js +109 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +6 -0
- package/dist/jev.d.ts +6 -0
- package/dist/jev.js +8 -0
- package/dist/openjev.d.ts +6 -0
- package/dist/openjev.js +9 -0
- package/dist/ops.d.ts +458 -0
- package/dist/ops.js +4 -0
- package/dist/project.d.ts +138 -0
- package/dist/project.js +623 -0
- package/dist/reflex.d.ts +85 -0
- package/dist/reflex.js +8 -0
- package/dist/runtime.d.ts +34 -0
- package/dist/runtime.js +254 -0
- package/dist/systemone.d.ts +21 -0
- package/dist/systemone.js +114 -0
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +90 -0
- package/dist/types.d.ts +1363 -0
- package/dist/types.js +7 -0
- package/package.json +62 -0
- package/runtime/loader.mjs +128 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// The wire types, by hand, from the Rust: what crosses the boundary as JSON — every value the op table takes and
|
|
2
|
+
// answers — in the core's module order. Kept honest by the vectors: build/vectors.ts makes every case of
|
|
3
|
+
// spec/vectors satisfy its op's types, so a field that drifts here fails the check. The rules of the wire
|
|
4
|
+
// (spec/README.md#wire):
|
|
5
|
+
// snake_case keys; an Option absent when none; a newtype as its value; an enum tagged by `type` (a Decision by
|
|
6
|
+
// `outcome`); a Result as { ok } | { err }.
|
|
7
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evoke-build/evoke",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "You invoke a function; you evoke a reflex. The SDK: load a project of reflexes, decide with Jev, run.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jev",
|
|
7
|
+
"openjev",
|
|
8
|
+
"typesafe",
|
|
9
|
+
"classifier",
|
|
10
|
+
"natural-language",
|
|
11
|
+
"reflex",
|
|
12
|
+
"cli",
|
|
13
|
+
"sdk",
|
|
14
|
+
"automation"
|
|
15
|
+
],
|
|
16
|
+
"license": "Apache-2.0",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/evoke-build/evoke.git",
|
|
20
|
+
"directory": "sdk"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.5"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"core.wasm",
|
|
29
|
+
"runtime",
|
|
30
|
+
"NOTICE"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./jev": {
|
|
38
|
+
"types": "./dist/jev.d.ts",
|
|
39
|
+
"default": "./dist/jev.js"
|
|
40
|
+
},
|
|
41
|
+
"./openjev": {
|
|
42
|
+
"types": "./dist/openjev.d.ts",
|
|
43
|
+
"default": "./dist/openjev.js"
|
|
44
|
+
},
|
|
45
|
+
"./testing": {
|
|
46
|
+
"types": "./dist/testing.d.ts",
|
|
47
|
+
"default": "./dist/testing.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc -p tsconfig.build.json",
|
|
55
|
+
"check": "node scripts/vectors.mts && tsc -p tsconfig.json",
|
|
56
|
+
"test": "node --test 'test/**/*.test.mts'"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "24.13.6",
|
|
60
|
+
"typescript": "5.9.3"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// The loader: one envelope line on stdin — { run, args, input, config, deadline } — the body `run` names imported
|
|
2
|
+
// and its default export called with (args, { input, config, signal }), then one result line on stdout:
|
|
3
|
+
// { text, data? } or { error, refused? } — `refused` when the error is a refusal by Node's permission model or the
|
|
4
|
+
// kernel: what was refused, a permission or a syscall, and the path, so the host names the declaration's key. It
|
|
5
|
+
// exits when stdin closes, before or during a body, so its life is bounded by its parent's. The body's console
|
|
6
|
+
// and stdout go to stderr, as do the frames of an error it throws — the frames alone, without the message the
|
|
7
|
+
// host reports, and without the frames inside Node itself; an error thrown from a callback ends the body as a
|
|
8
|
+
// rejection does. SIGTERM and the deadline abort `signal`; a body that has not settled a second later is
|
|
9
|
+
// abandoned. The SDK ships this same file.
|
|
10
|
+
import { writeSync } from "node:fs";
|
|
11
|
+
import module from "node:module";
|
|
12
|
+
import { pathToFileURL } from "node:url";
|
|
13
|
+
|
|
14
|
+
const GRACE = 1000;
|
|
15
|
+
// What a refusal's code is: Node's permission model's, the kernel's, or the resolver's when its socket is refused.
|
|
16
|
+
const REFUSALS = new Set(["ERR_ACCESS_DENIED", "EACCES", "EPERM", "EAI_AGAIN", "ENOTFOUND"]);
|
|
17
|
+
// Node's type stripper loads on the first `.mts` import, some twenty milliseconds a body would pay after its
|
|
18
|
+
// envelope arrived: loaded now instead, while the envelope is on its way. The host turns the API's experimental
|
|
19
|
+
// warning off; a runtime without the API skips this, and a body's own import says if types cannot be stripped.
|
|
20
|
+
try {
|
|
21
|
+
module.stripTypeScriptTypes?.("let warm: true = true");
|
|
22
|
+
} catch {
|
|
23
|
+
// Nothing to warm.
|
|
24
|
+
}
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
// The whole line, however long: `process.stdout` below puts the pipe in non-blocking mode, so one write may take
|
|
27
|
+
// part of it, and the next may be told to wait a moment.
|
|
28
|
+
const out = (value) => {
|
|
29
|
+
const bytes = Buffer.from(`${JSON.stringify(value)}\n`);
|
|
30
|
+
for (let written = 0; written < bytes.length; ) {
|
|
31
|
+
try {
|
|
32
|
+
written += writeSync(1, bytes, written);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error.code !== "EAGAIN") throw error;
|
|
35
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const fail = (message, refused) => {
|
|
40
|
+
out(refused === undefined ? { error: message } : { error: message, refused });
|
|
41
|
+
process.exit(1);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
process.stdout.write = (chunk, encoding, callback) => process.stderr.write(chunk, encoding, callback);
|
|
45
|
+
globalThis.console = new console.Console({ stdout: process.stderr, stderr: process.stderr });
|
|
46
|
+
|
|
47
|
+
let buffered = "";
|
|
48
|
+
let started = false;
|
|
49
|
+
process.stdin.setEncoding("utf8");
|
|
50
|
+
process.stdin.on("data", (chunk) => {
|
|
51
|
+
if (started) return;
|
|
52
|
+
buffered += chunk;
|
|
53
|
+
const end = buffered.indexOf("\n");
|
|
54
|
+
if (end >= 0) {
|
|
55
|
+
started = true;
|
|
56
|
+
run(buffered.slice(0, end));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
process.stdin.on("end", () => process.exit(started ? 1 : 0));
|
|
60
|
+
|
|
61
|
+
async function run(line) {
|
|
62
|
+
let envelope;
|
|
63
|
+
try {
|
|
64
|
+
envelope = JSON.parse(line);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return fail(`the envelope is not JSON: ${error.message}`);
|
|
67
|
+
}
|
|
68
|
+
const { run, args, input, config, deadline } = envelope;
|
|
69
|
+
const stop = (why) => {
|
|
70
|
+
if (!controller.signal.aborted) controller.abort(new Error(why));
|
|
71
|
+
setTimeout(() => fail(why), GRACE);
|
|
72
|
+
};
|
|
73
|
+
process.on("SIGTERM", () => stop("terminated"));
|
|
74
|
+
process.on("uncaughtException", thrown);
|
|
75
|
+
const timer = setTimeout(() => stop(`timed out after ${deadline} ms`), deadline);
|
|
76
|
+
try {
|
|
77
|
+
const module = await import(pathToFileURL(run).href);
|
|
78
|
+
if (module.default === undefined) throw new Error(`${run} has no default export`);
|
|
79
|
+
if (typeof module.default !== "function") throw new Error(`the default export of ${run} is not a function`);
|
|
80
|
+
const returned = await module.default(args, { input, config, signal: controller.signal });
|
|
81
|
+
const result = typeof returned === "string" ? { text: returned } : returned;
|
|
82
|
+
if (result === null || typeof result !== "object" || typeof result.text !== "string") {
|
|
83
|
+
throw new Error(`the body returned ${describe(returned)}, not text or { text, data }`);
|
|
84
|
+
}
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
out(result.data === undefined ? { text: result.text } : { text: result.text, data: result.data });
|
|
87
|
+
process.exit(0);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
thrown(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A body's error, whether its promise rejected with it or a callback threw it: the frames on stderr, then the
|
|
94
|
+
// message and what refused the body, when something did, as the one line.
|
|
95
|
+
function thrown(error) {
|
|
96
|
+
const frames = error instanceof Error && error.stack ? where(error.stack) : "";
|
|
97
|
+
if (frames) process.stderr.write(`${frames}\n`);
|
|
98
|
+
fail(error instanceof Error ? error.message : String(error), refusal(error));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// What refused the body, when something did. A lookup names the host, whether Node's permission model refused it
|
|
102
|
+
// or the kernel refused the resolver its socket; any other refused call names the syscall and the path, or the
|
|
103
|
+
// address and a port when there is one, the kernel's and, on the network, Node's alike; anything else Node's
|
|
104
|
+
// permission model refuses names the permission and the resource. A fetch wraps what refused it in its cause.
|
|
105
|
+
function refusal(error) {
|
|
106
|
+
const cause = error?.cause;
|
|
107
|
+
const e = cause !== null && typeof cause === "object" && "code" in cause ? cause : error;
|
|
108
|
+
if (e === null || typeof e !== "object" || !REFUSALS.has(e.code)) return undefined;
|
|
109
|
+
const text = (value) => (value === undefined || value === null ? "" : String(value));
|
|
110
|
+
if (e.hostname !== undefined) return { what: "resolve", path: text(e.hostname) };
|
|
111
|
+
if (e.syscall === undefined) return { what: text(e.permission), path: text(e.resource) };
|
|
112
|
+
const address = [e.address, e.port].filter((part) => part !== undefined).join(":");
|
|
113
|
+
return { what: text(e.syscall), path: text(e.path) || address };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function where(stack) {
|
|
117
|
+
const lines = stack.split("\n");
|
|
118
|
+
const first = lines.findIndex((line) => line.startsWith(" at "));
|
|
119
|
+
return (first < 0 ? [] : lines.slice(first))
|
|
120
|
+
.filter((line) => !/[( ]node:/.test(line) && !line.includes("[eval"))
|
|
121
|
+
.join("\n");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function describe(value) {
|
|
125
|
+
if (value === null) return "null";
|
|
126
|
+
if (Array.isArray(value)) return "an array";
|
|
127
|
+
return typeof value === "object" ? "an object without text" : typeof value;
|
|
128
|
+
}
|