@nylorun/runtime 0.12.0-beta → 0.14.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 +361 -0
- package/README.md +69 -15
- package/dist/adapters/execution/restate.d.ts +7 -2
- package/dist/adapters/execution/restate.js +38 -8
- package/dist/adapters/replication/pgoutput.d.ts +16 -0
- package/dist/adapters/replication/pgoutput.js +169 -0
- package/dist/adapters/streams/s2.js +37 -20
- package/dist/admin-openapi.json +1071 -0
- package/dist/api/a2a/card.d.ts +15 -0
- package/dist/api/a2a/card.js +24 -0
- package/dist/api/a2a/endpoint.d.ts +8 -0
- package/dist/api/a2a/endpoint.js +81 -0
- package/dist/api/a2a/protocol.d.ts +144 -0
- package/dist/api/a2a/protocol.js +188 -0
- package/dist/api/a2a/routes.d.ts +19 -0
- package/dist/api/a2a/routes.js +289 -0
- package/dist/api/a2a/tasks.d.ts +50 -0
- package/dist/api/a2a/tasks.js +186 -0
- package/dist/api/ag-ui/endpoint.d.ts +8 -0
- package/dist/api/ag-ui/endpoint.js +126 -0
- package/dist/api/ag-ui/history.d.ts +7 -0
- package/dist/api/ag-ui/history.js +60 -0
- package/dist/api/ag-ui/routes.d.ts +32 -0
- package/dist/api/ag-ui/routes.js +305 -0
- package/dist/api/ag-ui/session-id.d.ts +1 -0
- package/dist/api/ag-ui/session-id.js +12 -0
- package/dist/api/ag-ui/sse.d.ts +9 -0
- package/dist/api/ag-ui/sse.js +7 -0
- package/dist/api/ag-ui/translate.d.ts +38 -0
- package/dist/api/ag-ui/translate.js +222 -0
- package/dist/api/components.d.ts +7825 -0
- package/dist/api/components.js +83 -0
- package/dist/api/http/app.d.ts +18 -0
- package/dist/api/http/app.js +58 -0
- package/dist/api/http/body.d.ts +4 -0
- package/dist/api/http/body.js +37 -0
- package/dist/api/http/define.d.ts +39 -0
- package/dist/api/http/define.js +130 -0
- package/dist/api/http/respond.d.ts +9 -0
- package/dist/api/http/respond.js +44 -0
- package/dist/api/http/routes/access.d.ts +24 -0
- package/dist/api/http/routes/access.js +259 -0
- package/dist/api/http/routes/actions.d.ts +8 -0
- package/dist/api/http/routes/actions.js +76 -0
- package/dist/api/http/routes/endpoints.d.ts +7 -0
- package/dist/api/http/routes/endpoints.js +100 -0
- package/dist/api/http/routes/sessions.d.ts +3 -0
- package/dist/api/http/routes/sessions.js +205 -0
- package/dist/api/http/routes/tenant.d.ts +10 -0
- package/dist/api/http/routes/tenant.js +172 -0
- package/dist/api/http/routes/vaults.d.ts +8 -0
- package/dist/api/http/routes/vaults.js +167 -0
- package/dist/api/openapi.d.ts +19 -0
- package/dist/api/openapi.js +138 -0
- package/dist/api/route.d.ts +12 -0
- package/dist/api/route.js +4 -0
- package/dist/core/bearer.d.ts +8 -0
- package/dist/core/bearer.js +11 -0
- package/dist/core/flow-host.d.ts +7 -15
- package/dist/core/flow-host.js +19 -41
- package/dist/core/sandbox-routes.d.ts +12 -7
- package/dist/core/sandbox-routes.js +24 -25
- package/dist/execution/memory.d.ts +8 -5
- package/dist/execution/memory.js +33 -13
- package/dist/execution/types.d.ts +38 -6
- package/dist/execution/types.js +12 -3
- package/dist/host/admin-api.d.ts +22 -0
- package/dist/host/admin-api.js +178 -0
- package/dist/host/app.d.ts +34 -0
- package/dist/host/app.js +185 -0
- package/dist/host/config-for.d.ts +2 -0
- package/dist/host/config-for.js +1 -0
- package/dist/host/config.d.ts +11 -0
- package/dist/host/cors.d.ts +27 -0
- package/dist/host/cors.js +64 -0
- package/dist/host/create-host.d.ts +31 -3
- package/dist/host/create-host.js +168 -327
- package/dist/host/http.d.ts +14 -3
- package/dist/host/http.js +64 -23
- package/dist/host/main.js +55 -4
- package/dist/host/stack-config.d.ts +20 -0
- package/dist/host/stack-config.js +55 -0
- package/dist/mcp/pool.d.ts +19 -1
- package/dist/mcp/pool.js +60 -10
- package/dist/model/catalog.d.ts +2 -10
- package/dist/model/classify.d.ts +13 -0
- package/dist/model/classify.js +61 -0
- package/dist/model/models.d.ts +10 -1
- package/dist/model/models.js +14 -6
- package/dist/model/pi-model.d.ts +17 -2
- package/dist/model/pi-model.js +366 -222
- package/dist/openapi.json +25696 -0
- package/dist/sandbox/manager.d.ts +13 -1
- package/dist/sandbox/manager.js +8 -11
- package/dist/sandbox/resolve.d.ts +33 -0
- package/dist/sandbox/resolve.js +81 -0
- package/dist/sandbox/session-sandbox.d.ts +11 -0
- package/dist/sandbox/session-sandbox.js +51 -0
- package/dist/sandbox/share.d.ts +14 -2
- package/dist/sandbox/share.js +33 -3
- package/dist/sandbox/tenant-config.d.ts +37 -0
- package/dist/sandbox/tenant-config.js +51 -0
- package/dist/sandbox/tools.d.ts +7 -9
- package/dist/sandbox/tools.js +11 -3
- package/dist/sandbox/types.d.ts +8 -2
- package/dist/store/event.d.ts +19 -0
- package/dist/store/event.js +49 -0
- package/dist/store/memory.d.ts +20 -8
- package/dist/store/memory.js +265 -100
- package/dist/store/postgres/connect.d.ts +13 -0
- package/dist/store/postgres/connect.js +5 -0
- package/dist/store/postgres/migrations/003_subject_tokens.d.ts +8 -0
- package/dist/store/postgres/migrations/003_subject_tokens.js +42 -0
- package/dist/store/postgres/migrations/004_publishable_keys.d.ts +6 -0
- package/dist/store/postgres/migrations/004_publishable_keys.js +18 -0
- package/dist/store/postgres/migrations/005_action_endpoints.d.ts +6 -0
- package/dist/store/postgres/migrations/005_action_endpoints.js +32 -0
- package/dist/store/postgres/migrations/006_drop_executors.d.ts +11 -0
- package/dist/store/postgres/migrations/006_drop_executors.js +32 -0
- package/dist/store/postgres/migrations/007_event_time.d.ts +7 -0
- package/dist/store/postgres/migrations/007_event_time.js +14 -0
- package/dist/store/postgres/migrations/008_durable_streams.d.ts +13 -0
- package/dist/store/postgres/migrations/008_durable_streams.js +35 -0
- package/dist/store/postgres/migrations/index.d.ts +5 -1
- package/dist/store/postgres/migrations/index.js +22 -2
- package/dist/store/postgres/migrations/shared/index.d.ts +31 -0
- package/dist/store/postgres/migrations/shared/index.js +92 -0
- package/dist/store/postgres/record.d.ts +11 -0
- package/dist/store/postgres/record.js +64 -0
- package/dist/store/postgres/store.js +337 -95
- package/dist/store/postgres/tenants.js +14 -0
- package/dist/store/types.d.ts +176 -81
- package/dist/streams/basin.d.ts +18 -1
- package/dist/streams/basin.js +34 -2
- package/dist/streams/control.d.ts +18 -0
- package/dist/streams/control.js +29 -0
- package/dist/streams/memory.d.ts +3 -1
- package/dist/streams/memory.js +14 -8
- package/dist/streams/relay/core.d.ts +35 -0
- package/dist/streams/relay/core.js +366 -0
- package/dist/streams/relay/memory.d.ts +69 -0
- package/dist/streams/relay/memory.js +176 -0
- package/dist/streams/relay/types.d.ts +77 -0
- package/dist/streams/relay/types.js +7 -0
- package/dist/streams/types.d.ts +66 -36
- package/dist/streams/types.js +18 -53
- package/dist/tenant/access-policy.d.ts +30 -0
- package/dist/tenant/access-policy.js +52 -0
- package/dist/tenant/actions.d.ts +10 -149
- package/dist/tenant/actions.js +5 -167
- package/dist/tenant/advance.js +32 -0
- package/dist/tenant/auth.d.ts +19 -17
- package/dist/tenant/auth.js +90 -93
- package/dist/tenant/browser.d.ts +15 -0
- package/dist/tenant/browser.js +39 -0
- package/dist/tenant/commands.d.ts +18 -2
- package/dist/tenant/commands.js +121 -129
- package/dist/tenant/context.d.ts +75 -18
- package/dist/tenant/context.js +14 -10
- package/dist/tenant/delivery-token.d.ts +41 -0
- package/dist/tenant/delivery-token.js +105 -0
- package/dist/tenant/delivery.d.ts +62 -0
- package/dist/tenant/delivery.js +476 -0
- package/dist/tenant/effects.d.ts +5 -0
- package/dist/tenant/effects.js +138 -48
- package/dist/tenant/endpoints.d.ts +67 -0
- package/dist/tenant/endpoints.js +90 -0
- package/dist/tenant/ephemeral.d.ts +6 -0
- package/dist/tenant/ephemeral.js +60 -36
- package/dist/tenant/http.d.ts +8 -9
- package/dist/tenant/http.js +13 -27
- package/dist/tenant/jwt.d.ts +16 -0
- package/dist/tenant/jwt.js +50 -0
- package/dist/tenant/module.d.ts +3 -0
- package/dist/tenant/module.js +6 -12
- package/dist/tenant/outbound.d.ts +44 -0
- package/dist/tenant/outbound.js +127 -0
- package/dist/tenant/pool.d.ts +0 -2
- package/dist/tenant/pool.js +0 -18
- package/dist/tenant/reset.d.ts +0 -4
- package/dist/tenant/reset.js +0 -5
- package/dist/tenant/runtime.d.ts +10 -20
- package/dist/tenant/runtime.js +59 -42
- package/dist/tenant/scheduler.d.ts +7 -2
- package/dist/tenant/scheduler.js +7 -3
- package/dist/tenant/session-streams.d.ts +125 -0
- package/dist/tenant/session-streams.js +399 -0
- package/dist/tenant/sessions.d.ts +28 -4
- package/dist/tenant/sessions.js +118 -24
- package/dist/tenant/signing-keys.d.ts +55 -0
- package/dist/tenant/signing-keys.js +172 -0
- package/dist/tenant/slim.d.ts +8 -0
- package/dist/tenant/slim.js +21 -0
- package/dist/tenant/status.d.ts +0 -3
- package/dist/tenant/status.js +19 -12
- package/dist/tenant/streams.d.ts +60 -67
- package/dist/tenant/streams.js +140 -208
- package/dist/tenant/subject-limits.d.ts +16 -0
- package/dist/tenant/subject-limits.js +45 -0
- package/dist/tenant/sweep.d.ts +1 -10
- package/dist/tenant/sweep.js +29 -69
- package/dist/tenant/tokens.d.ts +14 -0
- package/dist/tenant/tokens.js +178 -0
- package/dist/tenant/transcript.d.ts +48 -5
- package/dist/tenant/transcript.js +58 -1
- package/dist/tenant/types.d.ts +29 -7
- package/dist/tenant/worker.d.ts +3 -1
- package/dist/tenant/worker.js +9 -3
- package/dist/vault/service.d.ts +18 -2
- package/dist/vault/service.js +57 -13
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +20 -8
- package/dist/core/executors.d.ts +0 -44
- package/dist/core/executors.js +0 -95
- package/dist/streams/relay.d.ts +0 -37
- package/dist/streams/relay.js +0 -254
- package/dist/tenant/live.d.ts +0 -92
- package/dist/tenant/live.js +0 -290
- package/dist/tenant/routes-tenant.d.ts +0 -12
- package/dist/tenant/routes-tenant.js +0 -137
- package/dist/tenant/routes.d.ts +0 -9
- package/dist/tenant/routes.js +0 -151
package/dist/streams/types.d.ts
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Durable Streams seam (Durable Streams §8).
|
|
3
|
+
*
|
|
4
|
+
* Durable Streams deliver what the record holds. Each Tenant has one S2 basin per basin
|
|
5
|
+
* generation (`streams/basin.ts`); inside it:
|
|
6
|
+
*
|
|
7
|
+
* | Stream | Contents | Written by | Read by |
|
|
8
|
+
* | --- | --- | --- | --- |
|
|
9
|
+
* | `sessions/<sessionId>` | every event of the session, in sequence | the stream relay, from the record | history and session SSE |
|
|
10
|
+
* | `tenant/control` | `session.cancel`, `sessions.reset` and `subject.revoked` signals | API nodes | every process with the Tenant open |
|
|
11
|
+
*
|
|
12
|
+
* **Basin generations.** A session id is unique within its Tenant's basin generation. A
|
|
13
|
+
* Tenant reset, the only path that frees ids, moves the Tenant to the next generation, so
|
|
14
|
+
* a session created again with the same id starts in an empty basin at sequence 0; the old
|
|
15
|
+
* basin is deleted afterwards. The cursor is `base64url("<sessionId>:<seq>")`.
|
|
16
|
+
*
|
|
17
|
+
* S2 is the supported implementation (`adapters/streams/s2.ts`, the only file
|
|
18
|
+
* importing the S2 SDK); `streams/memory.ts` is the in-memory fake.
|
|
19
|
+
*
|
|
20
|
+
* ## Guarantees every implementation keeps
|
|
21
|
+
*
|
|
22
|
+
* - **Sequence numbers.** Each stream numbers its records from 0 without gaps.
|
|
23
|
+
* The tail is the sequence the next appended record gets (0 for a stream
|
|
24
|
+
* that does not exist yet).
|
|
25
|
+
* - **Conditional appends.** With `matchSeq`, a batch is appended only when the
|
|
26
|
+
* tail equals `matchSeq`; otherwise nothing is written and the result is a
|
|
27
|
+
* `SeqMismatch` carrying the current tail. The relay appends a session
|
|
28
|
+
* stream with `matchSeq` set to the record row's sequence, so a retried
|
|
29
|
+
* append after an unacknowledged success is detected and never duplicated.
|
|
30
|
+
* - **Batches are atomic.** A batch is appended entirely or not at all.
|
|
31
|
+
* - **Reads resume.** `read` from `fromSeq` yields every record with
|
|
32
|
+
* `seq >= fromSeq` in order, with no gap between history and the live tail.
|
|
33
|
+
* - **Tenant scope.** Methods take a Tenant id, or a basin key from `basinOf`
|
|
34
|
+
* for a later generation. `ensureTenant` creates the basin (idempotent) and
|
|
35
|
+
* must run before appends; streams are created on first append or read.
|
|
36
|
+
* `deleteTenant` removes the basin and every stream in it (with
|
|
37
|
+
* `allGenerations`, every generation's basin of the Tenant).
|
|
38
|
+
* - **Records are JSON.** Bodies are JSON-serializable values; implementations
|
|
39
|
+
* encode them as they need.
|
|
40
|
+
*/
|
|
1
41
|
/** A record as read from a stream. */
|
|
2
42
|
export interface StreamRecord<T = unknown> {
|
|
3
43
|
seq: number;
|
|
@@ -48,9 +88,14 @@ export interface DurableStreams {
|
|
|
48
88
|
tail(tenantId: string, stream: string): Promise<number>;
|
|
49
89
|
/** Creates the Tenant's basin. Idempotent. */
|
|
50
90
|
ensureTenant(tenantId: string): Promise<void>;
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Deletes the basin and all its streams. Idempotent. With `allGenerations`, given a Tenant
|
|
93
|
+
* id, also every later generation's basin (Tenant deletion).
|
|
94
|
+
*/
|
|
95
|
+
deleteTenant(tenantId: string, options?: {
|
|
96
|
+
allGenerations?: boolean;
|
|
97
|
+
}): Promise<void>;
|
|
98
|
+
/** Deletes one stream. Idempotent. */
|
|
54
99
|
deleteStream(tenantId: string, stream: string): Promise<void>;
|
|
55
100
|
/**
|
|
56
101
|
* Names of the Tenant's streams starting with `prefix`, in name order,
|
|
@@ -66,50 +111,35 @@ export interface DurableStreams {
|
|
|
66
111
|
probe?(signal: AbortSignal): Promise<void>;
|
|
67
112
|
}
|
|
68
113
|
export declare const SESSION_STREAM_PREFIX = "sessions/";
|
|
69
|
-
/** `work_available` signals for executor connections. */
|
|
70
|
-
export declare const WORK_STREAM = "tenant/work";
|
|
71
114
|
/** `session.cancel` and `sessions.reset` signals for every process with the Tenant open. */
|
|
72
115
|
export declare const CONTROL_STREAM = "tenant/control";
|
|
116
|
+
/** The stream of a session: `sessions/<sessionId>`. */
|
|
117
|
+
export declare function sessionStream(sessionId: string): string;
|
|
73
118
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*/
|
|
77
|
-
export declare const LEGACY_INCARNATION = "0";
|
|
78
|
-
/** A new session incarnation: 12 random base64url characters. */
|
|
79
|
-
export declare function newStreamIncarnation(): string;
|
|
80
|
-
/** The stream of one incarnation of a session: `sessions/<sessionId>/<incarnation>`. */
|
|
81
|
-
export declare function sessionStream(sessionId: string, incarnation: string): string;
|
|
82
|
-
/** The fields of a session document that name its stream. */
|
|
83
|
-
export interface SessionStreamRef {
|
|
84
|
-
id: string;
|
|
85
|
-
/** Set when the session is created (`newStreamIncarnation`); never changed. */
|
|
86
|
-
streamIncarnation?: string;
|
|
87
|
-
}
|
|
88
|
-
/** The stream of a session as stored now. */
|
|
89
|
-
export declare function streamOfSession(session: SessionStreamRef): string;
|
|
90
|
-
/** The session id and incarnation of a session stream, or undefined for other streams. */
|
|
91
|
-
export declare function parseSessionStream(stream: string): {
|
|
92
|
-
sessionId: string;
|
|
93
|
-
incarnation: string;
|
|
94
|
-
} | undefined;
|
|
95
|
-
/**
|
|
96
|
-
* Signals are not canonical events: they are appended without the outbox, and
|
|
97
|
-
* a lost signal costs latency, not correctness.
|
|
119
|
+
* Signals are not events: they are appended directly, never recorded, and a
|
|
120
|
+
* lost signal costs latency, not correctness.
|
|
98
121
|
*/
|
|
99
|
-
export interface WorkSignal {
|
|
100
|
-
type: "work_available";
|
|
101
|
-
}
|
|
102
122
|
/** Ends the advance of `sessionId` on the process running it. */
|
|
103
123
|
export interface SessionCancelSignal {
|
|
104
124
|
type: "session.cancel";
|
|
105
125
|
sessionId: string;
|
|
106
126
|
}
|
|
107
127
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
128
|
+
* The Tenant was reset and moved to basin generation `generation`. Appended to the old
|
|
129
|
+
* generation's `tenant/control`: each process switches its readers to the new basin and
|
|
130
|
+
* ends the streams of sessions the reset deleted.
|
|
110
131
|
*/
|
|
111
132
|
export interface SessionsResetSignal {
|
|
112
133
|
type: "sessions.reset";
|
|
134
|
+
generation?: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A subject's tokens older than `epoch` were revoked: each process ends that subject's
|
|
138
|
+
* streams opened with them.
|
|
139
|
+
*/
|
|
140
|
+
export interface SubjectRevokedSignal {
|
|
141
|
+
type: "subject.revoked";
|
|
142
|
+
subject: string;
|
|
143
|
+
epoch: number;
|
|
113
144
|
}
|
|
114
|
-
export type ControlSignal = SessionCancelSignal | SessionsResetSignal;
|
|
115
|
-
export declare const WORK_AVAILABLE: Readonly<WorkSignal>;
|
|
145
|
+
export type ControlSignal = SessionCancelSignal | SessionsResetSignal | SubjectRevokedSignal;
|
package/dist/streams/types.js
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Durable Streams seam (
|
|
2
|
+
* The Durable Streams seam (Durable Streams §8).
|
|
3
3
|
*
|
|
4
|
-
* Durable Streams
|
|
5
|
-
*
|
|
4
|
+
* Durable Streams deliver what the record holds. Each Tenant has one S2 basin per basin
|
|
5
|
+
* generation (`streams/basin.ts`); inside it:
|
|
6
6
|
*
|
|
7
7
|
* | Stream | Contents | Written by | Read by |
|
|
8
8
|
* | --- | --- | --- | --- |
|
|
9
|
-
* | `sessions/<sessionId
|
|
10
|
-
* | `tenant/
|
|
11
|
-
* | `tenant/control` | `session.cancel` and `sessions.reset` signals | API nodes | every process with the Tenant open |
|
|
9
|
+
* | `sessions/<sessionId>` | every event of the session, in sequence | the stream relay, from the record | history and session SSE |
|
|
10
|
+
* | `tenant/control` | `session.cancel`, `sessions.reset` and `subject.revoked` signals | API nodes | every process with the Tenant open |
|
|
12
11
|
*
|
|
13
|
-
* **
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* starting at sequence 0: nothing ever deletes and re-creates the same stream.
|
|
18
|
-
* Abandoned streams are deleted best effort afterwards
|
|
19
|
-
* (`collectSessionStreams` in `tenant/streams.ts`). The cursor stays
|
|
20
|
-
* `base64url("<sessionId>:<seq>")`; readers resolve the incarnation from the
|
|
21
|
-
* session.
|
|
12
|
+
* **Basin generations.** A session id is unique within its Tenant's basin generation. A
|
|
13
|
+
* Tenant reset, the only path that frees ids, moves the Tenant to the next generation, so
|
|
14
|
+
* a session created again with the same id starts in an empty basin at sequence 0; the old
|
|
15
|
+
* basin is deleted afterwards. The cursor is `base64url("<sessionId>:<seq>")`.
|
|
22
16
|
*
|
|
23
17
|
* S2 is the supported implementation (`adapters/streams/s2.ts`, the only file
|
|
24
18
|
* importing the S2 SDK); `streams/memory.ts` is the in-memory fake.
|
|
@@ -31,56 +25,27 @@
|
|
|
31
25
|
* - **Conditional appends.** With `matchSeq`, a batch is appended only when the
|
|
32
26
|
* tail equals `matchSeq`; otherwise nothing is written and the result is a
|
|
33
27
|
* `SeqMismatch` carrying the current tail. The relay appends a session
|
|
34
|
-
* stream with `matchSeq` set to the
|
|
28
|
+
* stream with `matchSeq` set to the record row's sequence, so a retried
|
|
35
29
|
* append after an unacknowledged success is detected and never duplicated.
|
|
36
30
|
* - **Batches are atomic.** A batch is appended entirely or not at all.
|
|
37
31
|
* - **Reads resume.** `read` from `fromSeq` yields every record with
|
|
38
32
|
* `seq >= fromSeq` in order, with no gap between history and the live tail.
|
|
39
|
-
* - **Tenant scope.**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* - **Tenant scope.** Methods take a Tenant id, or a basin key from `basinOf`
|
|
34
|
+
* for a later generation. `ensureTenant` creates the basin (idempotent) and
|
|
35
|
+
* must run before appends; streams are created on first append or read.
|
|
36
|
+
* `deleteTenant` removes the basin and every stream in it (with
|
|
37
|
+
* `allGenerations`, every generation's basin of the Tenant).
|
|
42
38
|
* - **Records are JSON.** Bodies are JSON-serializable values; implementations
|
|
43
39
|
* encode them as they need.
|
|
44
40
|
*/
|
|
45
|
-
import { randomBytes } from "node:crypto";
|
|
46
41
|
// ---------------------------------------------------------------------------
|
|
47
42
|
// Stream names and signal records
|
|
48
43
|
export const SESSION_STREAM_PREFIX = "sessions/";
|
|
49
|
-
/** `work_available` signals for executor connections. */
|
|
50
|
-
export const WORK_STREAM = "tenant/work";
|
|
51
44
|
/** `session.cancel` and `sessions.reset` signals for every process with the Tenant open. */
|
|
52
45
|
export const CONTROL_STREAM = "tenant/control";
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
* Random incarnations are 12 characters, so never this.
|
|
56
|
-
*/
|
|
57
|
-
export const LEGACY_INCARNATION = "0";
|
|
58
|
-
/** A new session incarnation: 12 random base64url characters. */
|
|
59
|
-
export function newStreamIncarnation() {
|
|
60
|
-
return randomBytes(9).toString("base64url");
|
|
61
|
-
}
|
|
62
|
-
/** The stream of one incarnation of a session: `sessions/<sessionId>/<incarnation>`. */
|
|
63
|
-
export function sessionStream(sessionId, incarnation) {
|
|
46
|
+
/** The stream of a session: `sessions/<sessionId>`. */
|
|
47
|
+
export function sessionStream(sessionId) {
|
|
64
48
|
if (!sessionId)
|
|
65
49
|
throw new Error("sessionId is required");
|
|
66
|
-
|
|
67
|
-
throw new Error("incarnation must be non-empty and contain no '/'");
|
|
68
|
-
return `${SESSION_STREAM_PREFIX}${sessionId}/${incarnation}`;
|
|
69
|
-
}
|
|
70
|
-
/** The stream of a session as stored now. */
|
|
71
|
-
export function streamOfSession(session) {
|
|
72
|
-
return sessionStream(session.id, session.streamIncarnation ?? LEGACY_INCARNATION);
|
|
73
|
-
}
|
|
74
|
-
/** The session id and incarnation of a session stream, or undefined for other streams. */
|
|
75
|
-
export function parseSessionStream(stream) {
|
|
76
|
-
if (!stream.startsWith(SESSION_STREAM_PREFIX))
|
|
77
|
-
return undefined;
|
|
78
|
-
const rest = stream.slice(SESSION_STREAM_PREFIX.length);
|
|
79
|
-
const slash = rest.lastIndexOf("/");
|
|
80
|
-
if (slash <= 0 || slash === rest.length - 1)
|
|
81
|
-
return undefined;
|
|
82
|
-
return { sessionId: rest.slice(0, slash), incarnation: rest.slice(slash + 1) };
|
|
50
|
+
return `${SESSION_STREAM_PREFIX}${sessionId}`;
|
|
83
51
|
}
|
|
84
|
-
export const WORK_AVAILABLE = Object.freeze({
|
|
85
|
-
type: "work_available",
|
|
86
|
-
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Tenant's access policy (Host feature `subject-tokens`): the roles subject tokens are
|
|
3
|
+
* minted for, what a publishable key grants alone (`anon`), and how long tokens live. One
|
|
4
|
+
* validated JSON document in the Tenant settings; a Tenant that never set one has no roles,
|
|
5
|
+
* so nothing can be minted.
|
|
6
|
+
*
|
|
7
|
+
* A token's permissions are resolved from the policy on every request, so editing a role
|
|
8
|
+
* changes outstanding tokens at their next request and removing one ends them.
|
|
9
|
+
*/
|
|
10
|
+
import { type AccessPolicy, type RoleLimits, type TokenScope } from "@nylorun/core/contracts";
|
|
11
|
+
import type { Tx } from "../store/types.js";
|
|
12
|
+
export declare const ACCESS_POLICY_SETTING = "access.policy";
|
|
13
|
+
export declare function readPolicy(t: Tx): Promise<AccessPolicy>;
|
|
14
|
+
export declare function writePolicy(t: Tx, policy: AccessPolicy): Promise<void>;
|
|
15
|
+
/** What a token may do right now: its role narrowed by what the mint asked for. */
|
|
16
|
+
export interface EffectiveAccess {
|
|
17
|
+
readonly role: string;
|
|
18
|
+
readonly scopes: ReadonlySet<TokenScope>;
|
|
19
|
+
readonly agents: ReadonlySet<string> | "*";
|
|
20
|
+
readonly limits?: RoleLimits;
|
|
21
|
+
}
|
|
22
|
+
/** Agents both lists allow; `"*"` allows every agent. */
|
|
23
|
+
export declare function intersectAgents(a: readonly string[] | "*", b: readonly string[] | "*" | undefined): ReadonlySet<string> | "*";
|
|
24
|
+
/**
|
|
25
|
+
* The role's permissions narrowed to `scopes` and `agents`, or undefined when the role no
|
|
26
|
+
* longer exists.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveRole(policy: AccessPolicy, role: string, scopes: readonly TokenScope[], agents?: readonly string[]): EffectiveAccess | undefined;
|
|
29
|
+
/** True when `agentId` is allowed by `agents`. */
|
|
30
|
+
export declare function agentAllowed(agents: ReadonlySet<string> | "*", agentId: string): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Tenant's access policy (Host feature `subject-tokens`): the roles subject tokens are
|
|
3
|
+
* minted for, what a publishable key grants alone (`anon`), and how long tokens live. One
|
|
4
|
+
* validated JSON document in the Tenant settings; a Tenant that never set one has no roles,
|
|
5
|
+
* so nothing can be minted.
|
|
6
|
+
*
|
|
7
|
+
* A token's permissions are resolved from the policy on every request, so editing a role
|
|
8
|
+
* changes outstanding tokens at their next request and removing one ends them.
|
|
9
|
+
*/
|
|
10
|
+
import { AccessPolicySchema, DEFAULT_ACCESS_POLICY, } from "@nylorun/core/contracts";
|
|
11
|
+
export const ACCESS_POLICY_SETTING = "access.policy";
|
|
12
|
+
export async function readPolicy(t) {
|
|
13
|
+
const stored = await t.getSetting(ACCESS_POLICY_SETTING);
|
|
14
|
+
if (stored === undefined)
|
|
15
|
+
return DEFAULT_ACCESS_POLICY;
|
|
16
|
+
// Only `writePolicy` stores it, after validation.
|
|
17
|
+
return AccessPolicySchema.parse(JSON.parse(stored));
|
|
18
|
+
}
|
|
19
|
+
export async function writePolicy(t, policy) {
|
|
20
|
+
await t.putSetting(ACCESS_POLICY_SETTING, JSON.stringify(AccessPolicySchema.parse(policy)));
|
|
21
|
+
}
|
|
22
|
+
/** Agents both lists allow; `"*"` allows every agent. */
|
|
23
|
+
export function intersectAgents(a, b) {
|
|
24
|
+
if (b === undefined || b === "*")
|
|
25
|
+
return a === "*" ? "*" : new Set(a);
|
|
26
|
+
if (a === "*")
|
|
27
|
+
return new Set(b);
|
|
28
|
+
const allowed = new Set(a);
|
|
29
|
+
return new Set(b.filter((agent) => allowed.has(agent)));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The role's permissions narrowed to `scopes` and `agents`, or undefined when the role no
|
|
33
|
+
* longer exists.
|
|
34
|
+
*/
|
|
35
|
+
export function resolveRole(policy, role, scopes, agents) {
|
|
36
|
+
const entry = Object.hasOwn(policy.roles, role)
|
|
37
|
+
? policy.roles[role]
|
|
38
|
+
: undefined;
|
|
39
|
+
if (!entry)
|
|
40
|
+
return undefined;
|
|
41
|
+
const allowed = new Set(entry.scopes);
|
|
42
|
+
return {
|
|
43
|
+
role,
|
|
44
|
+
scopes: new Set(scopes.filter((scope) => allowed.has(scope))),
|
|
45
|
+
agents: intersectAgents(entry.agents, agents),
|
|
46
|
+
...(entry.limits ? { limits: entry.limits } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** True when `agentId` is allowed by `agents`. */
|
|
50
|
+
export function agentAllowed(agents, agentId) {
|
|
51
|
+
return agents === "*" || agents.has(agentId);
|
|
52
|
+
}
|
package/dist/tenant/actions.d.ts
CHANGED
|
@@ -1,153 +1,14 @@
|
|
|
1
|
-
import type { IncomingMessage } from "node:http";
|
|
2
|
-
import { type RegisterExecutorsRequestSchema } from "@nylorun/core/contracts";
|
|
3
|
-
import { type ExecutorRecord } from "../core/executors.js";
|
|
4
1
|
import { type SandboxRouteDeps } from "../core/sandbox-routes.js";
|
|
5
|
-
import { type
|
|
6
|
-
type
|
|
2
|
+
import { type TenantContext } from "./context.js";
|
|
3
|
+
import type { DeliveryScope } from "./delivery-token.js";
|
|
7
4
|
/** Session and Action lookups for the sandbox route handlers. */
|
|
8
5
|
export declare function sandboxRouteDeps(ctx: TenantContext): SandboxRouteDeps;
|
|
9
|
-
/** `
|
|
10
|
-
export declare function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
implementationVersion: string;
|
|
18
|
-
input: unknown;
|
|
19
|
-
context: Record<string, unknown>;
|
|
20
|
-
status: "cancelled" | "claimed" | "completed" | "pending" | "uncertain";
|
|
21
|
-
generation: number;
|
|
22
|
-
claimId: string | null;
|
|
23
|
-
leaseExpiresAt: string | null;
|
|
24
|
-
agent?: {
|
|
25
|
-
id: string;
|
|
26
|
-
path: string;
|
|
27
|
-
delegationId?: string | undefined;
|
|
28
|
-
} | undefined;
|
|
29
|
-
kind: "tool";
|
|
30
|
-
capabilityId: string;
|
|
31
|
-
toolName: string;
|
|
32
|
-
inputSchema?: Record<string, unknown> | undefined;
|
|
33
|
-
outputSchema?: Record<string, unknown> | undefined;
|
|
34
|
-
} | {
|
|
35
|
-
actionId: string;
|
|
36
|
-
sessionId: string;
|
|
37
|
-
turnId: string;
|
|
38
|
-
agentId: string;
|
|
39
|
-
manifestHash: string;
|
|
40
|
-
implementationVersion: string;
|
|
41
|
-
input: unknown;
|
|
42
|
-
context: Record<string, unknown>;
|
|
43
|
-
status: "cancelled" | "claimed" | "completed" | "pending" | "uncertain";
|
|
44
|
-
generation: number;
|
|
45
|
-
claimId: string | null;
|
|
46
|
-
leaseExpiresAt: string | null;
|
|
47
|
-
agent?: {
|
|
48
|
-
id: string;
|
|
49
|
-
path: string;
|
|
50
|
-
delegationId?: string | undefined;
|
|
51
|
-
} | undefined;
|
|
52
|
-
kind: "tool";
|
|
53
|
-
path: string;
|
|
54
|
-
key: string;
|
|
55
|
-
inputSchema?: Record<string, unknown> | undefined;
|
|
56
|
-
outputSchema?: Record<string, unknown> | undefined;
|
|
57
|
-
} | {
|
|
58
|
-
actionId: string;
|
|
59
|
-
sessionId: string;
|
|
60
|
-
turnId: string;
|
|
61
|
-
agentId: string;
|
|
62
|
-
manifestHash: string;
|
|
63
|
-
implementationVersion: string;
|
|
64
|
-
input: unknown;
|
|
65
|
-
context: Record<string, unknown>;
|
|
66
|
-
status: "cancelled" | "claimed" | "completed" | "pending" | "uncertain";
|
|
67
|
-
generation: number;
|
|
68
|
-
claimId: string | null;
|
|
69
|
-
leaseExpiresAt: string | null;
|
|
70
|
-
agent?: {
|
|
71
|
-
id: string;
|
|
72
|
-
path: string;
|
|
73
|
-
delegationId?: string | undefined;
|
|
74
|
-
} | undefined;
|
|
75
|
-
kind: "hook";
|
|
76
|
-
hook: {
|
|
77
|
-
at: "after" | "before";
|
|
78
|
-
scope: "step" | "turn";
|
|
79
|
-
capabilityIds: string[];
|
|
80
|
-
};
|
|
81
|
-
} | {
|
|
82
|
-
actionId: string;
|
|
83
|
-
sessionId: string;
|
|
84
|
-
turnId: string;
|
|
85
|
-
agentId: string;
|
|
86
|
-
manifestHash: string;
|
|
87
|
-
implementationVersion: string;
|
|
88
|
-
input: unknown;
|
|
89
|
-
context: Record<string, unknown>;
|
|
90
|
-
status: "cancelled" | "claimed" | "completed" | "pending" | "uncertain";
|
|
91
|
-
generation: number;
|
|
92
|
-
claimId: string | null;
|
|
93
|
-
leaseExpiresAt: string | null;
|
|
94
|
-
agent?: {
|
|
95
|
-
id: string;
|
|
96
|
-
path: string;
|
|
97
|
-
delegationId?: string | undefined;
|
|
98
|
-
} | undefined;
|
|
99
|
-
kind: "fn";
|
|
100
|
-
path: string;
|
|
101
|
-
key: string;
|
|
102
|
-
} | {
|
|
103
|
-
actionId: string;
|
|
104
|
-
sessionId: string;
|
|
105
|
-
turnId: string;
|
|
106
|
-
agentId: string;
|
|
107
|
-
manifestHash: string;
|
|
108
|
-
implementationVersion: string;
|
|
109
|
-
input: unknown;
|
|
110
|
-
context: Record<string, unknown>;
|
|
111
|
-
status: "cancelled" | "claimed" | "completed" | "pending" | "uncertain";
|
|
112
|
-
generation: number;
|
|
113
|
-
claimId: string | null;
|
|
114
|
-
leaseExpiresAt: string | null;
|
|
115
|
-
agent?: {
|
|
116
|
-
id: string;
|
|
117
|
-
path: string;
|
|
118
|
-
delegationId?: string | undefined;
|
|
119
|
-
} | undefined;
|
|
120
|
-
kind: "verify";
|
|
121
|
-
path: string;
|
|
122
|
-
key: string;
|
|
123
|
-
})[];
|
|
6
|
+
/** `POST /v1/actions/:id/sandbox/:tool`: a sandbox tool call for the Action being delivered. */
|
|
7
|
+
export declare function actionSandboxTool(ctx: TenantContext, scope: DeliveryScope, actionId: string, toolName: string, body: () => Promise<unknown>, signal: AbortSignal): Promise<{
|
|
8
|
+
kind: "completed";
|
|
9
|
+
output: unknown;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "failed";
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
124
14
|
}>;
|
|
125
|
-
/** `POST /v1/actions/:id/sandbox/:tool`: a claim-scoped sandbox tool call. */
|
|
126
|
-
export declare function actionSandboxTool(ctx: TenantContext, scope: AuthScope, actionId: string, toolName: string, request: IncomingMessage): Promise<import("../sandbox/tools.js").SandboxToolOutcome>;
|
|
127
|
-
/** `POST /v1/actions/:id/claim` and `/heartbeat`; anything else under the Action is a 404. */
|
|
128
|
-
export declare function updateAction(ctx: TenantContext, scope: AuthScope, actionId: string, method: string | undefined, operation: string | undefined, body: unknown): Promise<unknown>;
|
|
129
|
-
/** `GET /v1/executors`. */
|
|
130
|
-
export declare function listExecutors(ctx: TenantContext): {
|
|
131
|
-
executors: {
|
|
132
|
-
agentId: string;
|
|
133
|
-
implementationVersion: string;
|
|
134
|
-
manifestHash?: string | undefined;
|
|
135
|
-
connected: boolean;
|
|
136
|
-
updatedAt: string;
|
|
137
|
-
}[];
|
|
138
|
-
};
|
|
139
|
-
/** `PUT /v1/executors`: persist the batch, then update the registry and end rotated streams. */
|
|
140
|
-
export declare function registerExecutors(ctx: TenantContext, principalId: string, body: RegisterExecutorsRequest): Promise<{
|
|
141
|
-
executors: {
|
|
142
|
-
agentId: string;
|
|
143
|
-
implementationVersion: string;
|
|
144
|
-
rotated: boolean;
|
|
145
|
-
replacedBy?: "different-credential" | undefined;
|
|
146
|
-
}[];
|
|
147
|
-
}>;
|
|
148
|
-
/** `DELETE /v1/executors/:agentId`: forget the executor and end its streams. */
|
|
149
|
-
export declare function deleteExecutor(ctx: TenantContext, agentId: string): Promise<{
|
|
150
|
-
agentId: string;
|
|
151
|
-
deleted: boolean;
|
|
152
|
-
}>;
|
|
153
|
-
export {};
|