@wenathlan/saddle 2.0.154 → 2.0.159
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/Dockerfile +167 -1334
- package/README.md +59 -60
- package/biome.jsonc +3 -3
- package/browser.ts +482 -0
- package/cli.ts +274 -0
- package/distribution.ts +731 -0
- package/docker.config +29 -8
- package/docs/{architecture.1.8.19.mmd → architecture1819.md} +6 -0
- package/docs/artifactavailability.md +2 -2
- package/docs/browser.md +18 -1
- package/docs/{containerplatforms.2.1.0.md → containerplatforms210.md} +1 -1
- package/docs/{documentmap.1.8.12.md → documentmap1812.md} +1 -1
- package/docs/extension.md +13 -2
- package/docs/features.md +5 -0
- package/docs/libraryapi.md +1 -1
- package/docs/{ninety.modalities.md → ninetymodalities.md} +87 -4
- package/docs/{planning.ninety.md → planningninety.md} +6 -6
- package/docs/{releasenotes.1.8.13.md → releasenotes1813.md} +2 -2
- package/docs/{releasenotes.1.8.14.md → releasenotes1814.md} +1 -1
- package/docs/{repo.synthesis.1.8.16.md → reposynthesis1816.md} +1 -1
- package/docs/todo.md +2 -2
- package/docs/{todo.1.8.15.md → todo1815.md} +1 -1
- package/docs/{todo.1.8.16.md → todo1816.md} +5 -5
- package/execution.ts +677 -0
- package/foundation.ts +314 -0
- package/index.ts +36 -34
- package/isolation.ts +84 -0
- package/modalityregistry.ts +189 -145
- package/modes.ts +170 -0
- package/mttg.config +1 -1
- package/orchestrator.ts +49 -15
- package/package.json +105 -89
- package/qemu.config +2 -2
- package/sandbox.ts +3279 -0
- package/scheduler.ts +1 -1
- package/server.ts +52 -0
- package/tsconfig.json +12 -13
- package/virtual.ts +7528 -0
- package/workloadlaw.ts +293 -0
- package/dist/App.d.ts +0 -5
- package/dist/App.js +0 -52
- package/dist/Sol/Sol.d.ts +0 -3
- package/dist/Sol/Sol.js +0 -46
- package/dist/Sol/agentbrowser/agentbrowser.d.ts +0 -9
- package/dist/Sol/agentbrowser/agentbrowser.js +0 -121
- package/dist/Sol/architecture/architecture.d.ts +0 -9
- package/dist/Sol/architecture/architecture.js +0 -93
- package/dist/Sol/compute/compute.d.ts +0 -9
- package/dist/Sol/compute/compute.js +0 -22
- package/dist/Sol/console/console.d.ts +0 -15
- package/dist/Sol/console/console.js +0 -292
- package/dist/Sol/dashboard/dashboard.d.ts +0 -10
- package/dist/Sol/dashboard/dashboard.js +0 -181
- package/dist/Sol/docs/docs.d.ts +0 -9
- package/dist/Sol/docs/docs.js +0 -28
- package/dist/Sol/home/home.d.ts +0 -35
- package/dist/Sol/home/home.js +0 -239
- package/dist/Sol/integrations/integrations.d.ts +0 -9
- package/dist/Sol/integrations/integrations.js +0 -83
- package/dist/Sol/intro/intro.d.ts +0 -7
- package/dist/Sol/intro/intro.js +0 -102
- package/dist/Sol/login/login.d.ts +0 -16
- package/dist/Sol/login/login.js +0 -49
- package/dist/Sol/notfound/notfound.d.ts +0 -9
- package/dist/Sol/notfound/notfound.js +0 -15
- package/dist/Sol/onboarding/onboarding.d.ts +0 -25
- package/dist/Sol/onboarding/onboarding.js +0 -60
- package/dist/Sol/playground/playground.d.ts +0 -9
- package/dist/Sol/playground/playground.js +0 -127
- package/dist/Sol/register/register.d.ts +0 -16
- package/dist/Sol/register/register.js +0 -193
- package/dist/Sol/shell/Shell.d.ts +0 -124
- package/dist/Sol/shell/Shell.js +0 -335
- package/dist/Sol/wingets/ComputeBootladder.d.ts +0 -6
- package/dist/Sol/wingets/ComputeBootladder.js +0 -71
- package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +0 -7
- package/dist/Sol/wingets/ComputeModalitycatalog.js +0 -71
- package/dist/Sol/wingets/ConsoleApibadge.d.ts +0 -7
- package/dist/Sol/wingets/ConsoleApibadge.js +0 -5
- package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +0 -6
- package/dist/Sol/wingets/ConsoleEdgelaw.js +0 -36
- package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +0 -19
- package/dist/Sol/wingets/ConsoleEventstimeline.js +0 -12
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +0 -8
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +0 -8
- package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +0 -21
- package/dist/Sol/wingets/ConsoleSpecpanel.js +0 -75
- package/dist/Sol/wingets/ConsoleTerminal.d.ts +0 -22
- package/dist/Sol/wingets/ConsoleTerminal.js +0 -77
- package/dist/Sol/wingets/DashboardAccountpanel.d.ts +0 -18
- package/dist/Sol/wingets/DashboardAccountpanel.js +0 -65
- package/dist/Sol/wingets/DashboardAdminpanel.d.ts +0 -6
- package/dist/Sol/wingets/DashboardAdminpanel.js +0 -90
- package/dist/Sol/wingets/DashboardAuditlog.d.ts +0 -8
- package/dist/Sol/wingets/DashboardAuditlog.js +0 -50
- package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +0 -10
- package/dist/Sol/wingets/DashboardCreatesandboxform.js +0 -71
- package/dist/Sol/wingets/DashboardEventstimeline.d.ts +0 -8
- package/dist/Sol/wingets/DashboardEventstimeline.js +0 -83
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +0 -57
- package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardMeshnodestable.js +0 -103
- package/dist/Sol/wingets/DashboardSandboxlist.d.ts +0 -10
- package/dist/Sol/wingets/DashboardSandboxlist.js +0 -163
- package/dist/Sol/wingets/DashboardUserstable.d.ts +0 -8
- package/dist/Sol/wingets/DashboardUserstable.js +0 -78
- package/dist/Sol/wingets/HomeEntrygate.d.ts +0 -23
- package/dist/Sol/wingets/HomeEntrygate.js +0 -73
- package/dist/Sol/wingets/HomeMetricstrip.d.ts +0 -9
- package/dist/Sol/wingets/HomeMetricstrip.js +0 -4
- package/dist/Sol/wingets/HomeRuntimediagram.d.ts +0 -1
- package/dist/Sol/wingets/HomeRuntimediagram.js +0 -22
- package/dist/Sol/wingets/LoginForm.d.ts +0 -19
- package/dist/Sol/wingets/LoginForm.js +0 -141
- package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +0 -13
- package/dist/Sol/wingets/RegisterPasswordconfirm.js +0 -16
- package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +0 -19
- package/dist/Sol/wingets/RegisterPasswordmeter.js +0 -65
- package/dist/Sol/wingets/RegisterUsernamerules.d.ts +0 -11
- package/dist/Sol/wingets/RegisterUsernamerules.js +0 -16
- package/dist/Sol/wingets/index.d.ts +0 -39
- package/dist/Sol/wingets/index.js +0 -39
- package/dist/alternatives.d.ts +0 -508
- package/dist/alternatives.js +0 -950
- package/dist/api.d.ts +0 -154
- package/dist/api.js +0 -174
- package/dist/auth.d.ts +0 -268
- package/dist/auth.js +0 -476
- package/dist/automation.d.ts +0 -425
- package/dist/automation.js +0 -566
- package/dist/browser.d.ts +0 -561
- package/dist/browser.js +0 -1058
- package/dist/capacitor.config.d.ts +0 -45
- package/dist/capacitor.config.js +0 -48
- package/dist/catalog.d.ts +0 -43
- package/dist/catalog.js +0 -44
- package/dist/cli.d.ts +0 -16
- package/dist/cli.js +0 -168
- package/dist/communication.d.ts +0 -181
- package/dist/communication.js +0 -376
- package/dist/compute.d.ts +0 -1160
- package/dist/compute.js +0 -2272
- package/dist/dashboardlib.d.ts +0 -58
- package/dist/dashboardlib.js +0 -161
- package/dist/db.d.ts +0 -569
- package/dist/db.js +0 -1080
- package/dist/distribution.d.ts +0 -528
- package/dist/distribution.js +0 -810
- package/dist/drizzle.config.d.ts +0 -20
- package/dist/drizzle.config.js +0 -18
- package/dist/edgelandes.d.ts +0 -70
- package/dist/edgelandes.host.d.ts +0 -26
- package/dist/edgelandes.host.js +0 -1089
- package/dist/edgelandes.inproc.d.ts +0 -27
- package/dist/edgelandes.inproc.js +0 -952
- package/dist/edgelandes.js +0 -1133
- package/dist/edgelandes.ninety.d.ts +0 -31
- package/dist/edgelandes.ninety.js +0 -174
- package/dist/edgelandes.virtual.d.ts +0 -25
- package/dist/edgelandes.virtual.js +0 -629
- package/dist/edgeplane.d.ts +0 -121
- package/dist/edgeplane.js +0 -341
- package/dist/examplelocaljob.d.ts +0 -1
- package/dist/examplelocaljob.js +0 -14
- package/dist/execution.d.ts +0 -529
- package/dist/execution.js +0 -760
- package/dist/family.d.ts +0 -16
- package/dist/family.js +0 -42
- package/dist/familyurl.d.ts +0 -21
- package/dist/familyurl.js +0 -24
- package/dist/format.d.ts +0 -18
- package/dist/format.js +0 -59
- package/dist/foundation.d.ts +0 -172
- package/dist/foundation.js +0 -312
- package/dist/index.d.ts +0 -735
- package/dist/index.js +0 -1020
- package/dist/integration.d.ts +0 -235
- package/dist/integration.js +0 -228
- package/dist/intelligence.d.ts +0 -93
- package/dist/intelligence.js +0 -144
- package/dist/isolation.d.ts +0 -128
- package/dist/isolation.js +0 -95
- package/dist/labels.d.ts +0 -665
- package/dist/labels.js +0 -707
- package/dist/localauth.d.ts +0 -127
- package/dist/localauth.js +0 -413
- package/dist/media.d.ts +0 -343
- package/dist/media.js +0 -985
- package/dist/mesh.d.ts +0 -177
- package/dist/mesh.js +0 -468
- package/dist/modalityregistry.d.ts +0 -109
- package/dist/modalityregistry.js +0 -1386
- package/dist/modes.d.ts +0 -358
- package/dist/modes.js +0 -133
- package/dist/onboardingstate.d.ts +0 -79
- package/dist/onboardingstate.js +0 -282
- package/dist/orchestrator.d.ts +0 -1338
- package/dist/orchestrator.js +0 -4310
- package/dist/packager/targetcli.js +0 -4
- package/dist/paths.d.ts +0 -2
- package/dist/paths.js +0 -14
- package/dist/performance.d.ts +0 -415
- package/dist/performance.js +0 -826
- package/dist/quantum.d.ts +0 -809
- package/dist/quantum.js +0 -2072
- package/dist/render.d.ts +0 -380
- package/dist/render.js +0 -1072
- package/dist/runall.d.ts +0 -2
- package/dist/runall.js +0 -39
- package/dist/runtimeprobe.d.ts +0 -4
- package/dist/runtimeprobe.js +0 -8
- package/dist/sandbox.d.ts +0 -355
- package/dist/sandbox.js +0 -1721
- package/dist/sandboxenvprofile.d.ts +0 -29
- package/dist/sandboxenvprofile.js +0 -89
- package/dist/sandboxprofile.d.ts +0 -137
- package/dist/sandboxprofile.js +0 -241
- package/dist/sandboxqueue.d.ts +0 -108
- package/dist/sandboxqueue.js +0 -201
- package/dist/sandboxquota.d.ts +0 -121
- package/dist/sandboxquota.js +0 -236
- package/dist/scheduler.d.ts +0 -595
- package/dist/scheduler.js +0 -1258
- package/dist/scriptlanes.d.ts +0 -182
- package/dist/scriptlanes.js +0 -660
- package/dist/scripts.buildengine.d.ts +0 -1
- package/dist/scripts.buildengine.js +0 -39
- package/dist/scripts.securitygate.d.ts +0 -1
- package/dist/scripts.securitygate.js +0 -68
- package/dist/scripts.validateflatnative.d.ts +0 -1
- package/dist/scripts.validateflatnative.js +0 -72
- package/dist/security.d.ts +0 -500
- package/dist/security.js +0 -1169
- package/dist/seedcatalog.d.ts +0 -13
- package/dist/seedcatalog.js +0 -46
- package/dist/server.d.ts +0 -20
- package/dist/server.js +0 -53
- package/dist/speccatalog.d.ts +0 -31
- package/dist/speccatalog.js +0 -163
- package/dist/tiers.d.ts +0 -1001
- package/dist/tiers.js +0 -2169
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +0 -5
- package/dist/vaulthandoff.d.ts +0 -141
- package/dist/vaulthandoff.js +0 -444
- package/dist/virtual.d.ts +0 -640
- package/dist/virtual.js +0 -1284
- package/dist/virtualcpu.d.ts +0 -315
- package/dist/virtualcpu.js +0 -1180
- package/dist/virtualgpu.d.ts +0 -344
- package/dist/virtualgpu.js +0 -1000
- package/dist/virtualization.d.ts +0 -606
- package/dist/virtualization.js +0 -1186
- package/dist/virtualmemory.d.ts +0 -817
- package/dist/virtualmemory.js +0 -1795
- package/dist/vite.config.d.ts +0 -3
- package/dist/vite.config.js +0 -48
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -25
- package/dist/webserver.d.ts +0 -166
- package/dist/webserver.js +0 -2226
- package/dist/workloadlaw.d.ts +0 -133
- package/dist/workloadlaw.js +0 -193
- package/docs/.gitkeep +0 -0
- package/docs/architecture.1.8.19.md +0 -76
- package/docs/logs/examplesession.json +0 -54
- package/docs/repo.analysis.1.8.21.json +0 -2617
- package/docs/repo.candidates.1.8.21.jsonl +0 -666
- package/docs/repo.selected.1.8.21.json +0 -786
- package/manifest.json +0 -20
- package/media.ts +0 -1337
- package/virtualcpu.ts +0 -1274
- package/virtualgpu.ts +0 -1182
- package/virtualization.ts +0 -1628
- package/virtualmemory.ts +0 -2303
- /package/docs/{artifactresearch.1.8.9.md → artifactresearch189.md} +0 -0
- /package/docs/{batches.1816.to.1820.md → batches1816to1820.md} +0 -0
- /package/docs/{brancharchive.2026.08.18.md → brancharchive20260818.md} +0 -0
- /package/docs/{containerplatforms.1.8.17.md → containerplatforms1817.md} +0 -0
- /package/docs/{e2ugh.engine.md → e2ughengine.md} +0 -0
- /package/docs/{flatbuildresearch.1.8.11.md → flatbuildresearch1811.md} +0 -0
- /package/docs/{licenseaudit.1.8.12.md → licenseaudit1812.md} +0 -0
- /package/docs/{mobileconversionresearch.1.8.10.md → mobileconversionresearch1810.md} +0 -0
- /package/docs/{nativeidentityresearch.1.8.11.md → nativeidentityresearch1811.md} +0 -0
- /package/docs/{native.wrappers.md → nativewrappers.md} +0 -0
- /package/docs/{planning.1.8.18.md → planning1818.md} +0 -0
- /package/docs/{planning.1.8.19.md → planning1819.md} +0 -0
- /package/docs/{planning.engine.md → planningengine.md} +0 -0
- /package/docs/{releasenotes.1.8.12.md → releasenotes1812.md} +0 -0
- /package/docs/{releasenotes.1.8.15.md → releasenotes1815.md} +0 -0
- /package/docs/{releasenotes.1.8.16.md → releasenotes1816.md} +0 -0
- /package/docs/{releasenotes.1.8.17.md → releasenotes1817.md} +0 -0
- /package/docs/{releasenotes.1.8.18.md → releasenotes1818.md} +0 -0
- /package/docs/{releasenotes.1.8.19.md → releasenotes1819.md} +0 -0
- /package/docs/{reorganization.1.8.8.md → reorganization188.md} +0 -0
- /package/docs/{reorganization.1.8.9.md → reorganization189.md} +0 -0
- /package/docs/{repo.research.1.8.16.md → reporesearch1816.md} +0 -0
- /package/docs/{repo.research.1.8.21.md → reporesearch1821.md} +0 -0
- /package/docs/{repo.synthesis.1.8.21.md → reposynthesis1821.md} +0 -0
- /package/docs/{research.1.8.18.isolation.md → research1818isolation.md} +0 -0
- /package/docs/{research.1.8.19.virtual.browser.md → research1819virtualbrowser.md} +0 -0
- /package/docs/{scanningresearch.1.8.11.md → scanningresearch1811.md} +0 -0
- /package/docs/{securityaudit.1.8.7.md → securityaudit187.md} +0 -0
- /package/docs/{securityreferences.1.8.11.md → securityreferences1811.md} +0 -0
- /package/docs/{securityresearch.1.8.11.md → securityresearch1811.md} +0 -0
- /package/docs/{signingresearch.1.8.12.md → signingresearch1812.md} +0 -0
- /package/docs/{tauri.glib.risk.1.8.11.md → tauriglibrisk1811.md} +0 -0
- /package/docs/{todo.1.8.18.md → todo1818.md} +0 -0
- /package/docs/{todo.1.8.19.md → todo1819.md} +0 -0
- /package/docs/{toolchainresearch.1.8.9.md → toolchainresearch189.md} +0 -0
- /package/docs/{web.duplicatecleanup.md → webduplicatecleanup.md} +0 -0
- /package/docs/{web.ideas.md → webideas.md} +0 -0
- /package/docs/{workflowimprovements.2026.08.19.md → workflowimprovements20260819.md} +0 -0
package/foundation.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* foundation.ts — foundation errors, events, identifiers, hashing and serializable domain nouns.
|
|
3
|
+
*
|
|
4
|
+
* This file is the v2.0.0 grand-merge consolidation of the former nested
|
|
5
|
+
* folders of the repository (core) into the single
|
|
6
|
+
* root-level domain file of the saddle family standard: one optimized
|
|
7
|
+
* TypeScript file per correlated domain, ordinal sections, JSDoc on every
|
|
8
|
+
* block, intra-domain imports dissolved, cross-domain imports rewritten to
|
|
9
|
+
* ./<domain>.js. Every capability of every source file is preserved here;
|
|
10
|
+
* the pure re-export barrels (none in this domain) folded their surface into this file directly.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
16
|
+
/* Section 1: core/errors.ts — typed engine errors keep recovery decisions explicit. */
|
|
17
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
18
|
+
/**
|
|
19
|
+
* typed engine errors keep recovery decisions explicit.
|
|
20
|
+
*/
|
|
21
|
+
export const errorcodes = Object.freeze({
|
|
22
|
+
invalidinput: "INVALID_INPUT",
|
|
23
|
+
artifactnotfound: "ARTIFACT_NOT_FOUND",
|
|
24
|
+
storagefailure: "STORAGE_FAILURE",
|
|
25
|
+
runnerunavailable: "RUNNER_UNAVAILABLE",
|
|
26
|
+
jobfailed: "JOB_FAILED",
|
|
27
|
+
sessioninvalid: "SESSION_INVALID"
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export function saddleerror(message, options = {}) {
|
|
31
|
+
const error = new Error(message, { cause: options.cause });
|
|
32
|
+
error.name = "saddleerror";
|
|
33
|
+
error.code = options.code ?? errorcodes.jobfailed;
|
|
34
|
+
error.retryable = options.retryable ?? false;
|
|
35
|
+
error.details = options.details ?? {};
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function validationerror(message, details = {}) {
|
|
40
|
+
return saddleerror(message, { code: errorcodes.invalidinput, details });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function artifactnotfound(key) {
|
|
44
|
+
return saddleerror(`artifact not found: ${key}`, { code: errorcodes.artifactnotfound, details: { key } });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function runnerunavailable(jobid) {
|
|
48
|
+
return saddleerror(`no runner is available for job ${jobid}`, { code: errorcodes.runnerunavailable, retryable: true, details: { jobid } });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function aserror(error, jobid) {
|
|
52
|
+
if (error?.name === "saddleerror") return error;
|
|
53
|
+
return saddleerror(`job ${jobid} failed`, { code: errorcodes.jobfailed, cause: error, details: { jobid } });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Operational error presets keep status, recovery and retry decisions
|
|
57
|
+
* explicit for the engine's outbound lanes (registry pulls, runner
|
|
58
|
+
* handshakes, package fetches); the presets answer the sandbox engine
|
|
59
|
+
* only — the scrape lanes that once consumed them left the package. */
|
|
60
|
+
export const errorcatalog = Object.freeze({
|
|
61
|
+
timeout: { code: "E1001", statuscode: 504, retryable: true, recovery: "WAIT_AND_RETRY" },
|
|
62
|
+
connectionrefused: { code: "E1002", statuscode: 503, retryable: true, recovery: "WAIT_AND_RETRY" },
|
|
63
|
+
dns: { code: "E1003", statuscode: 503, retryable: true, recovery: "WAIT_AND_RETRY" },
|
|
64
|
+
ratelimited: { code: "E2001", statuscode: 429, retryable: true, recovery: "WAIT_AND_RETRY" },
|
|
65
|
+
forbidden: { code: "E2002", statuscode: 403, retryable: false, recovery: "REVIEW_CREDENTIALS" },
|
|
66
|
+
notfound: { code: "E2003", statuscode: 404, retryable: false, recovery: "ABANDON" },
|
|
67
|
+
parse: { code: "E4002", statuscode: 422, retryable: false, recovery: "ABANDON" },
|
|
68
|
+
session: { code: "E5001", statuscode: 401, retryable: true, recovery: "REFRESH_SESSION" },
|
|
69
|
+
config: { code: "E6001", statuscode: 400, retryable: false, recovery: "ABANDON" }
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** Creates a stable operational error with recovery metadata. */
|
|
73
|
+
export function operationerror(kind, message, options = {}) { const preset = errorcatalog[kind] ?? errorcatalog.config; const error = new Error(message, { cause: options.cause }); error.name = "operationerror"; error.code = options.code ?? preset.code; error.statuscode = options.statuscode ?? preset.statuscode; error.retryable = options.retryable ?? preset.retryable; error.recovery = options.recovery ?? preset.recovery; error.severity = options.severity ?? (error.statuscode >= 500 ? "high" : "medium"); error.details = options.details ?? {}; return error; }
|
|
74
|
+
|
|
75
|
+
/** Converts unknown failures into the stable operational taxonomy. */
|
|
76
|
+
export function classifyerror(error) { if (error?.name === "operationerror") return error; const message = String(error?.message ?? error); if (/timeout|aborted/i.test(message)) return operationerror("timeout", message, { cause: error }); if (/dns|enotfound/i.test(message)) return operationerror("dns", message, { cause: error }); return operationerror("config", message, { cause: error }); }
|
|
77
|
+
|
|
78
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
79
|
+
/* Section 2: core/events.ts — append only events are the small protocol shared by adapters. */
|
|
80
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
81
|
+
/**
|
|
82
|
+
* append only events are the small protocol shared by adapters.
|
|
83
|
+
*/
|
|
84
|
+
export const eventtypes = Object.freeze([
|
|
85
|
+
"jobqueued",
|
|
86
|
+
"jobpreparing",
|
|
87
|
+
"runnerselected",
|
|
88
|
+
"jobrunning",
|
|
89
|
+
"jobsyncing",
|
|
90
|
+
"storagecommitted",
|
|
91
|
+
"jobcompleted",
|
|
92
|
+
"jobfailed"
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
export function eventbus() {
|
|
96
|
+
const recorded = [];
|
|
97
|
+
return {
|
|
98
|
+
emit(event) { recorded.push(Object.freeze({ ...event })); },
|
|
99
|
+
all() { return [...recorded]; }
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
104
|
+
/* Section 3: core/ids.ts — injectable time and id factories make every engine path reproducible. */
|
|
105
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
106
|
+
/**
|
|
107
|
+
* injectable time and id factories make every engine path reproducible.
|
|
108
|
+
*/
|
|
109
|
+
export function systemclock() {
|
|
110
|
+
return { now: () => Date.now() };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function idfactory(randomuuid = globalThis.crypto?.randomUUID?.bind(globalThis.crypto)) {
|
|
114
|
+
return {
|
|
115
|
+
next(prefix) {
|
|
116
|
+
const suffix = randomuuid?.() ?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
117
|
+
return `${prefix}${suffix}`;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
123
|
+
/* Section 4: core/hash.ts — hash helpers use standard JavaScript primitives so transport-neutral modules do not require node:crypto. */
|
|
124
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
125
|
+
/**
|
|
126
|
+
* hash helpers use standard JavaScript primitives so transport-neutral modules do not require node:crypto.
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
const constants = Object.freeze([
|
|
130
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
131
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
132
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
133
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
134
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
135
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
136
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
137
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
/** Returns a SHA-256 hexadecimal digest for bytes or text. */
|
|
141
|
+
export function sha256(value) { return tohex(hashbytes(value)); }
|
|
142
|
+
|
|
143
|
+
/** Returns an HMAC-SHA-256 hexadecimal digest for bytes or text. */
|
|
144
|
+
export function hmacsha256(value, secret) {
|
|
145
|
+
let key = tobytes(secret);
|
|
146
|
+
if (key.length > 64) key = hashbytes(key);
|
|
147
|
+
const padded = new Uint8Array(64);
|
|
148
|
+
padded.set(key);
|
|
149
|
+
const outer = new Uint8Array(64);
|
|
150
|
+
const inner = new Uint8Array(64);
|
|
151
|
+
for (let index = 0; index < 64; index += 1) { outer[index] = padded[index] ^ 0x5c; inner[index] = padded[index] ^ 0x36; }
|
|
152
|
+
return sha256(concat(outer, hashbytes(concat(inner, tobytes(value)))));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Compares hexadecimal values without early exit based on content. */
|
|
156
|
+
export function constanttimeequal(left, right) { const a = String(left ?? ""); const b = String(right ?? ""); let difference = a.length ^ b.length; const length = Math.max(a.length, b.length); for (let index = 0; index < length; index += 1) difference |= (a.charCodeAt(index) || 0) ^ (b.charCodeAt(index) || 0); return difference === 0; }
|
|
157
|
+
|
|
158
|
+
function hashbytes(value) {
|
|
159
|
+
const input = tobytes(value);
|
|
160
|
+
const bitlength = BigInt(input.length) * 8n;
|
|
161
|
+
const length = Math.ceil((input.length + 9) / 64) * 64;
|
|
162
|
+
const padded = new Uint8Array(length);
|
|
163
|
+
padded.set(input);
|
|
164
|
+
padded[input.length] = 0x80;
|
|
165
|
+
const inputview = new DataView(padded.buffer);
|
|
166
|
+
inputview.setUint32(length - 8, Number((bitlength >> 32n) & 0xffffffffn));
|
|
167
|
+
inputview.setUint32(length - 4, Number(bitlength & 0xffffffffn));
|
|
168
|
+
const state = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);
|
|
169
|
+
const words = new Uint32Array(64);
|
|
170
|
+
for (let offset = 0; offset < length; offset += 64) {
|
|
171
|
+
for (let index = 0; index < 16; index += 1) words[index] = inputview.getUint32(offset + index * 4);
|
|
172
|
+
for (let index = 16; index < 64; index += 1) {
|
|
173
|
+
const sigma0 = smallright(words[index - 15], 7) ^ smallright(words[index - 15], 18) ^ (words[index - 15] >>> 3);
|
|
174
|
+
const sigma1 = smallright(words[index - 2], 17) ^ smallright(words[index - 2], 19) ^ (words[index - 2] >>> 10);
|
|
175
|
+
words[index] = (sigma1 + words[index - 7] + sigma0 + words[index - 16]) >>> 0;
|
|
176
|
+
}
|
|
177
|
+
let [a, b, c, d, e, f, g, h] = state;
|
|
178
|
+
for (let index = 0; index < 64; index += 1) {
|
|
179
|
+
const choose = (e & f) ^ (~e & g);
|
|
180
|
+
const majority = (a & b) ^ (a & c) ^ (b & c);
|
|
181
|
+
const first = (h + (smallright(e, 6) ^ smallright(e, 11) ^ smallright(e, 25)) + choose + constants[index] + words[index]) >>> 0;
|
|
182
|
+
const second = ((smallright(a, 2) ^ smallright(a, 13) ^ smallright(a, 22)) + majority) >>> 0;
|
|
183
|
+
[h, g, f, e, d, c, b, a] = [g, f, e, (d + first) >>> 0, c, b, a, (first + second) >>> 0];
|
|
184
|
+
}
|
|
185
|
+
state[0] = (state[0] + a) >>> 0; state[1] = (state[1] + b) >>> 0; state[2] = (state[2] + c) >>> 0; state[3] = (state[3] + d) >>> 0;
|
|
186
|
+
state[4] = (state[4] + e) >>> 0; state[5] = (state[5] + f) >>> 0; state[6] = (state[6] + g) >>> 0; state[7] = (state[7] + h) >>> 0;
|
|
187
|
+
}
|
|
188
|
+
const output = new Uint8Array(32);
|
|
189
|
+
const view = new DataView(output.buffer);
|
|
190
|
+
state.forEach((word, index) => {
|
|
191
|
+
view.setUint32(index * 4, word);
|
|
192
|
+
});
|
|
193
|
+
return output;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function tobytes(value) { if (value instanceof Uint8Array) return value; if (value instanceof ArrayBuffer) return new Uint8Array(value); return new TextEncoder().encode(String(value ?? "")); }
|
|
197
|
+
function concat(left, right) { const result = new Uint8Array(left.length + right.length); result.set(left); result.set(right, left.length); return result; }
|
|
198
|
+
function smallright(value, amount) { return (value >>> amount) | (value << (32 - amount)); }
|
|
199
|
+
function tohex(value) { return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join(""); }
|
|
200
|
+
|
|
201
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
202
|
+
/* Section 5: core/artifacts.ts — artifacts are serializable manifests with content checksums. */
|
|
203
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
204
|
+
/**
|
|
205
|
+
* artifacts are serializable manifests with content checksums.
|
|
206
|
+
*/
|
|
207
|
+
export function artifactmanifest(input) {
|
|
208
|
+
return {
|
|
209
|
+
key: input.key,
|
|
210
|
+
sizebytes: input.sizebytes,
|
|
211
|
+
sha256: input.sha256,
|
|
212
|
+
contenttype: input.contenttype,
|
|
213
|
+
createdat: input.createdat,
|
|
214
|
+
metadata: { ...(input.metadata ?? {}) }
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
219
|
+
/* Section 6: core/jobs.ts — job creation is kept small and side effect free. */
|
|
220
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
221
|
+
/**
|
|
222
|
+
* job creation is kept small and side effect free.
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
export const jobstatuses = Object.freeze(["queued", "preparing", "running", "syncing", "completed", "failed", "cancelled"]);
|
|
226
|
+
|
|
227
|
+
export function createjob(spec, ids, clock) {
|
|
228
|
+
if (!spec?.name || !spec.name.trim()) throw validationerror("job name cannot be empty");
|
|
229
|
+
return {
|
|
230
|
+
id: ids.next("job"),
|
|
231
|
+
name: spec.name,
|
|
232
|
+
input: spec.input,
|
|
233
|
+
priority: spec.priority ?? 0,
|
|
234
|
+
outputkey: spec.outputkey,
|
|
235
|
+
metadata: { ...(spec.metadata ?? {}) },
|
|
236
|
+
status: "queued",
|
|
237
|
+
createdat: clock.now()
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
242
|
+
/* Section 7: core/providers.ts — providers declare capacity while scheduling remains a runtime decision. */
|
|
243
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
244
|
+
/**
|
|
245
|
+
* providers declare capacity while scheduling remains a runtime decision.
|
|
246
|
+
*/
|
|
247
|
+
export const runnerstatuses = Object.freeze(["available", "busy", "offline"]);
|
|
248
|
+
|
|
249
|
+
export function runnercontext(job, workingset, signal) {
|
|
250
|
+
return { job, workingset, signal };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
254
|
+
/* Section 8: core/runtime.ts — runtime records describe temporary process space without claiming physical vram. */
|
|
255
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
256
|
+
/**
|
|
257
|
+
* runtime records describe temporary process space without claiming physical vram.
|
|
258
|
+
*/
|
|
259
|
+
export function workingset(jobid, location, resultpath, createdat = Date.now()) {
|
|
260
|
+
return { jobid, location, resultpath, createdat };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function syncresult(bytes, location) {
|
|
264
|
+
return { bytes, location };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
268
|
+
/* Section 9: core/sessions.ts — session logs are versioned and validated before any replay adapter sees them. */
|
|
269
|
+
/* ════════════════════════════════════════════════════════════════════ */
|
|
270
|
+
/**
|
|
271
|
+
* session logs are versioned and validated before any replay adapter sees them.
|
|
272
|
+
*/
|
|
273
|
+
|
|
274
|
+
const sessioneventtypes = new Set(["move", "click", "drag", "scroll", "key"]);
|
|
275
|
+
|
|
276
|
+
export function validatesession(value) {
|
|
277
|
+
if (!value || typeof value !== "object") throw validationerror("session must be an object");
|
|
278
|
+
if (value.version !== 1 || typeof value.id !== "string" || typeof value.agentname !== "string" || typeof value.originurl !== "string" || typeof value.seed !== "string") throw validationerror("session header is invalid");
|
|
279
|
+
if (!Array.isArray(value.events)) throw validationerror("session events must be an array");
|
|
280
|
+
if (!["created", "recording", "closed"].includes(value.status)) throw validationerror("session status is invalid");
|
|
281
|
+
if (!Number.isFinite(value.startedat) || value.startedat < 0) throw validationerror("session startedat is invalid");
|
|
282
|
+
return {
|
|
283
|
+
version: 1,
|
|
284
|
+
id: value.id,
|
|
285
|
+
agentname: value.agentname,
|
|
286
|
+
originurl: value.originurl,
|
|
287
|
+
seed: value.seed,
|
|
288
|
+
status: value.status,
|
|
289
|
+
startedat: value.startedat,
|
|
290
|
+
finishedat: Number.isFinite(value.finishedat) ? value.finishedat : undefined,
|
|
291
|
+
events: value.events.map((event, index) => validateevent(event, index))
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function validateevent(value, index) {
|
|
296
|
+
if (!value || typeof value !== "object" || !Number.isFinite(value.t) || value.t < 0 || !sessioneventtypes.has(value.type)) throw validationerror(`session event ${index} is invalid`);
|
|
297
|
+
for (const name of ["x", "y", "tx", "ty", "dx", "dy"]) if (value[name] !== undefined && !Number.isFinite(value[name])) throw validationerror(`session event ${index} ${name} is invalid`);
|
|
298
|
+
if (value.key !== undefined && typeof value.key !== "string") throw validationerror(`session event ${index} key is invalid`);
|
|
299
|
+
if (value.target !== undefined && typeof value.target !== "string") throw validationerror(`session event ${index} target is invalid`);
|
|
300
|
+
if (value.button !== undefined && !["left", "right"].includes(value.button)) throw validationerror(`session event ${index} button is invalid`);
|
|
301
|
+
const context = validatecontext(value.context ?? value, index);
|
|
302
|
+
return context ? { ...value, context } : { ...value };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function validatecontext(value, index) {
|
|
306
|
+
if (value.context !== undefined && (value.context === null || typeof value.context !== "object" || Array.isArray(value.context))) throw validationerror(`session event ${index} context is invalid`);
|
|
307
|
+
const source = value.context ?? value;
|
|
308
|
+
const context = {};
|
|
309
|
+
for (const name of ["windowid", "tabid", "frameid"]) if (source[name] !== undefined) {
|
|
310
|
+
if (typeof source[name] !== "string" || !source[name]) throw validationerror(`session event ${index} ${name} is invalid`);
|
|
311
|
+
context[name] = source[name];
|
|
312
|
+
}
|
|
313
|
+
return Object.keys(context).length ? context : undefined;
|
|
314
|
+
}
|
package/index.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { randomInt, randomUUID } from 'node:crypto';
|
|
|
21
21
|
import { EventEmitter } from 'node:events';
|
|
22
22
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
23
23
|
import { join } from 'node:path';
|
|
24
|
-
import type { migprofileid } from './
|
|
24
|
+
import type { migprofileid } from './virtual.ts';
|
|
25
25
|
|
|
26
26
|
/* ------------------------------------------------------------------ */
|
|
27
27
|
/* Section 1: reference versions */
|
|
@@ -1399,12 +1399,11 @@ export function planlint(candidate: plan): readonly string[] {
|
|
|
1399
1399
|
/** Re-exports the compute domain (wasm/wasmtime 48 lts, webgpu on
|
|
1400
1400
|
* lavapipe, node 26 runtime surface, ai workload planners, wasm canary,
|
|
1401
1401
|
* wasi:gfx, chatops, gpu ebpf telemetry, ai migration predictor). */
|
|
1402
|
-
export * from './compute.
|
|
1403
|
-
|
|
1404
|
-
*
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1407
|
-
export * from './media.js';
|
|
1402
|
+
export * from './compute.ts';
|
|
1403
|
+
/* the media pipeline and transcode domain moved to devthink (the saddle
|
|
1404
|
+
* ownership law, wave a, actions 108-112: the master virtualization engine
|
|
1405
|
+
* keeps only the sandbox/vm/runner/vgpu/vcpu/ports/hardware-virtual
|
|
1406
|
+
* modalities — the media lane rides its new owner). */
|
|
1408
1407
|
export {
|
|
1409
1408
|
bellstate,
|
|
1410
1409
|
deutsch,
|
|
@@ -1421,12 +1420,12 @@ export {
|
|
|
1421
1420
|
quantumsim,
|
|
1422
1421
|
runbb84,
|
|
1423
1422
|
rune91,
|
|
1424
|
-
} from './quantum.
|
|
1423
|
+
} from './quantum.ts';
|
|
1425
1424
|
/** Re-exports the scheduling and allocation domain (typecheck sharding,
|
|
1426
1425
|
* shared-memory cache, project graph, MIG/vCPU/RAM/GPU/NUMA/PCI
|
|
1427
1426
|
* allocation, aipsched, psi lstm, tenant QoS, anomaly detector,
|
|
1428
1427
|
* hot reload, otel, health, shutdown, plugin hooks). */
|
|
1429
|
-
export * from './scheduler.
|
|
1428
|
+
export * from './scheduler.ts';
|
|
1430
1429
|
export {
|
|
1431
1430
|
cgroupsv2slice,
|
|
1432
1431
|
creatiersengine,
|
|
@@ -1446,33 +1445,36 @@ export {
|
|
|
1446
1445
|
tierserror,
|
|
1447
1446
|
tmpfsrecipe,
|
|
1448
1447
|
zramrecipe,
|
|
1449
|
-
} from './tiers.
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
export * from
|
|
1454
|
-
|
|
1455
|
-
*
|
|
1456
|
-
* bridge). */
|
|
1457
|
-
export * from './virtualization.js';
|
|
1458
|
-
/** Re-exports the MIG profile union declared by the memory module. */
|
|
1459
|
-
export type { migprofileid } from './virtualmemory.js';
|
|
1460
|
-
/** Re-exports the memory tier catalog and virtual memory manager. */
|
|
1461
|
-
export * from './virtualmemory.js';
|
|
1448
|
+
} from './tiers.ts';
|
|
1449
|
+
/* the virtual family fold (the edgelandes law, wave/virtualfold): the
|
|
1450
|
+
* four arm modules — virtualcpu.ts, virtualgpu.ts, virtualization.ts and
|
|
1451
|
+
* virtualmemory.ts — retired into the one keyword file virtual.ts, so
|
|
1452
|
+
* their star re-exports retire with them: the `export * from
|
|
1453
|
+
* './virtual.ts'` of the routing barrel below carries every one of their
|
|
1454
|
+
* names (plus the MIG profile type union) through the single seat. */
|
|
1462
1455
|
|
|
1463
1456
|
/* ── Section 2: the saddle domain routing barrel ── */
|
|
1464
1457
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
export * from './
|
|
1471
|
-
export * from './
|
|
1472
|
-
export * from './
|
|
1473
|
-
export * from './
|
|
1458
|
+
/* the workflow automation and AI intelligence domains moved to devthink
|
|
1459
|
+
* (the saddle ownership law, wave a, actions 108-112: the master
|
|
1460
|
+
* virtualization engine keeps only the sandbox/vm/runner/vgpu/vcpu/ports/
|
|
1461
|
+
* hardware-virtual modalities — the automation and intelligence lanes ride
|
|
1462
|
+
* their new owner). */
|
|
1463
|
+
export * from './browser.ts';
|
|
1464
|
+
export * from './communication.ts';
|
|
1465
|
+
export * from './distribution.ts';
|
|
1466
|
+
export * from './execution.ts';
|
|
1467
|
+
export * from './foundation.ts';
|
|
1468
|
+
export * from './integration.ts';
|
|
1469
|
+
export * from './isolation.ts';
|
|
1474
1470
|
/** Re-exports the sandbox modality registry — the catalog the join
|
|
1475
1471
|
* resolver reads (the spine of the sandbox modalities the engine opens). */
|
|
1476
|
-
export * from './modalityregistry.
|
|
1477
|
-
export * from './modes.
|
|
1478
|
-
|
|
1472
|
+
export * from './modalityregistry.ts';
|
|
1473
|
+
export * from './modes.ts';
|
|
1474
|
+
/** Re-exports the script lanes — the sh execution through the universal
|
|
1475
|
+
* runner, the yml/yaml interpretation through the house yaml subset with
|
|
1476
|
+
* the babel compile roundtrip, the detached background runs on the house
|
|
1477
|
+
* job queue and the docker-ready descriptors (the PR15 lane surface the
|
|
1478
|
+
* webserver routes and the script cli command consume). */
|
|
1479
|
+
export * from './scriptlanes.ts';
|
|
1480
|
+
export * from './virtual.ts';
|
package/isolation.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* isolation.ts — isolation contracts describe effect boundaries without
|
|
3
|
+
* executing binaries, touching hosts, or calling providers.
|
|
4
|
+
*
|
|
5
|
+
* This file is the v2.0.0 grand-merge carrier of the former
|
|
6
|
+
* isolation/contracts.ts: the browser-safe boundary contract surface of the
|
|
7
|
+
* virtual domain. It stays its own root file (the one deliberate split of
|
|
8
|
+
* the domain) because the web interface bundles exactly these contracts —
|
|
9
|
+
* the whole file is import-free and browser-loadable, while the node-side
|
|
10
|
+
* implementations of the domain live in virtual.ts.
|
|
11
|
+
*/
|
|
12
|
+
// @ts-nocheck
|
|
13
|
+
/**
|
|
14
|
+
* isolation contracts describe effect boundaries without executing binaries, touching hosts, or calling providers.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const boundaries = new Set(["gateway", "planning", "policy", "materialization", "execution", "persistence", "evidence"]);
|
|
18
|
+
const effects = new Set(["binary-execution", "host-bridge", "remote-dispatch", "provider-access", "local-storage", "browser-session", "database", "network"]);
|
|
19
|
+
const targets = new Set(["local", "remote", "provider", "browser", "storage"]);
|
|
20
|
+
|
|
21
|
+
/** Validates a bounded request for a privileged effect without performing it. */
|
|
22
|
+
export function executionrequest(input = {}) {
|
|
23
|
+
const effect = valid(input.effect, effects, "execution effect");
|
|
24
|
+
const target = valid(input.target, targets, "execution target");
|
|
25
|
+
const source = digest(input.source, "execution source");
|
|
26
|
+
return Object.freeze({ version: 1, id: nonempty(input.id, "execution id"), effect, target, source, budget: budget(input.budget), state: "requested" });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Evaluates a requested effect against explicit policy, approval, and adapter declarations. */
|
|
30
|
+
export function executiondecision(request, input = {}) {
|
|
31
|
+
const normalized = executionrequest(request);
|
|
32
|
+
const policy = normalizedlist(input.policy?.alloweffects);
|
|
33
|
+
const policytargets = normalizedlist(input.policy?.allowtargets);
|
|
34
|
+
const approval = normalizedlist(input.approval?.effects);
|
|
35
|
+
const approvaltargets = normalizedlist(input.approval?.targets);
|
|
36
|
+
const capabilities = normalizedlist(input.adapter?.capabilities);
|
|
37
|
+
const reasons = [];
|
|
38
|
+
if (!policy.includes(normalized.effect)) reasons.push("policy-effect");
|
|
39
|
+
if (!policytargets.includes(normalized.target)) reasons.push("policy-target");
|
|
40
|
+
if (!approval.includes(normalized.effect)) reasons.push("approval-effect");
|
|
41
|
+
if (!approvaltargets.includes(normalized.target)) reasons.push("approval-target");
|
|
42
|
+
if (!capabilities.includes(normalized.effect)) reasons.push("adapter-capability");
|
|
43
|
+
if (!String(input.adapter?.owner ?? "")) reasons.push("adapter-owner");
|
|
44
|
+
const allowed = reasons.length === 0;
|
|
45
|
+
return Object.freeze({ version: 1, request: normalized, state: allowed ? "caller-delegates" : "denied", reasons: Object.freeze(reasons), adapter: allowed ? Object.freeze({ owner: String(input.adapter.owner), capabilities: Object.freeze(capabilities) }) : null, effects: Object.freeze([]) });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Renders a side-effect-free handoff and never invokes an adapter. */
|
|
49
|
+
export function executionhandoff(input = {}) {
|
|
50
|
+
const decision = executiondecision(input.request, input.configuration);
|
|
51
|
+
if (decision.state !== "caller-delegates") return Object.freeze({ version: 1, state: "execution-disabled", code: "EXECUTION_POLICY_DENIED", decision, effects: Object.freeze([]) });
|
|
52
|
+
return Object.freeze({ version: 1, state: "caller-delegates", code: "CALLER_ADAPTER_REQUIRED", decision, effects: Object.freeze([]) });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Validates a serializable envelope for a unified web internal API boundary. */
|
|
56
|
+
export function internalenvelope(input = {}) {
|
|
57
|
+
const boundary = valid(input.boundary, boundaries, "internal api boundary");
|
|
58
|
+
return Object.freeze({ version: 1, boundary, requestid: nonempty(input.requestid, "internal api requestid"), payload: freezeobject(input.payload ?? {}) });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Creates pure internal API handlers for planning, policy, handoff, and evidence projections. */
|
|
62
|
+
export function internalapi(input = {}) {
|
|
63
|
+
const configuration = freezeobject(input.configuration ?? {});
|
|
64
|
+
function handle(envelope) {
|
|
65
|
+
const request = internalenvelope(envelope);
|
|
66
|
+
if (request.boundary === "gateway") return response(request, "accepted", { requestid: request.requestid });
|
|
67
|
+
if (request.boundary === "planning") return response(request, "planned", { request: executionrequest(request.payload) });
|
|
68
|
+
if (request.boundary === "policy") return response(request, "evaluated", { decision: executiondecision(request.payload.request, request.payload.configuration ?? configuration) });
|
|
69
|
+
if (request.boundary === "execution") return response(request, "projected", { handoff: executionhandoff({ request: request.payload.request, configuration: request.payload.configuration ?? configuration }) });
|
|
70
|
+
if (request.boundary === "materialization") return response(request, "planned", { state: "no-materialization", effects: Object.freeze([]) });
|
|
71
|
+
if (request.boundary === "persistence") return response(request, "projected", { state: "ephemeral-fixture", effects: Object.freeze([]) });
|
|
72
|
+
return response(request, "recorded", { receipt: Object.freeze({ version: 1, state: String(request.payload.state ?? "unknown"), effects: Object.freeze([]) }) });
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze({ handle });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function response(request, state, data) { return Object.freeze({ version: 1, boundary: request.boundary, requestid: request.requestid, state, data: freezeobject(data), effects: Object.freeze([]) }); }
|
|
78
|
+
function budget(input = {}) { return Object.freeze({ maxbytes: positive(input.maxbytes ?? 1, "execution budget maxbytes"), maxmilliseconds: positive(input.maxmilliseconds ?? 1, "execution budget maxmilliseconds"), network: input.network === true }); }
|
|
79
|
+
function normalizedlist(value) { return Object.freeze([...new Set(Array.isArray(value) ? value.map((entry) => String(entry)) : [])].sort()); }
|
|
80
|
+
function freezeobject(value) { if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError("internal api payload must be an object"); return Object.freeze({ ...value }); }
|
|
81
|
+
function valid(value, collection, name) { const output = String(value ?? ""); if (!collection.has(output)) throw new TypeError(`${name} is invalid`); return output; }
|
|
82
|
+
function digest(value, name) { const output = String(value ?? "").toLowerCase(); if (!/^[a-f0-9]{64}$/.test(output)) throw new TypeError(`${name} sha256 is invalid`); return output; }
|
|
83
|
+
function nonempty(value, name) { const output = String(value ?? ""); if (!output) throw new TypeError(`${name} is required`); return output; }
|
|
84
|
+
function positive(value, name) { const output = Number(value); if (!Number.isSafeInteger(output) || output < 1) throw new TypeError(`${name} must be a positive safe integer`); return output; }
|