@agentorg/cli 0.0.5 → 0.0.7
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 +23 -104
- package/dist/node_modules/@agentorg/computer/LICENSE +201 -0
- package/dist/node_modules/@agentorg/computer/NOTICE +2 -0
- package/dist/node_modules/@agentorg/computer/dist/THIRD_PARTY_LICENSES.txt +1321 -0
- package/dist/node_modules/@agentorg/computer/dist/sdk.js +24909 -0
- package/dist/node_modules/@agentorg/computer/dist/types/generated/schema.d.ts +860 -0
- package/dist/node_modules/@agentorg/computer/dist/types/sdk.d.ts +242 -0
- package/dist/node_modules/@agentorg/computer/package.json +12 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/index.d.ts +1 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/index.js +1 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.d.ts +24 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.js +482 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.d.ts +19 -0
- package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.js +149 -0
- package/dist/node_modules/@agentorg/computer-connector/package.json +33 -0
- package/dist/node_modules/@agentorg/computer-connector/skills/browser/SKILL.md +31 -0
- package/dist/node_modules/@agentorg/computer-connector/skills/computer/SKILL.md +30 -0
- package/dist/node_modules/@agentorg/computer-connector/skills/files/SKILL.md +28 -0
- package/dist/node_modules/@agentorg/computer-connector/skills/terminal/SKILL.md +39 -0
- package/dist/node_modules/@agentorg/computer-connector/skills/web-research/SKILL.md +29 -0
- package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.d.ts +2 -7
- package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.js +4 -144
- package/dist/node_modules/@agentorg/hub/dist/src/index.d.ts +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/index.js +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/router.d.ts +9 -58
- package/dist/node_modules/@agentorg/hub/dist/src/router.js +41 -414
- package/dist/node_modules/@agentorg/hub/dist/src/state.d.ts +17 -317
- package/dist/node_modules/@agentorg/hub/dist/src/state.js +42 -536
- package/dist/node_modules/@agentorg/hub/dist/src/validate.d.ts +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/validate.js +19 -17
- package/dist/node_modules/@agentorg/hub/package.json +0 -3
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.d.ts +119 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.js +96 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.d.ts +42 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.js +53 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/chat.d.ts +93 -38
- package/dist/node_modules/@agentorg/interfaces/dist/src/chat.js +71 -22
- package/dist/node_modules/@agentorg/interfaces/dist/src/connection.d.ts +36 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/connection.js +31 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/folders.d.ts +19 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/folders.js +25 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/hub.d.ts +16 -286
- package/dist/node_modules/@agentorg/interfaces/dist/src/hub.js +17 -159
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +9 -9
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +9 -9
- package/dist/node_modules/@agentorg/interfaces/dist/src/kv.d.ts +2 -2
- package/dist/node_modules/@agentorg/interfaces/dist/src/kv.js +2 -2
- package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.d.ts +2 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.js +2 -1
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +626 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +349 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/tools.d.ts +39 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/tools.js +43 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/units.d.ts +460 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/units.js +204 -0
- package/dist/node_modules/@agentorg/looper/dist/src/index.d.ts +5 -0
- package/dist/node_modules/@agentorg/looper/dist/src/index.js +5 -0
- package/dist/node_modules/@agentorg/looper/dist/src/loop.d.ts +75 -0
- package/dist/node_modules/@agentorg/looper/dist/src/loop.js +332 -0
- package/dist/node_modules/@agentorg/looper/dist/src/looper.d.ts +71 -0
- package/dist/node_modules/@agentorg/looper/dist/src/looper.js +282 -0
- package/dist/node_modules/@agentorg/looper/dist/src/record.d.ts +99 -0
- package/dist/node_modules/@agentorg/looper/dist/src/record.js +278 -0
- package/dist/node_modules/@agentorg/looper/dist/src/tools.d.ts +11 -0
- package/dist/node_modules/@agentorg/looper/dist/src/tools.js +42 -0
- package/dist/node_modules/@agentorg/looper/dist/src/types.d.ts +147 -0
- package/dist/node_modules/@agentorg/looper/dist/src/types.js +32 -0
- package/dist/node_modules/@agentorg/looper/package.json +24 -0
- package/dist/node_modules/@agentorg/manager/dist/src/activity.d.ts +18 -0
- package/dist/node_modules/@agentorg/manager/dist/src/activity.js +65 -0
- package/dist/node_modules/@agentorg/manager/dist/src/control.d.ts +134 -0
- package/dist/node_modules/@agentorg/manager/dist/src/control.js +1115 -0
- package/dist/node_modules/@agentorg/manager/dist/src/form.d.ts +40 -0
- package/dist/node_modules/@agentorg/manager/dist/src/form.js +191 -0
- package/dist/node_modules/@agentorg/manager/dist/src/index.d.ts +1 -0
- package/dist/node_modules/@agentorg/manager/dist/src/index.js +1 -0
- package/dist/node_modules/@agentorg/manager/dist/src/manager.d.ts +25 -0
- package/dist/node_modules/@agentorg/manager/dist/src/manager.js +680 -0
- package/dist/node_modules/@agentorg/manager/dist/src/skills.d.ts +27 -0
- package/dist/node_modules/@agentorg/manager/dist/src/skills.js +152 -0
- package/dist/node_modules/@agentorg/manager/dist/src/stack.d.ts +454 -0
- package/dist/node_modules/@agentorg/manager/dist/src/stack.js +917 -0
- package/dist/node_modules/@agentorg/manager/package.json +30 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/connection.d.ts +34 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/connection.js +296 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/index.d.ts +4 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/index.js +4 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/kinds.d.ts +158 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/kinds.js +164 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/provider.d.ts +22 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/provider.js +197 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/public.d.ts +6 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/public.js +72 -0
- package/dist/node_modules/@agentorg/mcp/package.json +31 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/cli.js +3 -23
- package/dist/node_modules/@agentorg/sdk/dist/src/client.d.ts +4 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/client.js +5 -55
- package/dist/node_modules/@agentorg/sdk/dist/src/errors.d.ts +1 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/errors.js +3 -3
- package/dist/node_modules/@agentorg/sdk/dist/src/filled.d.ts +21 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/filled.js +24 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/index.d.ts +3 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/index.js +2 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/interface.d.ts +6 -34
- package/dist/node_modules/@agentorg/sdk/dist/src/interface.js +3 -24
- package/dist/node_modules/@agentorg/sdk/dist/src/module-host.d.ts +8 -17
- package/dist/node_modules/@agentorg/sdk/dist/src/module-host.js +15 -87
- package/dist/node_modules/@agentorg/sdk/dist/src/module.d.ts +10 -76
- package/dist/node_modules/@agentorg/sdk/dist/src/module.js +3 -23
- package/dist/node_modules/@agentorg/sdk/dist/src/person-commands.js +0 -5
- package/dist/node_modules/@agentorg/sdk/dist/src/runtime.d.ts +3 -27
- package/dist/node_modules/@agentorg/sdk/dist/src/runtime.js +5 -100
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.d.ts +7 -8
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +12 -24
- package/dist/node_modules/@agentorg/sdk/package.json +4 -37
- package/dist/node_modules/@agentorg/shell/dist/app.css +4624 -739
- package/dist/node_modules/@agentorg/shell/dist/app.js +245 -202
- package/dist/node_modules/@agentorg/shell/package.json +23 -10
- package/dist/node_modules/@agentorg/wire/dist/src/frames.d.ts +2 -3
- package/dist/node_modules/@agentorg/wire/dist/src/frames.js +2 -3
- package/dist/node_modules/@agentorg/wire/dist/src/ops.d.ts +5 -34
- package/dist/node_modules/@agentorg/wire/dist/src/ops.js +2 -17
- package/dist/node_modules/assistant/dist/src/chats.d.ts +92 -0
- package/dist/node_modules/assistant/dist/src/chats.js +357 -0
- package/dist/node_modules/assistant/dist/src/engine.d.ts +42 -0
- package/dist/node_modules/assistant/dist/src/engine.js +160 -0
- package/dist/node_modules/assistant/dist/src/local-store.d.ts +3 -0
- package/dist/node_modules/assistant/dist/src/local-store.js +58 -0
- package/dist/node_modules/assistant/dist/src/provider.d.ts +21 -0
- package/dist/node_modules/assistant/dist/src/provider.js +259 -0
- package/dist/node_modules/assistant/dist/src/settings.d.ts +17 -0
- package/dist/node_modules/assistant/dist/src/settings.js +43 -0
- package/dist/node_modules/assistant/dist/src/tools.d.ts +57 -0
- package/dist/node_modules/assistant/dist/src/tools.js +102 -0
- package/dist/node_modules/assistant/package.json +30 -0
- package/dist/node_modules/chatgpt/dist/src/account.d.ts +52 -0
- package/dist/node_modules/chatgpt/dist/src/account.js +270 -0
- package/dist/node_modules/chatgpt/dist/src/encoding.d.ts +7 -0
- package/dist/node_modules/chatgpt/dist/src/encoding.js +20 -0
- package/dist/node_modules/chatgpt/dist/src/file-store.d.ts +9 -0
- package/dist/node_modules/chatgpt/dist/src/file-store.js +68 -0
- package/dist/node_modules/chatgpt/dist/src/index.d.ts +1 -0
- package/dist/node_modules/chatgpt/dist/src/index.js +1 -0
- package/dist/node_modules/chatgpt/dist/src/jwt.d.ts +15 -0
- package/dist/node_modules/chatgpt/dist/src/jwt.js +37 -0
- package/dist/node_modules/chatgpt/dist/src/oauth.d.ts +43 -0
- package/dist/node_modules/chatgpt/dist/src/oauth.js +104 -0
- package/dist/node_modules/chatgpt/dist/src/program.d.ts +23 -0
- package/dist/node_modules/chatgpt/dist/src/program.js +41 -0
- package/dist/node_modules/chatgpt/dist/src/responses.d.ts +54 -0
- package/dist/node_modules/chatgpt/dist/src/responses.js +300 -0
- package/dist/node_modules/chatgpt/dist/src/serve.d.ts +65 -0
- package/dist/node_modules/chatgpt/dist/src/serve.js +46 -0
- package/dist/node_modules/chatgpt/package.json +33 -0
- package/dist/src/api.d.ts +5 -34
- package/dist/src/api.js +10 -68
- package/dist/src/cli.js +3 -7
- package/dist/src/folders.d.ts +2 -0
- package/dist/src/folders.js +45 -0
- package/dist/src/gateway.d.ts +13 -8
- package/dist/src/gateway.js +119 -296
- package/dist/src/index.d.ts +4 -5
- package/dist/src/index.js +3 -4
- package/dist/src/live.d.ts +17 -0
- package/dist/src/live.js +109 -0
- package/dist/src/notes.d.ts +11 -0
- package/dist/src/notes.js +64 -0
- package/dist/src/oauth.d.ts +16 -0
- package/dist/src/oauth.js +46 -0
- package/dist/src/programs.d.ts +36 -0
- package/dist/src/programs.js +198 -0
- package/dist/src/signin.d.ts +12 -3
- package/dist/src/signin.js +30 -6
- package/package.json +4 -11
- package/dist/bundled/index.json +0 -6
- package/dist/bundled/sha256-0e91cc3d0e9762b81abc2427b5496b20f383abcd6fb97d928a8d50e956b54d1f.agentorg +0 -0
- package/dist/bundled/sha256-1f64ca62a0209d767d6aa6c4feb50b0653d60f10bebbc301f79bd3a37e0153c1.agentorg +0 -0
- package/dist/bundled/sha256-4055f8fddf6b90f3d356543f554b2a9e9a2c4a8827a8774f8f87952dc1692331.agentorg +0 -0
- package/dist/bundled/sha256-e356ea3c1899138a8494baf521556831006f38534fa9e92ae873e7e6956c3a46.agentorg +0 -0
- package/dist/node_modules/@agentorg/hub/dist/src/build.d.ts +0 -17
- package/dist/node_modules/@agentorg/hub/dist/src/build.js +0 -120
- package/dist/node_modules/@agentorg/hub/dist/src/logs.d.ts +0 -33
- package/dist/node_modules/@agentorg/hub/dist/src/logs.js +0 -162
- package/dist/node_modules/@agentorg/hub/dist/src/net.d.ts +0 -41
- package/dist/node_modules/@agentorg/hub/dist/src/net.js +0 -265
- package/dist/node_modules/@agentorg/hub/dist/src/processes.d.ts +0 -78
- package/dist/node_modules/@agentorg/hub/dist/src/processes.js +0 -485
- package/dist/node_modules/@agentorg/hub/dist/src/storage.d.ts +0 -38
- package/dist/node_modules/@agentorg/hub/dist/src/storage.js +0 -194
- package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -6
- package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.js +0 -7
- package/dist/node_modules/@agentorg/interfaces/dist/src/installer.d.ts +0 -191
- package/dist/node_modules/@agentorg/interfaces/dist/src/installer.js +0 -136
- package/dist/node_modules/@agentorg/interfaces/dist/src/layout.d.ts +0 -47
- package/dist/node_modules/@agentorg/interfaces/dist/src/layout.js +0 -52
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +0 -35
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +0 -37
- package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -23
- package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.js +0 -31
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -14
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.js +0 -26
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -27
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.js +0 -26
- package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +0 -37
- package/dist/node_modules/@agentorg/kit/dist/src/chat.js +0 -131
- package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +0 -94
- package/dist/node_modules/@agentorg/kit/dist/src/components.js +0 -66
- package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +0 -17
- package/dist/node_modules/@agentorg/kit/dist/src/icons.js +0 -30
- package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +0 -6
- package/dist/node_modules/@agentorg/kit/dist/src/index.js +0 -10
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +0 -9
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +0 -14
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +0 -5
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +0 -8
- package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +0 -11
- package/dist/node_modules/@agentorg/kit/dist/src/styles.js +0 -166
- package/dist/node_modules/@agentorg/kit/package.json +0 -44
- package/dist/node_modules/@agentorg/sdk/dist/frame/runtime.js +0 -753
- package/dist/node_modules/@agentorg/sdk/dist/host/runner.js +0 -21963
- package/dist/node_modules/@agentorg/sdk/dist/src/build.d.ts +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/build.js +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/client-http.d.ts +0 -24
- package/dist/node_modules/@agentorg/sdk/dist/src/client-http.js +0 -247
- package/dist/node_modules/@agentorg/sdk/dist/src/describe.d.ts +0 -13
- package/dist/node_modules/@agentorg/sdk/dist/src/describe.js +0 -16
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +0 -8
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +0 -64
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.js +0 -35
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.d.ts +0 -57
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.js +0 -293
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -124
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.js +0 -16
- package/dist/node_modules/@agentorg/sdk/dist/src/frame.d.ts +0 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/frame.js +0 -248
- package/dist/node_modules/@agentorg/sdk/dist/src/host-main.d.ts +0 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/host-main.js +0 -60
- package/dist/node_modules/@agentorg/sdk/dist/src/host.d.ts +0 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/host.js +0 -92
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.js +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest.d.ts +0 -56
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest.js +0 -165
- package/dist/node_modules/@agentorg/sdk/dist/src/package.d.ts +0 -60
- package/dist/node_modules/@agentorg/sdk/dist/src/package.js +0 -538
- package/dist/node_modules/@agentorg/sdk/dist/src/tar.d.ts +0 -7
- package/dist/node_modules/@agentorg/sdk/dist/src/tar.js +0 -71
- package/dist/node_modules/@agentorg/shell/dist/agent-bindings.js +0 -59
- package/dist/node_modules/@agentorg/shell/src/agent-bindings.ts +0 -107
- package/dist/src/frames.d.ts +0 -23
- package/dist/src/frames.js +0 -78
- package/dist/src/layout.d.ts +0 -44
- package/dist/src/layout.js +0 -90
- package/dist/src/model.d.ts +0 -54
- package/dist/src/model.js +0 -299
- package/dist/src/rules.d.ts +0 -71
- package/dist/src/rules.js +0 -157
- package/dist/src/transfer.d.ts +0 -30
- package/dist/src/transfer.js +0 -110
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { readdirSync, rmSync } from "node:fs";
|
|
2
|
-
import { mkdir, mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { Refused } from "@agentorg/sdk";
|
|
6
|
-
import { BuildError, buildPackage } from "@agentorg/sdk/build";
|
|
7
|
-
/** What a package's source may total, paths and text: it fits in one frame. */
|
|
8
|
-
export const MAX_SOURCE = 768 * 1024;
|
|
9
|
-
/** Files one package's source may have. */
|
|
10
|
-
const MAX_FILES = 256;
|
|
11
|
-
/**
|
|
12
|
-
* What a package built by the Hub may import by name: the SDK, the interfaces, zod, and React and
|
|
13
|
-
* the kit for views (`react/jsx-runtime`, which JSX compiles to, is React's).
|
|
14
|
-
*/
|
|
15
|
-
const ALLOWED = [
|
|
16
|
-
"@agentorg/sdk",
|
|
17
|
-
"@agentorg/interfaces",
|
|
18
|
-
"zod",
|
|
19
|
-
"react",
|
|
20
|
-
"react-dom",
|
|
21
|
-
"@agentorg/kit",
|
|
22
|
-
];
|
|
23
|
-
/** Where those are found: this package's own folder (dist/src/build.js → the package). */
|
|
24
|
-
const FROM = fileURLToPath(new URL("../..", import.meta.url));
|
|
25
|
-
/** A source path: `package.json`, or a source file under `src/` named plainly. */
|
|
26
|
-
const PATH = /^(package\.json|src(\/[A-Za-z0-9_][A-Za-z0-9_.-]*)*\/[A-Za-z0-9_][A-Za-z0-9_.-]*\.(ts|tsx|mts|js|mjs|jsx|json))$/;
|
|
27
|
-
/** Files under `src/` that tools read as configuration: a tsconfig can name any file to read. */
|
|
28
|
-
const CONFIG = /(^|\/)(tsconfig|jsconfig|package)\.json$/;
|
|
29
|
-
/** At most 16 modules and 16 MiB built; 30 s to bundle each module, 60 s for the whole build. */
|
|
30
|
-
const LIMITS = { modules: 16, bytes: 16 * 1024 * 1024, bundleMs: 30_000, totalMs: 60_000 };
|
|
31
|
-
/** How long reading one module's definition may take, in a Hub build. */
|
|
32
|
-
const DESCRIBE_MS = 5_000;
|
|
33
|
-
/**
|
|
34
|
-
* The source as given, checked before anything is written or queued: its paths (no two the same
|
|
35
|
-
* but for case, none both a file and a folder), its size.
|
|
36
|
-
*/
|
|
37
|
-
export function checkSource(files) {
|
|
38
|
-
if (typeof files !== "object" || files === null || Array.isArray(files))
|
|
39
|
-
throw new Refused("invalid", "files is an object of path to text.");
|
|
40
|
-
const entries = Object.entries(files);
|
|
41
|
-
if (entries.length > MAX_FILES)
|
|
42
|
-
throw new Refused("invalid", `A package's source is at most ${MAX_FILES} files.`);
|
|
43
|
-
let size = 0;
|
|
44
|
-
const seen = new Set();
|
|
45
|
-
for (const [path, text] of entries) {
|
|
46
|
-
if (path.length > 256 || !PATH.test(path) || (path !== "package.json" && CONFIG.test(path)))
|
|
47
|
-
throw new Refused("invalid", `${JSON.stringify(path)}: a package's source is package.json and source files under src/ (.ts, .tsx, .mts, .js, .mjs, .jsx, .json; no tsconfig, jsconfig or package.json there), by plain relative paths.`);
|
|
48
|
-
const lower = path.toLowerCase();
|
|
49
|
-
if (seen.has(lower))
|
|
50
|
-
throw new Refused("invalid", `${path}: another path differs from it only by case.`);
|
|
51
|
-
seen.add(lower);
|
|
52
|
-
if (typeof text !== "string")
|
|
53
|
-
throw new Refused("invalid", `${path} isn't text.`);
|
|
54
|
-
size += Buffer.byteLength(path) + Buffer.byteLength(text);
|
|
55
|
-
}
|
|
56
|
-
if (size > MAX_SOURCE)
|
|
57
|
-
throw new Refused("invalid", `A package's source is at most ${MAX_SOURCE / 1024} KiB.`);
|
|
58
|
-
if (!entries.some(([path]) => path === "package.json"))
|
|
59
|
-
throw new Refused("invalid", "A package's source has a package.json.");
|
|
60
|
-
for (const lower of seen)
|
|
61
|
-
for (let at = lower.indexOf("/"); at > 0; at = lower.indexOf("/", at + 1))
|
|
62
|
-
if (seen.has(lower.slice(0, at)))
|
|
63
|
-
throw new Refused("invalid", `${lower.slice(0, at)} is both a file and a folder.`);
|
|
64
|
-
return entries;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* A build's message as the caller may see it: the package's own paths relative to it, and the
|
|
68
|
-
* places the Hub knows (its home, its installation) never named. The SDK already tells a place
|
|
69
|
-
* outside the package as <outside>; only known prefixes are replaced here, so what the caller
|
|
70
|
-
* wrote comes back as written.
|
|
71
|
-
*/
|
|
72
|
-
function told(message, source, home) {
|
|
73
|
-
return message
|
|
74
|
-
.replaceAll(`${source}/`, "")
|
|
75
|
-
.replaceAll(source, ".")
|
|
76
|
-
.replaceAll(home, "<home>")
|
|
77
|
-
.replaceAll(FROM.replace(/\/$/, ""), "<hub>");
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Build a package from its source, given as data, and add it with `add`: the files are written to
|
|
81
|
-
* a fresh folder in the home, built as `agentorg build` builds (importing by name only the SDK,
|
|
82
|
-
* the interfaces, zod, React, react-dom and the kit, and nothing outside the folder; reading no tsconfig; at most 16
|
|
83
|
-
* modules and 16 MiB built), and the folder is gone after, whatever happened. A build that fails
|
|
84
|
-
* is `Refused("build")` with the build's message, which names no path outside the package.
|
|
85
|
-
*/
|
|
86
|
-
export async function buildSource(home, entries, sandbox, add) {
|
|
87
|
-
const dir = await realpath(await mkdtemp(join(home, "build-")));
|
|
88
|
-
const source = join(dir, "source");
|
|
89
|
-
try {
|
|
90
|
-
let built;
|
|
91
|
-
try {
|
|
92
|
-
for (const [path, text] of entries) {
|
|
93
|
-
await mkdir(dirname(join(source, path)), { recursive: true, mode: 0o700 });
|
|
94
|
-
await writeFile(join(source, path), text, { mode: 0o600, flag: "wx" });
|
|
95
|
-
}
|
|
96
|
-
built = await buildPackage(source, {
|
|
97
|
-
out: join(dir, "out"),
|
|
98
|
-
packages: { allowed: ALLOWED, from: FROM },
|
|
99
|
-
limits: LIMITS,
|
|
100
|
-
describeTimeoutMs: DESCRIBE_MS,
|
|
101
|
-
// The describer runs the source's code: in the OS sandbox host processes run in.
|
|
102
|
-
describer: { sandbox },
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
107
|
-
throw new Refused("build", told(error instanceof BuildError ? message : `The build failed: ${message}`, source, await realpath(home)));
|
|
108
|
-
}
|
|
109
|
-
return add(built.file);
|
|
110
|
-
}
|
|
111
|
-
finally {
|
|
112
|
-
await rm(dir, { recursive: true, force: true });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/** Folders of builds a crash interrupted: removed when the Hub opens. */
|
|
116
|
-
export function sweepBuilds(home) {
|
|
117
|
-
for (const name of readdirSync(home))
|
|
118
|
-
if (name.startsWith("build-"))
|
|
119
|
-
rmSync(join(home, name), { recursive: true, force: true });
|
|
120
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/** One line of an Actor's log, as `hub.actors.logs` returns it. */
|
|
2
|
-
export interface LogLine {
|
|
3
|
-
level: "info" | "warn" | "error";
|
|
4
|
-
message: string;
|
|
5
|
-
data?: Record<string, unknown>;
|
|
6
|
-
module?: string;
|
|
7
|
-
at: string;
|
|
8
|
-
}
|
|
9
|
-
/** Where an Actor's log is kept in the home; the previous file, rotated once, is `<file>.1`. */
|
|
10
|
-
export declare const logFile: (home: string, actorId: string) => string;
|
|
11
|
-
/**
|
|
12
|
-
* The newest `limit` entries of an Actor's log, oldest first, across its file and the one rotated
|
|
13
|
-
* before it. Lines that aren't a log entry are skipped and don't count.
|
|
14
|
-
*/
|
|
15
|
-
export declare function readLogs(home: string, actorId: string, limit: number): LogLine[];
|
|
16
|
-
/**
|
|
17
|
-
* An entry as it is written, whoever gave it: a known level, the text cut, and the data rebuilt
|
|
18
|
-
* as a fresh object of at most `MAX_FIELDS` keys, each value a primitive or JSON text, cut.
|
|
19
|
-
*/
|
|
20
|
-
export declare function boundedEntry(level: unknown, message: unknown, data: unknown, module: string | undefined): LogLine;
|
|
21
|
-
/**
|
|
22
|
-
* Add an entry to an Actor's log (0600). A file that would pass 1 MiB is rotated to `<file>.1`
|
|
23
|
-
* first, replacing the one before, so an Actor's logs never hold more than two files.
|
|
24
|
-
*/
|
|
25
|
-
export declare function appendLog(home: string, actorId: string, entry: LogLine): void;
|
|
26
|
-
/** Add entries to an Actor's log in one write, rotating first as `appendLog` does. */
|
|
27
|
-
export declare function appendLogs(home: string, actorId: string, entries: LogLine[]): void;
|
|
28
|
-
/**
|
|
29
|
-
* A line a host process wrote, as a log entry: on stderr, a JSON line with a message and a time is
|
|
30
|
-
* one of the runner's `ctx.log` entries (bounded like any other); anything else is the process's
|
|
31
|
-
* own output, `info` from stdout and `error` from stderr.
|
|
32
|
-
*/
|
|
33
|
-
export declare function outputEntry(stream: "stdout" | "stderr", line: string): LogLine;
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, closeSync, fstatSync, mkdirSync, openSync, readSync, renameSync, statSync, } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
/** Where an Actor's log is kept in the home; the previous file, rotated once, is `<file>.1`. */
|
|
4
|
-
export const logFile = (home, actorId) => join(home, "logs", `${actorId}.log`);
|
|
5
|
-
/** A log file is rotated once it would pass this; each read takes at most this of a file's end. */
|
|
6
|
-
const MAX_FILE = 1024 * 1024;
|
|
7
|
-
const TAIL = MAX_FILE;
|
|
8
|
-
/** A line's text is cut to this. */
|
|
9
|
-
const MAX_MESSAGE = 4096;
|
|
10
|
-
/** A line's data: this many keys at most, each value a primitive or JSON text, cut to this. */
|
|
11
|
-
const MAX_FIELDS = 16;
|
|
12
|
-
const MAX_FIELD = 1024;
|
|
13
|
-
function tail(path) {
|
|
14
|
-
let fd;
|
|
15
|
-
try {
|
|
16
|
-
fd = openSync(path, "r");
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return []; // Not written yet.
|
|
20
|
-
}
|
|
21
|
-
try {
|
|
22
|
-
const size = fstatSync(fd).size;
|
|
23
|
-
const length = Math.min(size, TAIL);
|
|
24
|
-
const buffer = Buffer.alloc(length);
|
|
25
|
-
readSync(fd, buffer, 0, length, size - length);
|
|
26
|
-
const lines = buffer.toString("utf8").split("\n");
|
|
27
|
-
// Cut mid-file, the first line is a fragment.
|
|
28
|
-
return size > length ? lines.slice(1) : lines;
|
|
29
|
-
}
|
|
30
|
-
finally {
|
|
31
|
-
closeSync(fd);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const LEVELS = new Set(["info", "warn", "error"]);
|
|
35
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36
|
-
/** A line as a log entry, built from its known fields only; anything else isn't one. */
|
|
37
|
-
function entryOf(line) {
|
|
38
|
-
let raw;
|
|
39
|
-
try {
|
|
40
|
-
raw = JSON.parse(line);
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return undefined; // A partial line from a crash, or not ours.
|
|
44
|
-
}
|
|
45
|
-
if (!isRecord(raw) || typeof raw.message !== "string" || typeof raw.at !== "string")
|
|
46
|
-
return undefined;
|
|
47
|
-
return {
|
|
48
|
-
level: LEVELS.has(raw.level) ? raw.level : "info",
|
|
49
|
-
message: raw.message,
|
|
50
|
-
...(isRecord(raw.data) ? { data: raw.data } : {}),
|
|
51
|
-
...(typeof raw.module === "string" ? { module: raw.module } : {}),
|
|
52
|
-
at: raw.at,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* The newest `limit` entries of an Actor's log, oldest first, across its file and the one rotated
|
|
57
|
-
* before it. Lines that aren't a log entry are skipped and don't count.
|
|
58
|
-
*/
|
|
59
|
-
export function readLogs(home, actorId, limit) {
|
|
60
|
-
const file = logFile(home, actorId);
|
|
61
|
-
const lines = [...tail(`${file}.1`), ...tail(file)];
|
|
62
|
-
const entries = [];
|
|
63
|
-
for (let i = lines.length - 1; i >= 0 && entries.length < limit; i--) {
|
|
64
|
-
const entry = entryOf(lines[i]);
|
|
65
|
-
if (entry)
|
|
66
|
-
entries.push(entry);
|
|
67
|
-
}
|
|
68
|
-
return entries.reverse();
|
|
69
|
-
}
|
|
70
|
-
/** Anything as text, even what can't say itself (no prototype, a throwing `toString`). */
|
|
71
|
-
function textOf(value) {
|
|
72
|
-
try {
|
|
73
|
-
return String(value);
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return "[unprintable]";
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/** One field's value as it is kept: a number, boolean or null as is, anything else as text, cut. */
|
|
80
|
-
function fieldOf(read) {
|
|
81
|
-
try {
|
|
82
|
-
const value = read();
|
|
83
|
-
if (value === null || typeof value === "number" || typeof value === "boolean")
|
|
84
|
-
return value;
|
|
85
|
-
const text = typeof value === "string" ? value : textOf(JSON.stringify(value));
|
|
86
|
-
return text.slice(0, MAX_FIELD);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return "[unreadable]"; // A getter, toJSON or bigint that throws.
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* An entry as it is written, whoever gave it: a known level, the text cut, and the data rebuilt
|
|
94
|
-
* as a fresh object of at most `MAX_FIELDS` keys, each value a primitive or JSON text, cut.
|
|
95
|
-
*/
|
|
96
|
-
export function boundedEntry(level, message, data, module) {
|
|
97
|
-
let fields;
|
|
98
|
-
try {
|
|
99
|
-
if (isRecord(data)) {
|
|
100
|
-
// No prototype: a `__proto__` key is a key like any other.
|
|
101
|
-
fields = Object.create(null);
|
|
102
|
-
let kept = 0;
|
|
103
|
-
// Only the first keys are read: the rest are never touched.
|
|
104
|
-
for (const key in data) {
|
|
105
|
-
if (!Object.hasOwn(data, key))
|
|
106
|
-
continue;
|
|
107
|
-
if (kept++ >= MAX_FIELDS)
|
|
108
|
-
break;
|
|
109
|
-
fields[key.slice(0, MAX_FIELD)] = fieldOf(() => data[key]);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
fields = undefined; // Data that can't even list its keys (a hostile proxy) is left out.
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
level: LEVELS.has(level) ? level : "info",
|
|
118
|
-
message: textOf(message).slice(0, MAX_MESSAGE),
|
|
119
|
-
...(fields ? { data: fields } : {}),
|
|
120
|
-
...(module === undefined ? {} : { module }),
|
|
121
|
-
at: new Date().toISOString(),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Add an entry to an Actor's log (0600). A file that would pass 1 MiB is rotated to `<file>.1`
|
|
126
|
-
* first, replacing the one before, so an Actor's logs never hold more than two files.
|
|
127
|
-
*/
|
|
128
|
-
export function appendLog(home, actorId, entry) {
|
|
129
|
-
appendLogs(home, actorId, [entry]);
|
|
130
|
-
}
|
|
131
|
-
/** Add entries to an Actor's log in one write, rotating first as `appendLog` does. */
|
|
132
|
-
export function appendLogs(home, actorId, entries) {
|
|
133
|
-
if (!entries.length)
|
|
134
|
-
return;
|
|
135
|
-
const file = logFile(home, actorId);
|
|
136
|
-
const line = entries.map((entry) => `${JSON.stringify(entry)}\n`).join("");
|
|
137
|
-
// Past what a reader takes of a file, a line could never be read back.
|
|
138
|
-
if (Buffer.byteLength(line) > MAX_FILE)
|
|
139
|
-
return;
|
|
140
|
-
mkdirSync(join(home, "logs"), { recursive: true, mode: 0o700 });
|
|
141
|
-
let size = 0;
|
|
142
|
-
try {
|
|
143
|
-
size = statSync(file).size;
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
// Not written yet.
|
|
147
|
-
}
|
|
148
|
-
if (size > 0 && size + Buffer.byteLength(line) > MAX_FILE)
|
|
149
|
-
renameSync(file, `${file}.1`);
|
|
150
|
-
appendFileSync(file, line, { mode: 0o600 });
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* A line a host process wrote, as a log entry: on stderr, a JSON line with a message and a time is
|
|
154
|
-
* one of the runner's `ctx.log` entries (bounded like any other); anything else is the process's
|
|
155
|
-
* own output, `info` from stdout and `error` from stderr.
|
|
156
|
-
*/
|
|
157
|
-
export function outputEntry(stream, line) {
|
|
158
|
-
const parsed = stream === "stderr" ? entryOf(line) : undefined;
|
|
159
|
-
return parsed
|
|
160
|
-
? boundedEntry(parsed.level, parsed.message, parsed.data, parsed.module?.slice(0, 64))
|
|
161
|
-
: boundedEntry(stream === "stdout" ? "info" : "error", line, undefined, undefined);
|
|
162
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { LookupAddress } from "node:dns";
|
|
2
|
-
import { BlockList } from "node:net";
|
|
3
|
-
import { type HubState } from "./state.js";
|
|
4
|
-
export interface NetOptions {
|
|
5
|
-
/** Resolve a host name to every address it has. Tests give their own. */
|
|
6
|
-
lookup?: (host: string) => Promise<LookupAddress[]>;
|
|
7
|
-
/** A CA to trust beside the usual roots. Tests give their own. */
|
|
8
|
-
ca?: string;
|
|
9
|
-
/** How long a request may go without a byte either way. */
|
|
10
|
-
idleMs?: number;
|
|
11
|
-
/** Addresses refused: by default `blockedAddresses()`. Tests leave loopback out to reach their server. */
|
|
12
|
-
blocked?: BlockList;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Addresses that aren't the public internet: unspecified, loopback, private (RFC 1918, ULA),
|
|
16
|
-
* shared (CGNAT), link-local (the cloud metadata address among them), multicast, and the reserved
|
|
17
|
-
* and documentation ranges; in IPv6 also the IPv4-compatible range, Teredo and NAT64's local-use
|
|
18
|
-
* prefix. An IPv4-mapped IPv6 address is checked by its IPv4 rules here; `isPublicAddress` checks
|
|
19
|
-
* the other forms that carry an IPv4 address. Only tests leave IPv4 loopback out.
|
|
20
|
-
*/
|
|
21
|
-
export declare function blockedAddresses(options?: {
|
|
22
|
-
loopback?: boolean;
|
|
23
|
-
}): BlockList;
|
|
24
|
-
/** Whether `net` may connect to an address: an IP address, not blocked, and carrying none that is. */
|
|
25
|
-
export declare function isPublicAddress(address: string, blocked?: BlockList): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* The built-in `net` Actor's `http.egress@1`: a consumer's request, made from the Hub's process to
|
|
28
|
-
* the public internet over HTTPS. The host is resolved and every address checked; the connection
|
|
29
|
-
* goes to the checked address (with the name for SNI and the certificate), so a second resolution
|
|
30
|
-
* can't move it. Redirects come back as they are. Each request's method, host and status are
|
|
31
|
-
* audited; bodies never are.
|
|
32
|
-
*/
|
|
33
|
-
export declare class Net {
|
|
34
|
-
#private;
|
|
35
|
-
constructor(state: HubState, options?: NetOptions);
|
|
36
|
-
/** One request, for the consumer's slot. Refusals and failures throw the SDK's errors. */
|
|
37
|
-
handle(request: Request, by: {
|
|
38
|
-
consumer: string;
|
|
39
|
-
slot: string;
|
|
40
|
-
}): Promise<Response>;
|
|
41
|
-
}
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { lookup as dnsLookup } from "node:dns/promises";
|
|
2
|
-
import { request as httpsRequest } from "node:https";
|
|
3
|
-
import { BlockList, isIP } from "node:net";
|
|
4
|
-
import { Readable } from "node:stream";
|
|
5
|
-
import { pipeline } from "node:stream/promises";
|
|
6
|
-
import { rootCertificates } from "node:tls";
|
|
7
|
-
import { OutcomeUnknown, Refused } from "@agentorg/sdk";
|
|
8
|
-
import { ERROR_HEADER } from "@agentorg/sdk/http";
|
|
9
|
-
import { NET } from "./state.js";
|
|
10
|
-
/**
|
|
11
|
-
* Addresses that aren't the public internet: unspecified, loopback, private (RFC 1918, ULA),
|
|
12
|
-
* shared (CGNAT), link-local (the cloud metadata address among them), multicast, and the reserved
|
|
13
|
-
* and documentation ranges; in IPv6 also the IPv4-compatible range, Teredo and NAT64's local-use
|
|
14
|
-
* prefix. An IPv4-mapped IPv6 address is checked by its IPv4 rules here; `isPublicAddress` checks
|
|
15
|
-
* the other forms that carry an IPv4 address. Only tests leave IPv4 loopback out.
|
|
16
|
-
*/
|
|
17
|
-
export function blockedAddresses(options = {}) {
|
|
18
|
-
const blocked = new BlockList();
|
|
19
|
-
for (const [network, prefix] of [
|
|
20
|
-
["0.0.0.0", 8],
|
|
21
|
-
["10.0.0.0", 8],
|
|
22
|
-
["100.64.0.0", 10],
|
|
23
|
-
["127.0.0.0", 8],
|
|
24
|
-
["169.254.0.0", 16],
|
|
25
|
-
["172.16.0.0", 12],
|
|
26
|
-
["192.0.0.0", 24],
|
|
27
|
-
["192.0.2.0", 24],
|
|
28
|
-
["192.168.0.0", 16],
|
|
29
|
-
["198.18.0.0", 15],
|
|
30
|
-
["198.51.100.0", 24],
|
|
31
|
-
["203.0.113.0", 24],
|
|
32
|
-
["224.0.0.0", 4],
|
|
33
|
-
["240.0.0.0", 4],
|
|
34
|
-
])
|
|
35
|
-
if (options.loopback !== false || network !== "127.0.0.0")
|
|
36
|
-
blocked.addSubnet(network, prefix, "ipv4");
|
|
37
|
-
for (const [network, prefix] of [
|
|
38
|
-
// IPv4-compatible (deprecated), with :: and ::1 in it.
|
|
39
|
-
["::", 96],
|
|
40
|
-
["64:ff9b:1::", 48],
|
|
41
|
-
["100::", 64],
|
|
42
|
-
["2001::", 32],
|
|
43
|
-
["2001:db8::", 32],
|
|
44
|
-
["fc00::", 7],
|
|
45
|
-
["fe80::", 10],
|
|
46
|
-
["fec0::", 10],
|
|
47
|
-
["ff00::", 8],
|
|
48
|
-
])
|
|
49
|
-
blocked.addSubnet(network, prefix, "ipv6");
|
|
50
|
-
return blocked;
|
|
51
|
-
}
|
|
52
|
-
/** An IPv6 address's eight 16-bit groups; a zone and a dotted IPv4 tail are understood. */
|
|
53
|
-
function groupsOf(address) {
|
|
54
|
-
let text = address.toLowerCase().split("%")[0] ?? "";
|
|
55
|
-
const dotted = /(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(text);
|
|
56
|
-
if (dotted) {
|
|
57
|
-
const [a, b, c, d] = dotted.slice(1).map(Number);
|
|
58
|
-
text = `${text.slice(0, dotted.index)}${((a << 8) | b).toString(16)}:${((c << 8) | d).toString(16)}`;
|
|
59
|
-
}
|
|
60
|
-
const [head = "", tail] = text.split("::");
|
|
61
|
-
const left = head ? head.split(":") : [];
|
|
62
|
-
const right = tail ? tail.split(":") : [];
|
|
63
|
-
const fill = tail === undefined ? 0 : 8 - left.length - right.length;
|
|
64
|
-
const groups = [...left, ...Array(Math.max(fill, 0)).fill("0"), ...right];
|
|
65
|
-
return groups.length === 8 ? groups.map((group) => Number.parseInt(group, 16)) : undefined;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* The IPv4 address an IPv6 address carries, in the forms that reach it: NAT64's well-known
|
|
69
|
-
* prefix (64:ff9b::/96), IPv4-translated (::ffff:0:0:0/96) and 6to4 (2002::/16).
|
|
70
|
-
*/
|
|
71
|
-
function carriedIPv4(address) {
|
|
72
|
-
const g = groupsOf(address);
|
|
73
|
-
if (!g)
|
|
74
|
-
return undefined;
|
|
75
|
-
const v4 = (high, low) => `${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`;
|
|
76
|
-
const zero = (from, to) => g.slice(from, to).every((x) => x === 0);
|
|
77
|
-
if (g[0] === 0x64 && g[1] === 0xff9b && zero(2, 6))
|
|
78
|
-
return v4(g[6] ?? 0, g[7] ?? 0);
|
|
79
|
-
if (zero(0, 4) && g[4] === 0xffff && g[5] === 0)
|
|
80
|
-
return v4(g[6] ?? 0, g[7] ?? 0);
|
|
81
|
-
if (g[0] === 0x2002)
|
|
82
|
-
return v4(g[1] ?? 0, g[2] ?? 0);
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
/** Whether `net` may connect to an address: an IP address, not blocked, and carrying none that is. */
|
|
86
|
-
export function isPublicAddress(address, blocked = blockedAddresses()) {
|
|
87
|
-
const family = isIP(address);
|
|
88
|
-
if (family === 0)
|
|
89
|
-
return false;
|
|
90
|
-
if (blocked.check(address, family === 6 ? "ipv6" : "ipv4"))
|
|
91
|
-
return false;
|
|
92
|
-
const carried = family === 6 ? carriedIPv4(address) : undefined;
|
|
93
|
-
return !carried || !blocked.check(carried, "ipv4");
|
|
94
|
-
}
|
|
95
|
-
/** Headers that describe one hop, not the message. */
|
|
96
|
-
const HOP = new Set([
|
|
97
|
-
"connection",
|
|
98
|
-
"keep-alive",
|
|
99
|
-
"transfer-encoding",
|
|
100
|
-
"te",
|
|
101
|
-
"trailer",
|
|
102
|
-
"upgrade",
|
|
103
|
-
"proxy-authenticate",
|
|
104
|
-
"proxy-authorization",
|
|
105
|
-
"proxy-connection",
|
|
106
|
-
"host",
|
|
107
|
-
]);
|
|
108
|
-
/**
|
|
109
|
-
* An upstream response's headers for the consumer: hop-by-hop ones dropped, and the SDK's error
|
|
110
|
-
* header too, so no server out there can make the consumer's fetch throw.
|
|
111
|
-
*/
|
|
112
|
-
function responseHeaders(raw) {
|
|
113
|
-
const headers = new Headers();
|
|
114
|
-
for (const [name, value] of Object.entries(raw)) {
|
|
115
|
-
const lower = name.toLowerCase();
|
|
116
|
-
if (HOP.has(lower) || lower === ERROR_HEADER)
|
|
117
|
-
continue;
|
|
118
|
-
if (Array.isArray(value))
|
|
119
|
-
for (const one of value)
|
|
120
|
-
headers.append(name, one);
|
|
121
|
-
else if (value !== undefined)
|
|
122
|
-
headers.set(name, value);
|
|
123
|
-
}
|
|
124
|
-
return headers;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The built-in `net` Actor's `http.egress@1`: a consumer's request, made from the Hub's process to
|
|
128
|
-
* the public internet over HTTPS. The host is resolved and every address checked; the connection
|
|
129
|
-
* goes to the checked address (with the name for SNI and the certificate), so a second resolution
|
|
130
|
-
* can't move it. Redirects come back as they are. Each request's method, host and status are
|
|
131
|
-
* audited; bodies never are.
|
|
132
|
-
*/
|
|
133
|
-
export class Net {
|
|
134
|
-
#state;
|
|
135
|
-
#lookup;
|
|
136
|
-
#ca;
|
|
137
|
-
#idleMs;
|
|
138
|
-
#blocked;
|
|
139
|
-
constructor(state, options = {}) {
|
|
140
|
-
this.#state = state;
|
|
141
|
-
this.#lookup = options.lookup ?? ((host) => dnsLookup(host, { all: true, verbatim: true }));
|
|
142
|
-
this.#ca = options.ca ? [...rootCertificates, options.ca] : undefined;
|
|
143
|
-
this.#idleMs = options.idleMs ?? 5 * 60_000;
|
|
144
|
-
this.#blocked = options.blocked ?? blockedAddresses();
|
|
145
|
-
}
|
|
146
|
-
/** One request, for the consumer's slot. Refusals and failures throw the SDK's errors. */
|
|
147
|
-
async handle(request, by) {
|
|
148
|
-
const url = new URL(request.url);
|
|
149
|
-
const audit = (outcome) => {
|
|
150
|
-
try {
|
|
151
|
-
this.#state.auditHub("net.request", { ...by, method: request.method, host: url.host, ...outcome }, NET);
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
// The state is closed: the Hub is shutting down.
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
try {
|
|
158
|
-
const response = await this.#send(request, url);
|
|
159
|
-
audit({ status: response.status });
|
|
160
|
-
return response;
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
audit({ error: error instanceof Refused ? error.code : error.name });
|
|
164
|
-
throw error;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
async #send(request, url) {
|
|
168
|
-
if (url.protocol !== "https:")
|
|
169
|
-
throw new Refused("forbidden", `net reaches only https: URLs, not ${url.protocol}.`);
|
|
170
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
171
|
-
let addresses;
|
|
172
|
-
if (isIP(host))
|
|
173
|
-
addresses = [{ address: host, family: isIP(host) }];
|
|
174
|
-
else
|
|
175
|
-
try {
|
|
176
|
-
addresses = await this.#lookup(host);
|
|
177
|
-
}
|
|
178
|
-
catch {
|
|
179
|
-
throw new Refused("unreachable", `${host} doesn't resolve.`);
|
|
180
|
-
}
|
|
181
|
-
if (!addresses.length)
|
|
182
|
-
throw new Refused("unreachable", `${host} doesn't resolve.`);
|
|
183
|
-
for (const { address } of addresses)
|
|
184
|
-
if (!isPublicAddress(address, this.#blocked))
|
|
185
|
-
throw new Refused("forbidden", `${host} is at ${address}, which isn't on the public internet.`);
|
|
186
|
-
const target = addresses[0];
|
|
187
|
-
const sendsBody = Boolean(request.body) && request.method !== "GET" && request.method !== "HEAD";
|
|
188
|
-
const headers = {};
|
|
189
|
-
request.headers.forEach((value, name) => {
|
|
190
|
-
if (HOP.has(name) || name === "set-cookie")
|
|
191
|
-
return;
|
|
192
|
-
// The length comes from the body net sends, which is none for GET and HEAD.
|
|
193
|
-
if (name === "content-length" || name === "expect")
|
|
194
|
-
return;
|
|
195
|
-
headers[name] = value;
|
|
196
|
-
});
|
|
197
|
-
headers.host = url.host;
|
|
198
|
-
return new Promise((resolve, reject) => {
|
|
199
|
-
/** Whether anything may have reached the server: from the TLS handshake on. */
|
|
200
|
-
let connected = false;
|
|
201
|
-
const options = {
|
|
202
|
-
host,
|
|
203
|
-
port: Number(url.port || 443),
|
|
204
|
-
path: `${url.pathname}${url.search}`,
|
|
205
|
-
method: request.method,
|
|
206
|
-
headers,
|
|
207
|
-
agent: false,
|
|
208
|
-
...(this.#ca ? { ca: this.#ca } : {}),
|
|
209
|
-
// Every address was checked: the connection goes to one of them (node falls back between
|
|
210
|
-
// them), never to a new lookup.
|
|
211
|
-
lookup: (_name, options, callback) => {
|
|
212
|
-
if (options.all)
|
|
213
|
-
callback(null, addresses);
|
|
214
|
-
else
|
|
215
|
-
callback(null, target.address, target.family);
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
const outgoing = httpsRequest(options, (incoming) => {
|
|
219
|
-
const status = incoming.statusCode ?? 0;
|
|
220
|
-
// Whatever a server out there answers, it ends as a response or an error, never a throw
|
|
221
|
-
// in this process.
|
|
222
|
-
try {
|
|
223
|
-
if (status < 200 || status > 599)
|
|
224
|
-
throw new Error(`a status of ${status}`);
|
|
225
|
-
const empty = request.method === "HEAD" || status === 204 || status === 205 || status === 304;
|
|
226
|
-
const response = new Response(empty ? null : Readable.toWeb(incoming), {
|
|
227
|
-
status,
|
|
228
|
-
statusText: incoming.statusMessage ?? "",
|
|
229
|
-
headers: responseHeaders(incoming.headers),
|
|
230
|
-
});
|
|
231
|
-
if (empty)
|
|
232
|
-
incoming.resume();
|
|
233
|
-
resolve(response);
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
incoming.destroy();
|
|
237
|
-
reject(new OutcomeUnknown(`${url.host} answered what isn't an HTTP response net passes on: ${error.message}`));
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
// An upgrade nobody asked for: the request had reached the server.
|
|
241
|
-
outgoing.on("upgrade", (_response, socket) => {
|
|
242
|
-
socket.destroy();
|
|
243
|
-
reject(new OutcomeUnknown(`${url.host} switched protocols, which net doesn't follow.`));
|
|
244
|
-
});
|
|
245
|
-
outgoing.on("socket", (socket) => socket.once("secureConnect", () => (connected = true)));
|
|
246
|
-
// Before the TLS handshake is done nothing has been sent, so a quiet server is unreachable.
|
|
247
|
-
outgoing.setTimeout(this.#idleMs, () => outgoing.destroy(connected
|
|
248
|
-
? new OutcomeUnknown(`${url.host} sent nothing for ${this.#idleMs / 1000} s.`)
|
|
249
|
-
: new Refused("unreachable", `${url.host} didn't finish connecting within ${this.#idleMs / 1000} s.`)));
|
|
250
|
-
outgoing.on("error", (error) => reject(error instanceof OutcomeUnknown || error instanceof Refused
|
|
251
|
-
? error
|
|
252
|
-
: connected
|
|
253
|
-
? new OutcomeUnknown(`The request to ${url.host} failed: ${error.message}`)
|
|
254
|
-
: new Refused("unreachable", `${url.host} couldn't be reached: ${error.message}`)));
|
|
255
|
-
const abort = () => outgoing.destroy(request.signal.reason ?? new Error("aborted"));
|
|
256
|
-
if (request.signal.aborted)
|
|
257
|
-
return abort();
|
|
258
|
-
request.signal.addEventListener("abort", abort, { once: true });
|
|
259
|
-
outgoing.once("close", () => request.signal.removeEventListener("abort", abort));
|
|
260
|
-
if (!sendsBody || !request.body)
|
|
261
|
-
return void outgoing.end();
|
|
262
|
-
pipeline(Readable.fromWeb(request.body), outgoing).catch((error) => outgoing.destroy(error));
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|