@nylorun/runtime 0.22.0-beta → 0.24.0-beta
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/CHANGELOG.md +161 -0
- package/README.md +95 -30
- package/dist/adapters/execution/restate.d.ts +15 -3
- package/dist/adapters/execution/restate.js +78 -84
- package/dist/adapters/replication/pgoutput.d.ts +2 -0
- package/dist/adapters/replication/pgoutput.js +6 -3
- package/dist/adapters/sandbox/local.d.ts +9 -1
- package/dist/adapters/sandbox/local.js +16 -4
- package/dist/adapters/sandbox/virtual.js +4 -1
- package/dist/adapters/streams/s2.js +1 -13
- package/dist/api/a2a/endpoint.js +5 -1
- package/dist/api/a2a/routes.d.ts +2 -0
- package/dist/api/a2a/routes.js +2 -2
- package/dist/api/a2a/tasks.js +2 -1
- package/dist/api/ag-ui/endpoint.js +4 -2
- package/dist/api/ag-ui/history.js +4 -1
- package/dist/api/ag-ui/routes.d.ts +4 -1
- package/dist/api/ag-ui/routes.js +11 -10
- package/dist/api/ag-ui/translate.js +3 -2
- package/dist/api/components.d.ts +4953 -1204
- package/dist/api/components.js +25 -16
- package/dist/api/gate/keys.js +7 -1
- package/dist/api/gate/routes.d.ts +6 -0
- package/dist/api/gate/routes.js +39 -3
- package/dist/api/http/app.js +4 -4
- package/dist/api/http/define.d.ts +6 -0
- package/dist/api/http/define.js +13 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/artifacts.js +35 -8
- package/dist/api/http/routes/coverage.d.ts +9 -0
- package/dist/api/http/routes/coverage.js +34 -0
- package/dist/api/http/routes/environments.d.ts +11 -0
- package/dist/api/http/routes/environments.js +283 -0
- package/dist/api/http/routes/mcp.d.ts +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- package/dist/api/http/routes/me.js +1 -1
- package/dist/api/http/routes/reads.d.ts +45 -9
- package/dist/api/http/routes/reads.js +54 -5
- package/dist/api/http/routes/sessions.js +11 -6
- package/dist/api/http/routes/tenant.js +32 -10
- package/dist/api/openapi.js +31 -26
- package/dist/artifacts/disk.d.ts +59 -0
- package/dist/artifacts/disk.js +563 -0
- package/dist/artifacts/export.d.ts +1 -1
- package/dist/artifacts/export.js +2 -3
- package/dist/artifacts/folders.d.ts +6 -3
- package/dist/artifacts/folders.js +17 -12
- package/dist/artifacts/service.d.ts +2 -1
- package/dist/artifacts/service.js +6 -1
- package/dist/artifacts/workspace.d.ts +1 -1
- package/dist/artifacts/workspace.js +1 -1
- package/dist/core/flow-host.d.ts +3 -22
- package/dist/core/flow-host.js +11 -37
- package/dist/core/provider.d.ts +3 -2
- package/dist/core/provider.js +5 -37
- package/dist/core/sandbox-routes.d.ts +2 -21
- package/dist/core/sandbox-routes.js +10 -43
- package/dist/execution/types.d.ts +11 -9
- package/dist/execution/types.js +5 -7
- package/dist/gates/contract.d.ts +3 -24
- package/dist/gates/contract.js +1 -36
- package/dist/gates/egress-credentials.d.ts +9 -0
- package/dist/gates/egress-credentials.js +11 -4
- package/dist/gates/egress.d.ts +28 -1
- package/dist/gates/egress.js +115 -10
- package/dist/gates/fixture-model.d.ts +28 -0
- package/dist/gates/fixture-model.js +92 -0
- package/dist/gates/handler.js +4 -4
- package/dist/gates/http-tool.d.ts +6 -2
- package/dist/gates/http-tool.js +3 -5
- package/dist/gates/in-process.d.ts +5 -0
- package/dist/gates/in-process.js +12 -1
- package/dist/gates/journal.d.ts +30 -0
- package/dist/gates/journal.js +52 -0
- package/dist/gates/mcp-handler.d.ts +4 -0
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/meter.d.ts +10 -2
- package/dist/gates/meter.js +20 -5
- package/dist/gates/policy.d.ts +49 -0
- package/dist/gates/policy.js +134 -0
- package/dist/gates/tenant-vaults.d.ts +7 -7
- package/dist/gates/tenant-vaults.js +5 -5
- package/dist/gates/tool-calls.d.ts +10 -5
- package/dist/gates/tool-calls.js +28 -10
- package/dist/gates/tool-client.d.ts +8 -0
- package/dist/gates/tool-client.js +27 -11
- package/dist/gates/tool-contract.d.ts +10 -68
- package/dist/gates/tool-contract.js +1 -85
- package/dist/gates/tool-gate.d.ts +1 -1
- package/dist/harness/calls.d.ts +12 -5
- package/dist/harness/calls.js +21 -12
- package/dist/harness/executors.js +12 -9
- package/dist/harness/main.js +18 -5
- package/dist/harness/pod.d.ts +34 -0
- package/dist/harness/pod.js +41 -0
- package/dist/harness/service.d.ts +0 -1
- package/dist/harness/service.js +13 -5
- package/dist/harness/setup.d.ts +27 -0
- package/dist/harness/setup.js +150 -0
- package/dist/harness/ws-client.js +3 -2
- package/dist/harness/ws-port.d.ts +1 -5
- package/dist/harness/ws-port.js +1 -5
- package/dist/harness-api/in-process.js +3 -3
- package/dist/harness-api/record.d.ts +15 -1
- package/dist/harness-api/record.js +174 -44
- package/dist/harness-api/redact.d.ts +3 -0
- package/dist/harness-api/redact.js +45 -0
- package/dist/harness-api/server.d.ts +8 -0
- package/dist/harness-api/server.js +93 -13
- package/dist/harness-api/start.d.ts +10 -3
- package/dist/harness-api/start.js +40 -10
- package/dist/harness-api/tool-journal.d.ts +96 -0
- package/dist/harness-api/tool-journal.js +102 -0
- package/dist/harness-api/tool-status.d.ts +13 -0
- package/dist/harness-api/tool-status.js +26 -0
- package/dist/harness-api/workspace.d.ts +6 -3
- package/dist/harness-api/workspace.js +27 -11
- package/dist/harness-api/ws-server.d.ts +11 -3
- package/dist/harness-api/ws-server.js +94 -15
- package/dist/host/execution.d.ts +8 -6
- package/dist/host/gates.d.ts +2 -1
- package/dist/host/gates.js +10 -2
- package/dist/host/main.js +64 -21
- package/dist/host/operate.js +67 -5
- package/dist/host/stack-config.d.ts +70 -0
- package/dist/host/stack-config.js +67 -1
- package/dist/infra/execution.d.ts +18 -1
- package/dist/infra/execution.js +28 -4
- package/dist/infra/index.d.ts +1 -1
- package/dist/keys/client.js +4 -1
- package/dist/keys/keys.d.ts +5 -5
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +999 -2211
- package/dist/mcp/connect.d.ts +25 -20
- package/dist/mcp/connect.js +29 -30
- package/dist/mcp/pool.d.ts +2 -2
- package/dist/mcp/pool.js +1 -1
- package/dist/mcp/preview.d.ts +3 -3
- package/dist/mcp/preview.js +10 -20
- package/dist/mcp/snapshot.d.ts +5 -11
- package/dist/mcp/snapshot.js +6 -7
- package/dist/model/pi-model.js +8 -0
- package/dist/openapi.json +6955 -2526
- package/dist/reads/types.d.ts +16 -3
- package/dist/record/append.d.ts +3 -1
- package/dist/record/append.js +1 -0
- package/dist/record/envelope.d.ts +5 -1
- package/dist/record/envelope.js +7 -3
- package/dist/record/environment.d.ts +25 -0
- package/dist/record/environment.js +44 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/retry.d.ts +21 -0
- package/dist/retry.js +34 -0
- package/dist/sandbox/disk-fs.d.ts +95 -0
- package/dist/sandbox/disk-fs.js +206 -0
- package/dist/sandbox/join.d.ts +17 -18
- package/dist/sandbox/join.js +46 -20
- package/dist/sandbox/manager.d.ts +16 -8
- package/dist/sandbox/manager.js +33 -17
- package/dist/sandbox/placement.d.ts +13 -12
- package/dist/sandbox/placement.js +29 -12
- package/dist/sandbox/pods/client.d.ts +6 -1
- package/dist/sandbox/pods/lifecycle.d.ts +28 -27
- package/dist/sandbox/pods/lifecycle.js +14 -26
- package/dist/sandbox/pods/reconcile.js +21 -15
- package/dist/sandbox/pods/spec.d.ts +15 -13
- package/dist/sandbox/pods/spec.js +16 -20
- package/dist/sandbox/records.d.ts +2 -2
- package/dist/sandbox/records.js +3 -3
- package/dist/sandbox/resolve.d.ts +35 -27
- package/dist/sandbox/resolve.js +66 -41
- package/dist/sandbox/session-sandbox.js +1 -1
- package/dist/sandbox/setup.d.ts +61 -0
- package/dist/sandbox/setup.js +123 -0
- package/dist/sandbox/share.d.ts +11 -21
- package/dist/sandbox/share.js +12 -41
- package/dist/sandbox/tenant-config.d.ts +12 -14
- package/dist/sandbox/tenant-config.js +12 -17
- package/dist/sandbox/types.d.ts +6 -0
- package/dist/store/postgres/control.js +8 -1
- package/dist/store/postgres/drizzle/0018_wake_outbox_retries.sql +3 -0
- package/dist/store/postgres/drizzle/0019_sandbox_signal_outbox.sql +18 -0
- package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
- package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
- package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +42 -0
- package/dist/store/postgres/reads.js +117 -17
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/record.d.ts +7 -0
- package/dist/store/postgres/record.js +23 -2
- package/dist/store/postgres/schema.d.ts +1213 -779
- package/dist/store/postgres/schema.js +136 -76
- package/dist/store/postgres/store.js +283 -117
- package/dist/store/types.d.ts +206 -88
- package/dist/streams/relay/core.js +1 -13
- package/dist/tenant/advance.d.ts +7 -6
- package/dist/tenant/advance.js +121 -49
- package/dist/tenant/artifact-tool.js +3 -4
- package/dist/tenant/commands.d.ts +15 -2
- package/dist/tenant/commands.js +94 -14
- package/dist/tenant/context.d.ts +67 -33
- package/dist/tenant/context.js +4 -15
- package/dist/tenant/control.d.ts +8 -1
- package/dist/tenant/control.js +2 -0
- package/dist/tenant/effects.d.ts +1 -1
- package/dist/tenant/effects.js +37 -20
- package/dist/tenant/environments.d.ts +167 -0
- package/dist/tenant/environments.js +823 -0
- package/dist/tenant/harness-tokens.d.ts +21 -0
- package/dist/tenant/harness-tokens.js +61 -0
- package/dist/tenant/host-token.d.ts +1 -1
- package/dist/tenant/host-token.js +2 -4
- package/dist/tenant/identity-file.d.ts +4 -4
- package/dist/tenant/identity-file.js +17 -8
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/principals.js +1 -1
- package/dist/tenant/reset.js +3 -3
- package/dist/tenant/runtime.d.ts +6 -1
- package/dist/tenant/runtime.js +30 -4
- package/dist/tenant/scheduler.d.ts +7 -0
- package/dist/tenant/scheduler.js +38 -7
- package/dist/tenant/session-streams.d.ts +0 -1
- package/dist/tenant/session-streams.js +1 -13
- package/dist/tenant/session.d.ts +3 -3
- package/dist/tenant/session.js +0 -14
- package/dist/tenant/sessions.d.ts +13 -13
- package/dist/tenant/sessions.js +61 -138
- package/dist/tenant/signing-keys.d.ts +5 -1
- package/dist/tenant/status.js +3 -3
- package/dist/tenant/streams.js +14 -29
- package/dist/tenant/sweep.d.ts +39 -12
- package/dist/tenant/sweep.js +168 -63
- package/dist/tenant/transcript.d.ts +210 -20
- package/dist/tenant/transcript.js +62 -11
- package/dist/tenant/turn-timing.d.ts +43 -0
- package/dist/tenant/turn-timing.js +39 -0
- package/dist/tenant/types.d.ts +2 -0
- package/dist/traces/ids.d.ts +42 -0
- package/dist/traces/ids.js +85 -0
- package/dist/traces/key.d.ts +6 -0
- package/dist/traces/key.js +37 -0
- package/dist/traces/map.d.ts +113 -0
- package/dist/traces/map.js +317 -0
- package/dist/traces/options.d.ts +7 -0
- package/dist/traces/options.js +1 -0
- package/dist/traces/otlp.d.ts +42 -0
- package/dist/traces/otlp.js +84 -0
- package/dist/traces/projector.d.ts +58 -0
- package/dist/traces/projector.js +200 -0
- package/dist/traces/read.d.ts +23 -0
- package/dist/traces/read.js +16 -0
- package/dist/vault/coverage.d.ts +26 -0
- package/dist/vault/coverage.js +64 -0
- package/dist/vault/error.d.ts +11 -1
- package/dist/vault/error.js +5 -1
- package/dist/vault/service.d.ts +47 -48
- package/dist/vault/service.js +321 -382
- package/dist/vault/sources.d.ts +5 -16
- package/dist/vault/sources.js +6 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/package.json +14 -13
- package/dist/api/http/routes/sandboxes.d.ts +0 -9
- package/dist/api/http/routes/sandboxes.js +0 -153
- package/dist/api/http/routes/vaults.d.ts +0 -10
- package/dist/api/http/routes/vaults.js +0 -139
- package/dist/record/sandbox.d.ts +0 -25
- package/dist/record/sandbox.js +0 -43
- package/dist/tenant/sandboxes.d.ts +0 -122
- package/dist/tenant/sandboxes.js +0 -562
package/dist/vault/sources.d.ts
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where a session's MCP or HTTP tool credential comes from: the vaults attached to the session,
|
|
3
|
-
* and nothing else. OSS holds no OAuth client and asks no credential resolver (protocol 10,
|
|
4
|
-
* D49): a person's own keys live in their user vault, the installation's in its vaults.
|
|
5
|
-
*
|
|
6
|
-
* Both authorize sites call this: the gateway (`gates/tenant-vaults.ts`, remote MCP servers and
|
|
7
|
-
* HTTP tools in the gates service) and the Tenant (`tenant/effects.ts`, the in-process MCP pool
|
|
8
|
-
* and Tool Gate). The session comes from its row, never from the harness.
|
|
9
|
-
*/
|
|
10
|
-
import { type CredentialSelection } from "@nylorun/core/contracts";
|
|
11
1
|
import type { AuthorizeResult, VaultService } from "./service.js";
|
|
12
2
|
/** The session a request is made for: its row, as stored. */
|
|
13
3
|
export interface CredentialSession {
|
|
14
4
|
readonly id: string;
|
|
15
5
|
readonly ownerUserId: string;
|
|
16
|
-
readonly
|
|
17
|
-
readonly credentialSelections?: readonly CredentialSelection[];
|
|
6
|
+
readonly environmentId?: string;
|
|
18
7
|
}
|
|
19
|
-
/** One MCP or HTTP tool request: its URL, and the
|
|
8
|
+
/** One MCP or HTTP tool request: its URL, and the server's (or HTTP tool credential's) name. */
|
|
20
9
|
export interface McpCredentialRequest {
|
|
21
10
|
readonly url: string;
|
|
22
|
-
/** The server's name, or the HTTP tool's `credential
|
|
11
|
+
/** The server's name, or the HTTP tool's `credential`, for audit and messages. */
|
|
23
12
|
readonly serverName?: string;
|
|
24
13
|
}
|
|
25
14
|
/**
|
|
26
|
-
* The credential of one request made for `session`: the
|
|
27
|
-
*
|
|
15
|
+
* The credential of one request made for `session`: the answer of its Environment's vault
|
|
16
|
+
* (`VaultService.authorize`). A credential with an identity header (R2b C2)
|
|
28
17
|
* gets the session owner's subject in it (Q2), from the session row: the run token names no
|
|
29
18
|
* owner, so neither the model nor the manifest can change it. A session whose owner is no
|
|
30
19
|
* person (the reserved `installation`) sends none (Q3).
|
package/dist/vault/sources.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Where a session's MCP or HTTP tool credential comes from: the
|
|
3
|
-
* and nothing else. OSS holds no OAuth client and asks no credential
|
|
4
|
-
* D49): a person's own keys live in
|
|
2
|
+
* Where a session's MCP or HTTP tool credential comes from: the vault of the Environment the
|
|
3
|
+
* session names (D56), and nothing else. OSS holds no OAuth client and asks no credential
|
|
4
|
+
* resolver (protocol 10, D49): a person's own keys live in the Environment the app maps to them.
|
|
5
5
|
*
|
|
6
6
|
* Both authorize sites call this: the gateway (`gates/tenant-vaults.ts`, remote MCP servers and
|
|
7
7
|
* HTTP tools in the gates service) and the Tenant (`tenant/effects.ts`, the in-process MCP pool
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { isSubject } from "@nylorun/core/contracts";
|
|
11
11
|
/**
|
|
12
|
-
* The credential of one request made for `session`: the
|
|
13
|
-
*
|
|
12
|
+
* The credential of one request made for `session`: the answer of its Environment's vault
|
|
13
|
+
* (`VaultService.authorize`). A credential with an identity header (R2b C2)
|
|
14
14
|
* gets the session owner's subject in it (Q2), from the session row: the run token names no
|
|
15
15
|
* owner, so neither the model nor the manifest can change it. A session whose owner is no
|
|
16
16
|
* person (the reserved `installation`) sends none (Q3).
|
|
@@ -18,10 +18,8 @@ import { isSubject } from "@nylorun/core/contracts";
|
|
|
18
18
|
export async function sessionCredentials(vault, session, request) {
|
|
19
19
|
const result = await vault.authorize({
|
|
20
20
|
sessionId: session.id,
|
|
21
|
-
|
|
22
|
-
credentialSelections: session.credentialSelections ?? [],
|
|
21
|
+
...(session.environmentId === undefined ? {} : { environmentId: session.environmentId }),
|
|
23
22
|
url: request.url,
|
|
24
|
-
...(request.serverName === undefined ? {} : { serverName: request.serverName }),
|
|
25
23
|
});
|
|
26
24
|
if (result.status !== "authorized" || !result.identity || !isSubject(session.ownerUserId))
|
|
27
25
|
return result;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const RUNTIME_VERSION = "0.
|
|
1
|
+
export declare const RUNTIME_VERSION = "0.24.0-beta";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
// Kept in step with package.json by runtime/scripts/check-package.mjs, which runs in npm run check.
|
|
1
|
+
// Kept in step with package.json by runtime/server/scripts/check-package.mjs, which runs in npm run check.
|
|
2
2
|
// release:prepare also rewrites this when it bumps @nylorun/runtime.
|
|
3
|
-
export const RUNTIME_VERSION = "0.
|
|
3
|
+
export const RUNTIME_VERSION = "0.24.0-beta";
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0-beta",
|
|
4
4
|
"description": "Nylorun Runtime: the agent execution Host on Postgres, Restate and S2, and model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/nylorun/agents.git",
|
|
10
|
-
"directory": "runtime"
|
|
10
|
+
"directory": "runtime/server"
|
|
11
11
|
},
|
|
12
12
|
"engines": {
|
|
13
13
|
"node": ">=24.0.0"
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"provenance": true
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
|
-
"build": "npm run clean && node
|
|
48
|
+
"build": "npm run clean && node ../../scripts/check-typescript-version.mjs && tsc -p tsconfig.json && node scripts/copy-migrations.mjs && node scripts/build-openapi.mjs",
|
|
49
49
|
"check": "npm run build && npm test && node scripts/check-package.mjs",
|
|
50
|
-
"typecheck": "node
|
|
50
|
+
"typecheck": "node ../../scripts/check-typescript-version.mjs && tsc -p tsconfig.json --noEmit",
|
|
51
51
|
"test": "vitest run",
|
|
52
52
|
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
53
53
|
"test:stack:up": "node test/stack/up.mjs up",
|
|
@@ -59,21 +59,22 @@
|
|
|
59
59
|
"db:studio": "drizzle-kit studio"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@ag-ui/core": "~1.0.
|
|
62
|
+
"@ag-ui/core": "~1.0.2",
|
|
63
63
|
"@asteasolutions/zod-to-openapi": "^9.1.0",
|
|
64
64
|
"@earendil-works/pi-ai": "0.99.1",
|
|
65
65
|
"@hono/node-server": "^2.1.3",
|
|
66
66
|
"@hono/zod-openapi": "^1.6.3",
|
|
67
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
68
|
-
"@nylorun/core": "0.
|
|
69
|
-
"@nylorun/harness": "0.
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
68
|
+
"@nylorun/core": "0.20.0-beta",
|
|
69
|
+
"@nylorun/harness": "0.26.0-beta",
|
|
70
70
|
"@restatedev/restate-sdk": "1.17.2",
|
|
71
|
+
"@restatedev/restate-sdk-clients": "1.17.2",
|
|
71
72
|
"@s2-dev/streamstore": "0.28.0",
|
|
72
73
|
"aws4fetch": "1.0.20",
|
|
73
74
|
"drizzle-orm": "^0.45.3",
|
|
74
|
-
"hono": "^4.13.
|
|
75
|
+
"hono": "^4.13.13",
|
|
75
76
|
"jose": "^6.2.12",
|
|
76
|
-
"just-bash": "3.
|
|
77
|
+
"just-bash": "3.6.0",
|
|
77
78
|
"pg": "8.23.1",
|
|
78
79
|
"pg-logical-replication": "2.5.0",
|
|
79
80
|
"postgres": "^3.4.9",
|
|
@@ -83,9 +84,9 @@
|
|
|
83
84
|
},
|
|
84
85
|
"devDependencies": {
|
|
85
86
|
"@a2a-js/sdk": "~1.3.0",
|
|
86
|
-
"@ag-ui/client": "1.0.
|
|
87
|
-
"@scalar/openapi-parser": "^0.29.
|
|
88
|
-
"@types/node": "^26.
|
|
87
|
+
"@ag-ui/client": "1.0.2",
|
|
88
|
+
"@scalar/openapi-parser": "^0.29.11",
|
|
89
|
+
"@types/node": "^26.6.4",
|
|
89
90
|
"@types/pg": "^8.23.1",
|
|
90
91
|
"@types/ws": "^8.18.2",
|
|
91
92
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sandboxes as a resource (`/v1/sandboxes/**`, Host feature `sandboxes`): create or find one by
|
|
3
|
-
* id, read it, list them by label, read its lifecycle stream, and delete it. Ids may hold `/`,
|
|
4
|
-
* sent percent-encoded as one path segment (`team-a%2Fproj-42`). A token caller reaches only
|
|
5
|
-
* the ids its sandbox grants match, and changes them only with `sandboxes:write`.
|
|
6
|
-
*/
|
|
7
|
-
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
8
|
-
import type { TenantEnv } from "../app.js";
|
|
9
|
-
export declare function sandboxRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { isSandboxId, PutSandboxRequestSchema } from "@nylorun/core/contracts";
|
|
3
|
-
import { DeleteSandboxResponse, ListSandboxEventsResponse, ListSandboxesResponse, SandboxPage, PutSandboxRequest, SandboxView, } from "../../components.js";
|
|
4
|
-
import { fail } from "../../../tenant/http.js";
|
|
5
|
-
import { deleteSandbox, getSandbox, listSandboxes, putSandbox, resetSandbox, sandboxEventsOf, stopSandbox, } from "../../../tenant/sandboxes.js";
|
|
6
|
-
import { readJson } from "../body.js";
|
|
7
|
-
import { tenantRoute } from "../define.js";
|
|
8
|
-
import { pageQuery, sandboxPage } from "./reads.js";
|
|
9
|
-
import { jsonResponse } from "../respond.js";
|
|
10
|
-
/** Reading a sandbox: any caller that may use sessions, or change sandboxes. */
|
|
11
|
-
const READ = {
|
|
12
|
-
credentials: ["application", "subject", "token"],
|
|
13
|
-
scopes: ["sessions:own", "sandboxes:write"],
|
|
14
|
-
};
|
|
15
|
-
/** Creating or deleting one. */
|
|
16
|
-
const WRITE = {
|
|
17
|
-
credentials: ["application", "subject", "token"],
|
|
18
|
-
scopes: ["sandboxes:write"],
|
|
19
|
-
};
|
|
20
|
-
const json = (schema, description) => ({
|
|
21
|
-
description,
|
|
22
|
-
content: { "application/json": { schema } },
|
|
23
|
-
});
|
|
24
|
-
const sandboxId = z.object({
|
|
25
|
-
sandboxId: z
|
|
26
|
-
.string()
|
|
27
|
-
.meta({ description: "The sandbox id, percent-encoded: `team-a%2Fproj-42` for `team-a/proj-42`" }),
|
|
28
|
-
});
|
|
29
|
-
/** The path's sandbox id, or a 400 naming the rule. */
|
|
30
|
-
function idOf(value) {
|
|
31
|
-
if (!isSandboxId(value))
|
|
32
|
-
return fail(400, "A sandbox id is up to 200 characters: /-separated segments of letters, digits, '.', '_' and '-'");
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
/** `label=k=v`, repeated: every one must match. */
|
|
36
|
-
function labelsOf(values) {
|
|
37
|
-
const labels = {};
|
|
38
|
-
for (const value of values ?? []) {
|
|
39
|
-
const at = value.indexOf("=");
|
|
40
|
-
if (at <= 0)
|
|
41
|
-
fail(400, `label must be key=value, not ${value}`);
|
|
42
|
-
labels[value.slice(0, at)] = value.slice(at + 1);
|
|
43
|
-
}
|
|
44
|
-
return labels;
|
|
45
|
-
}
|
|
46
|
-
export function sandboxRoutes(api) {
|
|
47
|
-
tenantRoute(api, READ, {
|
|
48
|
-
method: "get",
|
|
49
|
-
path: "/v1/sandboxes",
|
|
50
|
-
tags: ["Sandboxes"],
|
|
51
|
-
summary: "List sandboxes",
|
|
52
|
-
description: "Every sandbox with all the labels asked for. A token caller sees only the sandboxes its grants reach.",
|
|
53
|
-
request: {
|
|
54
|
-
query: pageQuery.extend({
|
|
55
|
-
label: z
|
|
56
|
-
.union([z.string(), z.array(z.string())])
|
|
57
|
-
.optional()
|
|
58
|
-
.meta({ description: "`key=value`; repeat it to require several labels" }),
|
|
59
|
-
}),
|
|
60
|
-
},
|
|
61
|
-
responses: { 200: json(z.union([ListSandboxesResponse, SandboxPage]), "The sandboxes; limit opts into pagination") },
|
|
62
|
-
}, async (c) => jsonResponse(200, c.req.query("limit") !== undefined
|
|
63
|
-
? await sandboxPage(c.env.tenant, c.get("scope"), c.req.query(), labelsOf(c.req.queries("label")))
|
|
64
|
-
: await listSandboxes(c.env.tenant, labelsOf(c.req.queries("label")), c.get("scope"))));
|
|
65
|
-
tenantRoute(api, WRITE, {
|
|
66
|
-
method: "put",
|
|
67
|
-
path: "/v1/sandboxes/{sandboxId}",
|
|
68
|
-
tags: ["Sandboxes"],
|
|
69
|
-
summary: "Create or find a sandbox",
|
|
70
|
-
description: "Creates the sandbox within the Tenant's limits, or answers the one with this id, so get-or-create is one call. Its spec is fixed once it exists; labels, when sent, replace its labels. Kind `pod` needs sandbox pods (`nylorun sandbox enable`): it is created at once, and a PUT on an existing pod sandbox starts it again when it was stopped, or revives it with a longer `lifecycle.ttl`.",
|
|
71
|
-
request: {
|
|
72
|
-
params: sandboxId,
|
|
73
|
-
body: { required: true, content: { "application/json": { schema: PutSandboxRequest } } },
|
|
74
|
-
},
|
|
75
|
-
responses: {
|
|
76
|
-
200: json(SandboxView, "The sandbox"),
|
|
77
|
-
409: {
|
|
78
|
-
description: "A sandbox with this id has another spec, the Tenant holds as many sandboxes as it allows (`limit_exceeded`), kind pod without sandbox pods (`sandbox_unavailable`), or a lost pod sandbox (`sandbox_lost`)",
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
}, async (c) => {
|
|
82
|
-
const id = idOf(c.req.param("sandboxId"));
|
|
83
|
-
const body = PutSandboxRequestSchema.parse(await readJson(c.req.raw));
|
|
84
|
-
return jsonResponse(200, await putSandbox(c.env.tenant, id, body, c.get("scope")));
|
|
85
|
-
});
|
|
86
|
-
tenantRoute(api, READ, {
|
|
87
|
-
method: "get",
|
|
88
|
-
path: "/v1/sandboxes/{sandboxId}",
|
|
89
|
-
tags: ["Sandboxes"],
|
|
90
|
-
summary: "Get a sandbox",
|
|
91
|
-
description: "Its spec, labels, state and the sessions attached to it (acting for a person, only theirs).",
|
|
92
|
-
request: { params: sandboxId },
|
|
93
|
-
responses: { 200: json(SandboxView, "The sandbox") },
|
|
94
|
-
}, async (c) => jsonResponse(200, await getSandbox(c.env.tenant, idOf(c.req.param("sandboxId")), c.get("scope"))));
|
|
95
|
-
tenantRoute(api, READ, {
|
|
96
|
-
method: "get",
|
|
97
|
-
path: "/v1/sandboxes/{sandboxId}/events",
|
|
98
|
-
tags: ["Sandboxes"],
|
|
99
|
-
summary: "Read a sandbox's lifecycle events",
|
|
100
|
-
description: "`sandbox.created`, `sandbox.attached`, `sandbox.detached` and `sandbox.deleted`, in order, numbered from 0.",
|
|
101
|
-
request: {
|
|
102
|
-
params: sandboxId,
|
|
103
|
-
query: z.object({
|
|
104
|
-
from: z.string().optional().meta({ description: "The first `seq` to return" }),
|
|
105
|
-
}),
|
|
106
|
-
},
|
|
107
|
-
responses: { 200: json(ListSandboxEventsResponse, "The events") },
|
|
108
|
-
}, async (c) => {
|
|
109
|
-
const from = c.req.query("from");
|
|
110
|
-
if (from !== undefined && !/^\d+$/.test(from))
|
|
111
|
-
fail(400, "from must be a seq");
|
|
112
|
-
return jsonResponse(200, await sandboxEventsOf(c.env.tenant, idOf(c.req.param("sandboxId")), c.get("scope"), from === undefined ? undefined : Number(from)));
|
|
113
|
-
});
|
|
114
|
-
tenantRoute(api, WRITE, {
|
|
115
|
-
method: "delete",
|
|
116
|
-
path: "/v1/sandboxes/{sandboxId}",
|
|
117
|
-
tags: ["Sandboxes"],
|
|
118
|
-
summary: "Delete a sandbox",
|
|
119
|
-
description: "Deletes the sandbox and its files. Sessions attached to it stay attached by id; their next turn is refused until a sandbox with this id exists again.",
|
|
120
|
-
request: { params: sandboxId },
|
|
121
|
-
responses: {
|
|
122
|
-
200: json(DeleteSandboxResponse, "Deleted, or there was none"),
|
|
123
|
-
409: { description: "A session attached to it has a turn running (`sandbox_busy`)" },
|
|
124
|
-
},
|
|
125
|
-
}, async (c) => jsonResponse(200, await deleteSandbox(c.env.tenant, idOf(c.req.param("sandboxId")), c.get("scope"))));
|
|
126
|
-
for (const [action, summary, description, run] of [
|
|
127
|
-
[
|
|
128
|
-
"stop",
|
|
129
|
-
"Stop a pod sandbox",
|
|
130
|
-
"Suspends the pod: its volume is kept, and the next turn of a session attached to it (or a PUT) starts it again. Refused during a turn (`sandbox_busy`).",
|
|
131
|
-
stopSandbox,
|
|
132
|
-
],
|
|
133
|
-
[
|
|
134
|
-
"reset",
|
|
135
|
-
"Reset a pod sandbox",
|
|
136
|
-
"A new pod on a new, empty volume; the old pod and volume are deleted. The way out of `sandbox_lost`. Refused during a turn (`sandbox_busy`).",
|
|
137
|
-
resetSandbox,
|
|
138
|
-
],
|
|
139
|
-
])
|
|
140
|
-
tenantRoute(api, WRITE, {
|
|
141
|
-
method: "post",
|
|
142
|
-
path: `/v1/sandboxes/{sandboxId}/${action}`,
|
|
143
|
-
tags: ["Sandboxes"],
|
|
144
|
-
summary,
|
|
145
|
-
description,
|
|
146
|
-
request: { params: sandboxId },
|
|
147
|
-
responses: {
|
|
148
|
-
200: json(SandboxView, "The sandbox"),
|
|
149
|
-
400: { description: "The sandbox is virtual" },
|
|
150
|
-
409: { description: "A turn holds it (`sandbox_busy`), or no sandbox pods (`sandbox_unavailable`)" },
|
|
151
|
-
},
|
|
152
|
-
}, async (c) => jsonResponse(200, await run(c.env.tenant, idOf(c.req.param("sandboxId")), c.get("scope"))));
|
|
153
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vaults and their credentials (`/v1/tenant/vaults/**`, the Management API, protocol 8): secrets
|
|
3
|
-
* a session's tools use. Only a management key (or Studio's key, acting as itself) reaches these
|
|
4
|
-
* routes; an application key is `403 key_role_mismatch`, and nothing acts for a subject here. The
|
|
5
|
-
* installation's own vaults (`scope: "installation"`) attach to any session (`vaultIds`); a vault
|
|
6
|
-
* of one person (`ownerUserId`) attaches only to that person's sessions.
|
|
7
|
-
*/
|
|
8
|
-
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
9
|
-
import type { TenantEnv } from "../app.js";
|
|
10
|
-
export declare function vaultRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { CreateCredentialRequestSchema, CreateVaultRequestSchema, RotateCredentialRequestSchema, } from "@nylorun/core/contracts";
|
|
3
|
-
import { CreateCredentialRequest, CreateVaultRequest, CredentialInfo, DeletedResponse, ListCredentialsResponse, ListVaultsResponse, RotateCredentialRequest, VaultInfo, } from "../../components.js";
|
|
4
|
-
import { readJson } from "../body.js";
|
|
5
|
-
import { tenantRoute } from "../define.js";
|
|
6
|
-
import { jsonResponse } from "../respond.js";
|
|
7
|
-
/** The Management API's vault routes (`/v1/tenant/vaults`): a management key. */
|
|
8
|
-
const MANAGEMENT = { credentials: ["management"], scopes: "never" };
|
|
9
|
-
const json = (schema, description) => ({
|
|
10
|
-
description,
|
|
11
|
-
content: { "application/json": { schema } },
|
|
12
|
-
});
|
|
13
|
-
const body = (schema) => ({
|
|
14
|
-
required: true,
|
|
15
|
-
content: { "application/json": { schema } },
|
|
16
|
-
});
|
|
17
|
-
const vaultId = z.object({ vaultId: z.string() });
|
|
18
|
-
const credentialId = vaultId.extend({ credentialId: z.string() });
|
|
19
|
-
/** The vault routes under `base` (`/v1/tenant/vaults`). */
|
|
20
|
-
function vaultRoutesAt(api, base, access) {
|
|
21
|
-
tenantRoute(api, access, {
|
|
22
|
-
method: "post",
|
|
23
|
-
path: `${base}`,
|
|
24
|
-
tags: ["Vaults"],
|
|
25
|
-
summary: "Create a vault",
|
|
26
|
-
description: "With `scope: \"installation\"` the installation's own vault, owned by `installation`, which any session may attach; or a vault of one person (`ownerUserId`), which only that person's sessions attach.",
|
|
27
|
-
request: { body: body(CreateVaultRequest) },
|
|
28
|
-
responses: {
|
|
29
|
-
200: json(VaultInfo, "The vault"),
|
|
30
|
-
409: { description: "The idempotency key was used for another vault" },
|
|
31
|
-
},
|
|
32
|
-
}, async (c) => {
|
|
33
|
-
const request = CreateVaultRequestSchema.parse(await readJson(c.req.raw));
|
|
34
|
-
return jsonResponse(200, await c.env.tenant.vault.createVault(request));
|
|
35
|
-
});
|
|
36
|
-
tenantRoute(api, access, {
|
|
37
|
-
method: "get",
|
|
38
|
-
path: `${base}`,
|
|
39
|
-
tags: ["Vaults"],
|
|
40
|
-
summary: "List vaults",
|
|
41
|
-
description: "The installation vaults, after the vaults of `ownerUserId` when it names a person.",
|
|
42
|
-
request: {
|
|
43
|
-
query: z.object({
|
|
44
|
-
ownerUserId: z
|
|
45
|
-
.string()
|
|
46
|
-
.optional()
|
|
47
|
-
.meta({ description: "Also list this person's vaults" }),
|
|
48
|
-
}),
|
|
49
|
-
},
|
|
50
|
-
responses: { 200: json(ListVaultsResponse, "The vaults") },
|
|
51
|
-
}, async (c) => {
|
|
52
|
-
return jsonResponse(200, {
|
|
53
|
-
vaults: await c.env.tenant.vault.listVaults(c.req.query("ownerUserId"), {
|
|
54
|
-
installation: true,
|
|
55
|
-
}),
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
tenantRoute(api, access, {
|
|
59
|
-
method: "get",
|
|
60
|
-
path: `${base}/{vaultId}`,
|
|
61
|
-
tags: ["Vaults"],
|
|
62
|
-
summary: "Get a vault",
|
|
63
|
-
request: { params: vaultId },
|
|
64
|
-
responses: { 200: json(VaultInfo, "The vault") },
|
|
65
|
-
}, async (c) => {
|
|
66
|
-
return jsonResponse(200, await c.env.tenant.vault.getVault(c.req.param("vaultId")));
|
|
67
|
-
});
|
|
68
|
-
tenantRoute(api, access, {
|
|
69
|
-
method: "delete",
|
|
70
|
-
path: `${base}/{vaultId}`,
|
|
71
|
-
tags: ["Vaults"],
|
|
72
|
-
summary: "Delete a vault and its credentials",
|
|
73
|
-
request: { params: vaultId },
|
|
74
|
-
responses: { 200: json(DeletedResponse, "Deleted") },
|
|
75
|
-
}, async (c) => {
|
|
76
|
-
return jsonResponse(200, await c.env.tenant.vault.deleteVault(c.req.param("vaultId")));
|
|
77
|
-
});
|
|
78
|
-
tenantRoute(api, access, {
|
|
79
|
-
method: "post",
|
|
80
|
-
path: `${base}/{vaultId}/credentials`,
|
|
81
|
-
tags: ["Vaults"],
|
|
82
|
-
summary: "Add a credential",
|
|
83
|
-
description: "A bearer token, bound to the URL a tool may send it to.",
|
|
84
|
-
request: { params: vaultId, body: body(CreateCredentialRequest) },
|
|
85
|
-
responses: { 200: json(CredentialInfo, "The credential, without its secret") },
|
|
86
|
-
}, async (c) => {
|
|
87
|
-
const request = CreateCredentialRequestSchema.parse(await readJson(c.req.raw));
|
|
88
|
-
return jsonResponse(200, await c.env.tenant.keys.createCredential(c.req.param("vaultId"), request));
|
|
89
|
-
});
|
|
90
|
-
tenantRoute(api, access, {
|
|
91
|
-
method: "get",
|
|
92
|
-
path: `${base}/{vaultId}/credentials`,
|
|
93
|
-
tags: ["Vaults"],
|
|
94
|
-
summary: "List a vault's credentials",
|
|
95
|
-
request: { params: vaultId },
|
|
96
|
-
responses: { 200: json(ListCredentialsResponse, "The credentials, without their secrets") },
|
|
97
|
-
}, async (c) => {
|
|
98
|
-
return jsonResponse(200, {
|
|
99
|
-
credentials: await c.env.tenant.vault.listCredentials(c.req.param("vaultId")),
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
tenantRoute(api, access, {
|
|
103
|
-
method: "get",
|
|
104
|
-
path: `${base}/{vaultId}/credentials/{credentialId}`,
|
|
105
|
-
tags: ["Vaults"],
|
|
106
|
-
summary: "Get a credential",
|
|
107
|
-
request: { params: credentialId },
|
|
108
|
-
responses: { 200: json(CredentialInfo, "The credential, without its secret") },
|
|
109
|
-
}, async (c) => {
|
|
110
|
-
return jsonResponse(200, await c.env.tenant.vault.getCredential(c.req.param("vaultId"), c.req.param("credentialId")));
|
|
111
|
-
});
|
|
112
|
-
tenantRoute(api, access, {
|
|
113
|
-
method: "post",
|
|
114
|
-
path: `${base}/{vaultId}/credentials/{credentialId}`,
|
|
115
|
-
tags: ["Vaults"],
|
|
116
|
-
summary: "Rotate a credential's secret",
|
|
117
|
-
request: { params: credentialId, body: body(RotateCredentialRequest) },
|
|
118
|
-
responses: {
|
|
119
|
-
200: json(CredentialInfo, "The credential"),
|
|
120
|
-
409: { description: "A credential's type cannot change" },
|
|
121
|
-
},
|
|
122
|
-
}, async (c) => {
|
|
123
|
-
const request = RotateCredentialRequestSchema.parse(await readJson(c.req.raw));
|
|
124
|
-
return jsonResponse(200, await c.env.tenant.keys.rotateCredential(c.req.param("vaultId"), c.req.param("credentialId"), request));
|
|
125
|
-
});
|
|
126
|
-
tenantRoute(api, access, {
|
|
127
|
-
method: "delete",
|
|
128
|
-
path: `${base}/{vaultId}/credentials/{credentialId}`,
|
|
129
|
-
tags: ["Vaults"],
|
|
130
|
-
summary: "Delete a credential",
|
|
131
|
-
request: { params: credentialId },
|
|
132
|
-
responses: { 200: json(DeletedResponse, "Deleted") },
|
|
133
|
-
}, async (c) => {
|
|
134
|
-
return jsonResponse(200, await c.env.tenant.vault.deleteCredential(c.req.param("vaultId"), c.req.param("credentialId")));
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
export function vaultRoutes(api) {
|
|
138
|
-
vaultRoutesAt(api, "/v1/tenant/vaults", MANAGEMENT);
|
|
139
|
-
}
|
package/dist/record/sandbox.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { type SandboxEvent, type SandboxEventPayload, type SandboxEventType } from "@nylorun/core/contracts";
|
|
2
|
-
/** The sandbox stream's two statements, in the caller's transaction. */
|
|
3
|
-
export interface SandboxRecordWriter {
|
|
4
|
-
/** The seq the sandbox's next event takes: one past its last, or 0. */
|
|
5
|
-
nextSeq(sandboxId: string): Promise<number>;
|
|
6
|
-
insert(row: {
|
|
7
|
-
sandboxId: string;
|
|
8
|
-
seq: number;
|
|
9
|
-
type: string;
|
|
10
|
-
body: SandboxEvent;
|
|
11
|
-
}): Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
export interface SandboxAppendInput<T extends SandboxEventType> {
|
|
14
|
-
tenantId: string;
|
|
15
|
-
sandboxId: string;
|
|
16
|
-
time: Date;
|
|
17
|
-
type: T;
|
|
18
|
-
payload: SandboxEventPayload<T>;
|
|
19
|
-
}
|
|
20
|
-
/** Builds the event and checks it against the sandbox event catalog. */
|
|
21
|
-
export declare function buildSandboxEvent<T extends SandboxEventType>(input: SandboxAppendInput<T> & {
|
|
22
|
-
seq: number;
|
|
23
|
-
}): SandboxEvent;
|
|
24
|
-
/** Appends one event to the sandbox's stream through `writer`. */
|
|
25
|
-
export declare function appendSandboxEvent<T extends SandboxEventType>(writer: SandboxRecordWriter, input: SandboxAppendInput<T>): Promise<SandboxEvent>;
|
package/dist/record/sandbox.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A sandbox's lifecycle stream (blueprint D39, F7.1): `sandbox.created`, `sandbox.attached`,
|
|
3
|
-
* `sandbox.detached` and `sandbox.deleted`, on the `nylorun.sandbox-event/1` envelope, numbered
|
|
4
|
-
* from 0 per sandbox id in `nylorun_streams.sandbox_events`. The record module is its only
|
|
5
|
-
* writer, as for session events; the store runs the two statements through
|
|
6
|
-
* `SandboxRecordWriter` in the caller's transaction, under the sandbox row's lock (or, for a
|
|
7
|
-
* sandbox being created, its new row).
|
|
8
|
-
*
|
|
9
|
-
* The stream lives in the record only: it is not published to the stream relay, so no S2
|
|
10
|
-
* stream follows it yet. Clients read it with `GET /v1/sandboxes/{id}/events`.
|
|
11
|
-
*/
|
|
12
|
-
import { randomUUID } from "node:crypto";
|
|
13
|
-
import { z } from "zod";
|
|
14
|
-
import { SANDBOX_EVENT_PAYLOADS, SANDBOX_EVENT_SCHEMA, SandboxEventSchema, } from "@nylorun/core/contracts";
|
|
15
|
-
import { InvalidEventError } from "./envelope.js";
|
|
16
|
-
/** Builds the event and checks it against the sandbox event catalog. */
|
|
17
|
-
export function buildSandboxEvent(input) {
|
|
18
|
-
const payload = SANDBOX_EVENT_PAYLOADS[input.type];
|
|
19
|
-
const checkedPayload = payload.safeParse(input.payload);
|
|
20
|
-
if (!checkedPayload.success)
|
|
21
|
-
throw new InvalidEventError(input.type, z.prettifyError(checkedPayload.error));
|
|
22
|
-
const event = JSON.parse(JSON.stringify({
|
|
23
|
-
schema: SANDBOX_EVENT_SCHEMA,
|
|
24
|
-
eventId: randomUUID(),
|
|
25
|
-
tenantId: input.tenantId,
|
|
26
|
-
sandboxId: input.sandboxId,
|
|
27
|
-
seq: input.seq,
|
|
28
|
-
time: input.time.toISOString(),
|
|
29
|
-
type: input.type,
|
|
30
|
-
payload: input.payload,
|
|
31
|
-
}));
|
|
32
|
-
const checked = SandboxEventSchema.safeParse(event);
|
|
33
|
-
if (!checked.success)
|
|
34
|
-
throw new InvalidEventError(input.type, z.prettifyError(checked.error));
|
|
35
|
-
return event;
|
|
36
|
-
}
|
|
37
|
-
/** Appends one event to the sandbox's stream through `writer`. */
|
|
38
|
-
export async function appendSandboxEvent(writer, input) {
|
|
39
|
-
const seq = await writer.nextSeq(input.sandboxId);
|
|
40
|
-
const event = buildSandboxEvent({ ...input, seq });
|
|
41
|
-
await writer.insert({ sandboxId: input.sandboxId, seq, type: input.type, body: event });
|
|
42
|
-
return event;
|
|
43
|
-
}
|