@nylorun/runtime 0.27.0-beta → 0.29.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 +67 -0
- package/README.md +1 -1
- package/dist/api/a2a/card.d.ts +4 -3
- package/dist/api/a2a/card.js +3 -3
- package/dist/api/a2a/routes.js +18 -7
- package/dist/api/ag-ui/routes.js +4 -7
- package/dist/api/components.d.ts +5854 -2718
- package/dist/api/components.js +39 -30
- package/dist/api/http/app.js +9 -4
- package/dist/api/http/body.d.ts +2 -0
- package/dist/api/http/body.js +20 -0
- package/dist/api/http/define.d.ts +4 -0
- package/dist/api/http/define.js +20 -9
- package/dist/api/http/routes/agent-manifests.d.ts +10 -0
- package/dist/api/http/routes/agent-manifests.js +135 -0
- package/dist/api/http/routes/agents.d.ts +11 -0
- package/dist/api/http/routes/agents.js +418 -0
- package/dist/api/http/routes/artifacts.js +2 -2
- package/dist/api/http/routes/coverage.d.ts +4 -4
- package/dist/api/http/routes/coverage.js +12 -6
- package/dist/api/http/routes/files.js +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- package/dist/api/http/routes/me.d.ts +1 -1
- package/dist/api/http/routes/me.js +1 -2
- package/dist/api/http/routes/memories.d.ts +9 -0
- package/dist/api/http/routes/memories.js +152 -0
- package/dist/api/http/routes/reads.d.ts +1 -137
- package/dist/api/http/routes/reads.js +31 -12
- package/dist/api/http/routes/sessions.js +21 -50
- package/dist/api/http/routes/tenant.js +13 -10
- package/dist/api/http/routes/triggers.d.ts +10 -0
- package/dist/api/http/routes/triggers.js +183 -0
- package/dist/api/openapi.js +69 -47
- package/dist/artifacts/disk.d.ts +10 -10
- package/dist/artifacts/disk.js +27 -27
- package/dist/artifacts/quota.d.ts +1 -1
- package/dist/artifacts/quota.js +2 -2
- package/dist/artifacts/service.js +2 -2
- package/dist/core/flow-host.d.ts +0 -1
- package/dist/gates/egress-credentials.js +1 -1
- package/dist/gates/egress.d.ts +5 -5
- package/dist/gates/egress.js +6 -6
- package/dist/gates/http-tool.js +2 -2
- package/dist/gates/meter.js +22 -5
- package/dist/gates/policy.d.ts +8 -3
- package/dist/gates/policy.js +7 -2
- package/dist/gates/tenant-vaults.d.ts +1 -1
- package/dist/harness/pod.d.ts +2 -0
- package/dist/harness/setup.js +17 -6
- package/dist/harness-api/record.js +11 -0
- package/dist/harness-api/server.js +4 -0
- package/dist/harness-api/start.d.ts +11 -7
- package/dist/harness-api/start.js +49 -5
- package/dist/harness-api/workspace.js +2 -2
- package/dist/host/config-for.d.ts +2 -0
- package/dist/host/config-for.js +1 -0
- package/dist/host/http.d.ts +2 -2
- package/dist/host/http.js +5 -2
- package/dist/host/main.js +1 -0
- package/dist/keys/keys.d.ts +15 -4
- package/dist/keys/keys.js +16 -0
- package/dist/keys/webhooks.d.ts +25 -0
- package/dist/keys/webhooks.js +62 -0
- package/dist/management-openapi.json +313 -133
- package/dist/mcp/connect.d.ts +2 -2
- package/dist/mcp/connect.js +3 -3
- package/dist/mcp/preview.js +7 -7
- package/dist/memory/service.d.ts +97 -0
- package/dist/memory/service.js +335 -0
- package/dist/memory/tool.d.ts +36 -0
- package/dist/memory/tool.js +84 -0
- package/dist/model/pi-model.js +7 -0
- package/dist/openapi.json +13120 -9034
- package/dist/reads/types.d.ts +3 -3
- package/dist/record/agent.d.ts +27 -0
- package/dist/record/agent.js +46 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/sandbox/join.js +5 -5
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +3 -3
- package/dist/sandbox/pods/lifecycle.d.ts +6 -6
- package/dist/sandbox/pods/lifecycle.js +6 -6
- package/dist/sandbox/pods/reconcile.js +10 -2
- package/dist/sandbox/resolve.d.ts +3 -3
- package/dist/sandbox/resolve.js +7 -7
- package/dist/sandbox/setup.d.ts +3 -1
- package/dist/sandbox/setup.js +14 -4
- package/dist/store/postgres/drizzle/0032_agents.sql +54 -0
- package/dist/store/postgres/drizzle/0033_agent_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0034_protocol_17_session_queue.sql +13 -0
- package/dist/store/postgres/drizzle/0035_t4_triggers.sql +41 -0
- package/dist/store/postgres/drizzle/0036_t5_memories.sql +30 -0
- package/dist/store/postgres/drizzle/0037_model_usage_cost_split.sql +4 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +42 -0
- package/dist/store/postgres/reads.js +44 -87
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/schema.d.ts +1408 -123
- package/dist/store/postgres/schema.js +194 -38
- package/dist/store/postgres/store.js +329 -79
- package/dist/store/postgres/tenant.js +1 -2
- package/dist/store/types.d.ts +155 -50
- package/dist/store/types.js +0 -1
- package/dist/tenant/advance.js +20 -8
- package/dist/tenant/agent-manifests.d.ts +72 -0
- package/dist/tenant/agent-manifests.js +359 -0
- package/dist/tenant/agent-versions.d.ts +126 -0
- package/dist/tenant/agent-versions.js +389 -0
- package/dist/tenant/agents.d.ts +230 -0
- package/dist/tenant/{environments.js → agents.js} +464 -320
- package/dist/tenant/auth.d.ts +1 -1
- package/dist/tenant/auth.js +3 -3
- package/dist/tenant/commands.d.ts +63 -2
- package/dist/tenant/commands.js +240 -83
- package/dist/tenant/context.d.ts +46 -19
- package/dist/tenant/context.js +6 -2
- package/dist/tenant/effects.js +7 -16
- package/dist/tenant/identity-file.d.ts +6 -6
- package/dist/tenant/identity-file.js +12 -10
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/limits.d.ts +0 -3
- package/dist/tenant/limits.js +0 -3
- package/dist/tenant/memories.d.ts +38 -0
- package/dist/tenant/memories.js +119 -0
- package/dist/tenant/reset.js +2 -2
- package/dist/tenant/run-grants.d.ts +6 -0
- package/dist/tenant/run-grants.js +4 -0
- package/dist/tenant/runtime.d.ts +1 -1
- package/dist/tenant/runtime.js +8 -0
- package/dist/tenant/sessions.d.ts +28 -45
- package/dist/tenant/sessions.js +85 -208
- package/dist/tenant/status.js +6 -7
- package/dist/tenant/sweep.js +12 -3
- package/dist/tenant/transcript.d.ts +16 -16
- package/dist/tenant/triggers.d.ts +143 -0
- package/dist/tenant/triggers.js +715 -0
- package/dist/tenant/turn-timing.d.ts +11 -1
- package/dist/tenant/turn-timing.js +3 -1
- package/dist/tenant/types.d.ts +5 -0
- package/dist/tenant/worker.d.ts +2 -0
- package/dist/tenant/worker.js +5 -0
- package/dist/traces/map.d.ts +1 -1
- package/dist/traces/map.js +7 -1
- package/dist/tuning.d.ts +7 -0
- package/dist/tuning.js +19 -0
- package/dist/vault/service.d.ts +13 -8
- package/dist/vault/service.js +61 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +13 -12
- package/dist/api/http/routes/environment-manifests.d.ts +0 -9
- package/dist/api/http/routes/environment-manifests.js +0 -118
- package/dist/api/http/routes/environments.d.ts +0 -11
- package/dist/api/http/routes/environments.js +0 -332
- package/dist/record/environment.d.ts +0 -27
- package/dist/record/environment.js +0 -46
- package/dist/tenant/environment-manifests.d.ts +0 -57
- package/dist/tenant/environment-manifests.js +0 -208
- package/dist/tenant/environments.d.ts +0 -172
|
@@ -13,6 +13,8 @@ export interface TurnTiming {
|
|
|
13
13
|
turnStartedAt?: string;
|
|
14
14
|
/** The trace context the turn's message arrived with (R7.4); it ends with the turn. */
|
|
15
15
|
turnTrace?: unknown;
|
|
16
|
+
/** What started the turn when not a client (track T4); it ends with the turn. */
|
|
17
|
+
turnCause?: unknown;
|
|
16
18
|
pausedMs?: number;
|
|
17
19
|
pausedAt?: string;
|
|
18
20
|
}
|
|
@@ -25,16 +27,24 @@ export declare function resumeTurn(s: TurnTiming, now?: Date): void;
|
|
|
25
27
|
/**
|
|
26
28
|
* The facts the event that ends turn `turnId` carries: `durationMs` from its start to now, waits
|
|
27
29
|
* included, so the turn's span holds every crossing in it; `pausedMs`, how long it waited paused
|
|
28
|
-
* (a wait still open ends now, as for a cancel); the session's
|
|
30
|
+
* (a wait still open ends now, as for a cancel); the session's Agent and the manifest version it runs;
|
|
29
31
|
* and the turn's totals from the usage ledger (one read, as `/v1/tenant/usage` totals a turn;
|
|
30
32
|
* `steps` are the model calls the gate metered). Clears the turn's timing from `s`.
|
|
31
33
|
*/
|
|
32
34
|
export declare function endTurn(t: Tx, s: TurnTiming & {
|
|
33
35
|
agentId: string;
|
|
36
|
+
definition?: {
|
|
37
|
+
name: string;
|
|
38
|
+
version: number;
|
|
39
|
+
};
|
|
34
40
|
}, turnId: string | null, now?: Date): Promise<{
|
|
35
41
|
durationMs?: number;
|
|
36
42
|
pausedMs?: number;
|
|
37
43
|
agentId: string;
|
|
44
|
+
manifest?: {
|
|
45
|
+
name: string;
|
|
46
|
+
version: number;
|
|
47
|
+
};
|
|
38
48
|
totals?: {
|
|
39
49
|
steps: number;
|
|
40
50
|
tokens: number;
|
|
@@ -19,7 +19,7 @@ export function resumeTurn(s, now = new Date()) {
|
|
|
19
19
|
/**
|
|
20
20
|
* The facts the event that ends turn `turnId` carries: `durationMs` from its start to now, waits
|
|
21
21
|
* included, so the turn's span holds every crossing in it; `pausedMs`, how long it waited paused
|
|
22
|
-
* (a wait still open ends now, as for a cancel); the session's
|
|
22
|
+
* (a wait still open ends now, as for a cancel); the session's Agent and the manifest version it runs;
|
|
23
23
|
* and the turn's totals from the usage ledger (one read, as `/v1/tenant/usage` totals a turn;
|
|
24
24
|
* `steps` are the model calls the gate metered). Clears the turn's timing from `s`.
|
|
25
25
|
*/
|
|
@@ -30,10 +30,12 @@ export async function endTurn(t, s, turnId, now = new Date()) {
|
|
|
30
30
|
const facts = {
|
|
31
31
|
...(elapsed === undefined ? {} : { durationMs: Math.max(0, elapsed), pausedMs: s.pausedMs ?? 0 }),
|
|
32
32
|
agentId: s.agentId,
|
|
33
|
+
...(s.definition ? { manifest: { name: s.definition.name, version: s.definition.version } } : {}),
|
|
33
34
|
...(totals ? { totals: { steps: totals.calls, tokens: totals.tokens, costUsd: totals.costUsd } } : {}),
|
|
34
35
|
};
|
|
35
36
|
delete s.turnStartedAt;
|
|
36
37
|
delete s.pausedMs;
|
|
37
38
|
delete s.turnTrace;
|
|
39
|
+
delete s.turnCause;
|
|
38
40
|
return facts;
|
|
39
41
|
}
|
package/dist/tenant/types.d.ts
CHANGED
|
@@ -74,6 +74,11 @@ export interface TenantConfig {
|
|
|
74
74
|
* the identity file (`NYLORUN_IDENTITY_FILE`). Absent: none.
|
|
75
75
|
*/
|
|
76
76
|
issuers?: import("./issuers.js").TrustedIssuers;
|
|
77
|
+
/**
|
|
78
|
+
* The URL clients reach the Runtime API at (`NYLORUN_PUBLIC_URL`, no trailing slash): the base
|
|
79
|
+
* of webhook URLs and the OAuth resource. Absent: the origin each request reached.
|
|
80
|
+
*/
|
|
81
|
+
publicUrl?: string;
|
|
77
82
|
logger: Logger;
|
|
78
83
|
}
|
|
79
84
|
export interface Logger {
|
package/dist/tenant/worker.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface TenantWorker {
|
|
|
36
36
|
sweep(): Promise<void>;
|
|
37
37
|
/** Reconciles one pod sandbox (F7.2). Only infrastructure errors throw. */
|
|
38
38
|
sandbox?(sandboxId: string, trigger: SandboxTrigger, signal: AbortSignal): Promise<SandboxResult>;
|
|
39
|
+
/** A durable timer it armed fired (track T4's triggers). Only infrastructure errors throw. */
|
|
40
|
+
fire?(key: string): Promise<void>;
|
|
39
41
|
}
|
|
40
42
|
export interface TenantWorkersOptions {
|
|
41
43
|
/** Finds or opens a Tenant that is not registered on this process. */
|
package/dist/tenant/worker.js
CHANGED
|
@@ -132,6 +132,11 @@ export class TenantWorkers {
|
|
|
132
132
|
const worker = await this.find(tenantId);
|
|
133
133
|
return worker?.sandbox ? worker.sandbox(sandboxId, trigger, signal) : {};
|
|
134
134
|
},
|
|
135
|
+
// A timer of a Tenant that is not open here does nothing: the Tenant's sweep arms what is due
|
|
136
|
+
// once it opens.
|
|
137
|
+
fire: async (tenantId, key) => {
|
|
138
|
+
await (await this.find(tenantId))?.fire?.(key);
|
|
139
|
+
},
|
|
135
140
|
};
|
|
136
141
|
/** Runs one advance under the deadline and the grace period (see the module comment). */
|
|
137
142
|
async bounded(tenantId, sessionId, worker, signal) {
|
package/dist/traces/map.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* | Row | Span |
|
|
7
7
|
* | --- | --- |
|
|
8
|
-
* | `turn.completed`, `turn.failed`, `turn.cancelled` | `invoke_agent {
|
|
8
|
+
* | `turn.completed`, `turn.failed`, `turn.cancelled` | `invoke_agent {manifest name}`, the turn's root (INTERNAL) |
|
|
9
9
|
* | `message.assistant`, `model.failed`, `context.compacted` | `chat {model}` (CLIENT) |
|
|
10
10
|
* | `tool.completed` | `execute_tool {toolName}` (INTERNAL) |
|
|
11
11
|
* | `node.completed` | `execute_tool {key}`, a flow's HTTP stage (INTERNAL) |
|
package/dist/traces/map.js
CHANGED
|
@@ -56,11 +56,17 @@ export function spanOf(row, turn, settings) {
|
|
|
56
56
|
case "turn.failed":
|
|
57
57
|
case "turn.cancelled": {
|
|
58
58
|
const status = row.type.slice("turn.".length);
|
|
59
|
+
// The agent the turn ran: its manifest's name (protocol 16), else the Agent's id.
|
|
60
|
+
const manifest = p.manifest;
|
|
61
|
+
const agentName = typeof manifest?.name === "string" ? manifest.name : typeof p.agentId === "string" ? p.agentId : undefined;
|
|
59
62
|
const totals = p.totals;
|
|
60
63
|
const error = row.type === "turn.failed" ? (p.error ?? {}) : undefined;
|
|
61
64
|
const attributes = base
|
|
62
65
|
.str("gen_ai.operation.name", "invoke_agent")
|
|
63
66
|
.str("gen_ai.agent.id", p.agentId)
|
|
67
|
+
.str("gen_ai.agent.name", agentName)
|
|
68
|
+
// The agent manifest version the turn ran (T3): an Agent moves between versions.
|
|
69
|
+
.int("nylorun.manifest.version", typeof manifest?.version === "number" ? manifest.version : undefined)
|
|
64
70
|
.str("nylorun.turn.status", status)
|
|
65
71
|
.int("nylorun.turn.paused_ms", p.pausedMs)
|
|
66
72
|
.int("nylorun.turn.steps", totals?.steps)
|
|
@@ -76,7 +82,7 @@ export function spanOf(row, turn, settings) {
|
|
|
76
82
|
traceId: turn.traceId,
|
|
77
83
|
spanId: turn.spanId,
|
|
78
84
|
...(turn.parentSpanId ? { parentSpanId: turn.parentSpanId } : {}),
|
|
79
|
-
name:
|
|
85
|
+
name: agentName === undefined ? "invoke_agent" : `invoke_agent ${agentName}`,
|
|
80
86
|
kind: SPAN_KIND.internal,
|
|
81
87
|
...window(row.time, p.durationMs),
|
|
82
88
|
attributes: attributes.list,
|
package/dist/tuning.d.ts
CHANGED
|
@@ -104,6 +104,8 @@ export declare const HostTuningSchema: z.ZodObject<{
|
|
|
104
104
|
signingKeyRotationGraceMs: z.ZodDefault<z.ZodNumber>;
|
|
105
105
|
retryAfterSeconds: z.ZodDefault<z.ZodNumber>;
|
|
106
106
|
seedLeaseMs: z.ZodDefault<z.ZodNumber>;
|
|
107
|
+
upgradeIdleMs: z.ZodDefault<z.ZodNumber>;
|
|
108
|
+
upgradeStartMs: z.ZodDefault<z.ZodNumber>;
|
|
107
109
|
}, z.core.$strict>>;
|
|
108
110
|
sweep: z.ZodPrefault<z.ZodObject<{
|
|
109
111
|
intervalMs: z.ZodDefault<z.ZodNumber>;
|
|
@@ -120,6 +122,11 @@ export declare const HostTuningSchema: z.ZodObject<{
|
|
|
120
122
|
}, z.core.$strict>>;
|
|
121
123
|
stalePodMs: z.ZodDefault<z.ZodNumber>;
|
|
122
124
|
}, z.core.$strict>>;
|
|
125
|
+
triggers: z.ZodPrefault<z.ZodObject<{
|
|
126
|
+
lateGraceMs: z.ZodDefault<z.ZodNumber>;
|
|
127
|
+
intervalCheckFires: z.ZodDefault<z.ZodNumber>;
|
|
128
|
+
webhookToleranceMs: z.ZodDefault<z.ZodNumber>;
|
|
129
|
+
}, z.core.$strict>>;
|
|
123
130
|
execution: z.ZodPrefault<z.ZodObject<{
|
|
124
131
|
advanceDeadlineMs: z.ZodDefault<z.ZodNumber>;
|
|
125
132
|
advanceGraceMs: z.ZodDefault<z.ZodNumber>;
|
package/dist/tuning.js
CHANGED
|
@@ -177,6 +177,13 @@ export const HostTuningSchema = z
|
|
|
177
177
|
retryAfterSeconds: count(5),
|
|
178
178
|
/** How long a pending Environment seed holds the disk before another process may take it over. */
|
|
179
179
|
seedLeaseMs: ms(10 * MINUTE),
|
|
180
|
+
/**
|
|
181
|
+
* The longest a pod Agent waiting to start on a new version (track T3) stays idle before it
|
|
182
|
+
* stops, so its next start applies the version: its own `lifecycle.idle` when shorter.
|
|
183
|
+
*/
|
|
184
|
+
upgradeIdleMs: ms(MINUTE),
|
|
185
|
+
/** How long a pod may take to start on a new version before it goes back to the one it ran (T3). */
|
|
186
|
+
upgradeStartMs: ms(10 * MINUTE),
|
|
180
187
|
}),
|
|
181
188
|
/** The Tenant's sweep (`tenant/sweep.ts`): outbox, orphaned sessions, stale pods. */
|
|
182
189
|
sweep: group({
|
|
@@ -201,6 +208,18 @@ export const HostTuningSchema = z
|
|
|
201
208
|
/** How long a pod row may go unchanged before the sweep checks it. */
|
|
202
209
|
stalePodMs: ms(MINUTE),
|
|
203
210
|
}),
|
|
211
|
+
/** Triggers (track T4, D74): server timing; the Tenant's own bounds are its Runtime limits. */
|
|
212
|
+
triggers: group({
|
|
213
|
+
/**
|
|
214
|
+
* How long after it was due a fire counts as late (the server was down or asleep), and how
|
|
215
|
+
* overdue an active trigger is before the sweep arms it again.
|
|
216
|
+
*/
|
|
217
|
+
lateGraceMs: ms(2 * MINUTE),
|
|
218
|
+
/** How many upcoming fires the save check reads to find a cron's smallest gap. */
|
|
219
|
+
intervalCheckFires: count(100, 2, 10_000),
|
|
220
|
+
/** The clock skew a webhook delivery's `webhook-timestamp` may have, either way (D75). */
|
|
221
|
+
webhookToleranceMs: ms(5 * MINUTE),
|
|
222
|
+
}),
|
|
204
223
|
/** Durable Session Execution: Restate, or the in-process execution. */
|
|
205
224
|
execution: group({
|
|
206
225
|
/**
|
package/dist/vault/service.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CredentialCoverage, CredentialCoverageRequest, CredentialIdentity,
|
|
1
|
+
import type { CredentialCoverage, CredentialCoverageRequest, CredentialIdentity, EnvironmentSecretSlot, AgentSecretView, HostModelProviderInfo, HostModelView, PutAgentSecretRequest, PutHostModelRequest, CustomModelSettings, ModelInput, SelectHostModelRequest } from "@nylorun/core/contracts";
|
|
2
2
|
import type { AgentManifest, WorkflowManifest } from "@nylorun/core/define";
|
|
3
3
|
import type { SessionStore, Tx, VaultCredentialRow } from "../store/types.js";
|
|
4
4
|
export declare const HOST_VAULT_ID = "host";
|
|
@@ -101,16 +101,16 @@ export declare class VaultService {
|
|
|
101
101
|
dropped: string[];
|
|
102
102
|
}>;
|
|
103
103
|
/**
|
|
104
|
-
* `PUT /v1/
|
|
104
|
+
* `PUT /v1/agents/{id}/secrets/{name}`: creates or replaces one credential. The same
|
|
105
105
|
* name and type keeps the credential's id and re-seals its value and binding; another type
|
|
106
106
|
* replaces it. Refused (`409 credential_conflict`) when another credential of the vault is
|
|
107
107
|
* bound to one of its hosts or to its URL. Runs under the Environment row's lock, which also
|
|
108
108
|
* orders it with session opens and deletes, and counts as the Environment's use.
|
|
109
109
|
*/
|
|
110
|
-
putEnvironmentSecret(environmentId: string, name: string, body:
|
|
110
|
+
putEnvironmentSecret(environmentId: string, name: string, body: PutAgentSecretRequest, actor: string): Promise<AgentSecretView>;
|
|
111
111
|
/** The Environment's secrets: names, types and bindings, never values. */
|
|
112
|
-
listEnvironmentSecrets(environmentId: string): Promise<
|
|
113
|
-
getEnvironmentSecret(environmentId: string, name: string): Promise<
|
|
112
|
+
listEnvironmentSecrets(environmentId: string): Promise<AgentSecretView[]>;
|
|
113
|
+
getEnvironmentSecret(environmentId: string, name: string): Promise<AgentSecretView>;
|
|
114
114
|
deleteEnvironmentSecret(environmentId: string, name: string, actor: string): Promise<{
|
|
115
115
|
id: string;
|
|
116
116
|
}>;
|
|
@@ -154,9 +154,9 @@ export declare class VaultService {
|
|
|
154
154
|
url: string;
|
|
155
155
|
}): Promise<AuthorizeResult>;
|
|
156
156
|
/**
|
|
157
|
-
* What a session
|
|
158
|
-
* (`credentialNeeds`), decided as `authorize` decides a call:
|
|
159
|
-
*
|
|
157
|
+
* What a session on Agent `request.agentId` would send for each URL `manifest` (its manifest
|
|
158
|
+
* version's loop manifest) names (`credentialNeeds`), decided as `authorize` decides a call:
|
|
159
|
+
* the credential of the Agent's vault bound to the URL. Reads no secret, writes no audit row.
|
|
160
160
|
*/
|
|
161
161
|
coverage(manifest: AgentManifest | WorkflowManifest, request: CredentialCoverageRequest): Promise<CredentialCoverage>;
|
|
162
162
|
getHostModel(): Promise<HostModelView>;
|
|
@@ -204,4 +204,9 @@ type HostSecretPayload = {
|
|
|
204
204
|
};
|
|
205
205
|
export declare function modelBinding(row: VaultCredentialRow): ModelBinding;
|
|
206
206
|
export declare function hostModelAad(provider: string, model: string): Buffer;
|
|
207
|
+
/**
|
|
208
|
+
* Whether the credential in `row` fills secret slot `slot` (D64): of the slot's type, with its
|
|
209
|
+
* binding (the hosts and header of an `environment_secret`, the URL of a `bearer` or `headers`).
|
|
210
|
+
*/
|
|
211
|
+
export declare function slotHolds(slot: EnvironmentSecretSlot, row: Pick<VaultCredentialRow, "type" | "bindingJson">): boolean;
|
|
207
212
|
export {};
|
package/dist/vault/service.js
CHANGED
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
* sealEnvironmentSecretCopies(from, vaultId, slots | null): Promise<SealedSecretCopies>
|
|
19
19
|
* insertEnvironmentSecretCopies(t: Tx, vaultId, from, actor, sealed): Promise<{ copied; dropped }>
|
|
20
20
|
*
|
|
21
|
-
* // Its secrets (`/v1/
|
|
21
|
+
* // Its secrets (`/v1/agents/{id}/secrets`): each opens its own transaction and writes its
|
|
22
22
|
* // audit rows in it. A put needs the vault key, so callers reach it through `Keys`.
|
|
23
|
-
* putEnvironmentSecret(environmentId, name, body:
|
|
24
|
-
* listEnvironmentSecrets(environmentId): Promise<
|
|
25
|
-
* getEnvironmentSecret(environmentId, name): Promise<
|
|
23
|
+
* putEnvironmentSecret(environmentId, name, body: PutAgentSecretRequest, actor): Promise<AgentSecretView>
|
|
24
|
+
* listEnvironmentSecrets(environmentId): Promise<AgentSecretView[]>
|
|
25
|
+
* getEnvironmentSecret(environmentId, name): Promise<AgentSecretView>
|
|
26
26
|
* deleteEnvironmentSecret(environmentId, name, actor): Promise<{ id: string }>
|
|
27
27
|
*
|
|
28
28
|
* // The shell's variables of a session's sandbox, in the caller's transaction (R2c).
|
|
@@ -231,7 +231,7 @@ export class VaultService {
|
|
|
231
231
|
}
|
|
232
232
|
// --- an Environment's secrets ----------------------------------------------------
|
|
233
233
|
/**
|
|
234
|
-
* `PUT /v1/
|
|
234
|
+
* `PUT /v1/agents/{id}/secrets/{name}`: creates or replaces one credential. The same
|
|
235
235
|
* name and type keeps the credential's id and re-seals its value and binding; another type
|
|
236
236
|
* replaces it. Refused (`409 credential_conflict`) when another credential of the vault is
|
|
237
237
|
* bound to one of its hosts or to its URL. Runs under the Environment row's lock, which also
|
|
@@ -333,9 +333,12 @@ export class VaultService {
|
|
|
333
333
|
if (!vault)
|
|
334
334
|
return {};
|
|
335
335
|
const environment = {};
|
|
336
|
+
const live = await liveFilter(t, environmentId);
|
|
336
337
|
for (const row of await t.credentialsForVault(vault.id)) {
|
|
337
338
|
if (row.type !== "environment_secret" && row.type !== "environment_variable")
|
|
338
339
|
continue;
|
|
340
|
+
if (!live(row))
|
|
341
|
+
continue;
|
|
339
342
|
const binding = JSON.parse(row.bindingJson);
|
|
340
343
|
if (row.type === "environment_secret")
|
|
341
344
|
environment[binding.secretName] = ENVIRONMENT_SECRET_SENTINEL;
|
|
@@ -398,8 +401,10 @@ export class VaultService {
|
|
|
398
401
|
});
|
|
399
402
|
return { result: { status: "refused", url, credentialIds: [], reason: "vault_missing" } };
|
|
400
403
|
}
|
|
404
|
+
const live = await liveFilter(t, environmentId);
|
|
401
405
|
const matches = (await t.credentialsForVault(vault.id))
|
|
402
406
|
.filter(isUserCredential)
|
|
407
|
+
.filter(live)
|
|
403
408
|
.filter((row) => bindingUrl(row) === url)
|
|
404
409
|
.sort((a, b) => a.id.localeCompare(b.id));
|
|
405
410
|
if (matches.length === 0)
|
|
@@ -466,18 +471,19 @@ export class VaultService {
|
|
|
466
471
|
}
|
|
467
472
|
// --- coverage --------------------------------------------------------------------
|
|
468
473
|
/**
|
|
469
|
-
* What a session
|
|
470
|
-
* (`credentialNeeds`), decided as `authorize` decides a call:
|
|
471
|
-
*
|
|
474
|
+
* What a session on Agent `request.agentId` would send for each URL `manifest` (its manifest
|
|
475
|
+
* version's loop manifest) names (`credentialNeeds`), decided as `authorize` decides a call:
|
|
476
|
+
* the credential of the Agent's vault bound to the URL. Reads no secret, writes no audit row.
|
|
472
477
|
*/
|
|
473
478
|
async coverage(manifest, request) {
|
|
474
|
-
const environmentId = request.
|
|
479
|
+
const environmentId = request.agentId;
|
|
475
480
|
return this.store.tx(async (t) => {
|
|
476
481
|
const credentials = [];
|
|
477
|
-
|
|
482
|
+
{
|
|
478
483
|
const vault = await this.environmentVault(t, environmentId);
|
|
484
|
+
const live = await liveFilter(t, environmentId);
|
|
479
485
|
for (const row of await t.credentialsForVault(vault.id))
|
|
480
|
-
if (isUserCredential(row))
|
|
486
|
+
if (isUserCredential(row) && live(row))
|
|
481
487
|
credentials.push({ row, url: bindingUrl(row) });
|
|
482
488
|
}
|
|
483
489
|
const entries = credentialNeeds(manifest).map((need) => {
|
|
@@ -495,7 +501,6 @@ export class VaultService {
|
|
|
495
501
|
});
|
|
496
502
|
return {
|
|
497
503
|
agentId: request.agentId,
|
|
498
|
-
environmentId: environmentId ?? null,
|
|
499
504
|
complete: entries.every((entry) => entry.status === "covered"),
|
|
500
505
|
entries,
|
|
501
506
|
};
|
|
@@ -634,7 +639,7 @@ export class VaultService {
|
|
|
634
639
|
? await t.vaultOfEnvironment(environmentId)
|
|
635
640
|
: undefined;
|
|
636
641
|
if (!vault)
|
|
637
|
-
throw new VaultError(404, "
|
|
642
|
+
throw new VaultError(404, "Agent not found");
|
|
638
643
|
return vault;
|
|
639
644
|
}
|
|
640
645
|
async ensureHostVault(t) {
|
|
@@ -749,18 +754,18 @@ function bindingUrl(row) {
|
|
|
749
754
|
/** Where a credential is, for coverage: never its value. */
|
|
750
755
|
function coverageCredential(environmentId, row) {
|
|
751
756
|
const via = JSON.parse(row.bindingJson).via;
|
|
752
|
-
return { environmentId, name: row.name, ...(via === undefined ? {} : { via }) };
|
|
757
|
+
return { agentId: environmentId, name: row.name, ...(via === undefined ? {} : { via }) };
|
|
753
758
|
}
|
|
754
759
|
/** One coverage entry, with the sentence that says what the session would do. */
|
|
755
760
|
function coverageEntry(need, url, credential, environmentId, invalid) {
|
|
756
761
|
const required = need.kind === "http";
|
|
757
762
|
const where = environmentId === undefined
|
|
758
|
-
? "Without an
|
|
759
|
-
: `
|
|
763
|
+
? "Without an Agent, no credential is sent"
|
|
764
|
+
: `Agent ${environmentId} holds no credential for this URL`;
|
|
760
765
|
const message = invalid !== undefined
|
|
761
766
|
? `No credential can be bound to this URL (${invalid}).`
|
|
762
767
|
: credential !== undefined
|
|
763
|
-
? `Sends '${credential.name}' from
|
|
768
|
+
? `Sends '${credential.name}' from Agent ${credential.agentId}${credential.via ? ` through ${credential.via}` : ""}.`
|
|
764
769
|
: required
|
|
765
770
|
? `${where}: each call fails with http.credential.`
|
|
766
771
|
: `${where}: the server is called without one, which only a public server accepts.`;
|
|
@@ -1027,6 +1032,45 @@ async function environmentSecretsFor(t, environmentId, host) {
|
|
|
1027
1032
|
const vault = await t.vaultOfEnvironment(environmentId);
|
|
1028
1033
|
if (!vault)
|
|
1029
1034
|
return [];
|
|
1035
|
+
const live = await liveFilter(t, environmentId);
|
|
1030
1036
|
return (await t.credentialsForVault(vault.id)).filter((row) => row.type === "environment_secret" &&
|
|
1037
|
+
live(row) &&
|
|
1031
1038
|
(credentialBinding(row).allowedHosts ?? []).includes(lower));
|
|
1032
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Whether the credential in `row` fills secret slot `slot` (D64): of the slot's type, with its
|
|
1042
|
+
* binding (the hosts and header of an `environment_secret`, the URL of a `bearer` or `headers`).
|
|
1043
|
+
*/
|
|
1044
|
+
export function slotHolds(slot, row) {
|
|
1045
|
+
if (row.type !== slot.type)
|
|
1046
|
+
return false;
|
|
1047
|
+
const binding = JSON.parse(row.bindingJson);
|
|
1048
|
+
if (slot.type === "environment_variable")
|
|
1049
|
+
return true;
|
|
1050
|
+
if (slot.type === "environment_secret") {
|
|
1051
|
+
const hosts = (list) => canonical([...(list ?? [])].map((host) => host.toLowerCase()).sort());
|
|
1052
|
+
const inject = slot.inject ? { header: slot.inject.header, format: slot.inject.format } : null;
|
|
1053
|
+
return hosts(slot.allowedHosts) === hosts(binding.allowedHosts) && canonical(inject) === canonical(binding.inject ?? null);
|
|
1054
|
+
}
|
|
1055
|
+
try {
|
|
1056
|
+
return normalizeVaultUrl(slot.url) === binding.url;
|
|
1057
|
+
}
|
|
1058
|
+
catch {
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Which of Agent `environmentId`'s credentials are live (track T3, D73): with secret slots in the
|
|
1064
|
+
* runtime it applies, only those that fill a slot of the name (`slotHolds`). Another stays in the
|
|
1065
|
+
* vault, dormant: a slot the version dropped, or one whose binding changed until it gets a value
|
|
1066
|
+
* again. Without slots, every one.
|
|
1067
|
+
*/
|
|
1068
|
+
async function liveFilter(t, environmentId) {
|
|
1069
|
+
const slots = (await t.environment(environmentId))?.applied.secrets;
|
|
1070
|
+
if (slots === undefined)
|
|
1071
|
+
return () => true;
|
|
1072
|
+
return (row) => {
|
|
1073
|
+
const slot = slots[row.name];
|
|
1074
|
+
return slot !== undefined && slotHolds(slot, row);
|
|
1075
|
+
};
|
|
1076
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const RUNTIME_VERSION = "0.
|
|
1
|
+
export declare const RUNTIME_VERSION = "0.29.0-beta";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
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.29.0-beta";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.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",
|
|
@@ -61,17 +61,18 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@ag-ui/core": "~1.0.2",
|
|
63
63
|
"@asteasolutions/zod-to-openapi": "^9.1.0",
|
|
64
|
-
"@earendil-works/pi-ai": "
|
|
65
|
-
"@hono/node-server": "^2.1.
|
|
64
|
+
"@earendil-works/pi-ai": "1.2.0",
|
|
65
|
+
"@hono/node-server": "^2.1.5",
|
|
66
66
|
"@hono/zod-openapi": "^1.6.3",
|
|
67
67
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
68
|
-
"@nylorun/core": "0.
|
|
69
|
-
"@nylorun/harness": "0.
|
|
70
|
-
"@restatedev/restate-sdk": "1.17.
|
|
71
|
-
"@restatedev/restate-sdk-clients": "1.17.
|
|
68
|
+
"@nylorun/core": "0.25.0-beta",
|
|
69
|
+
"@nylorun/harness": "0.29.1-beta",
|
|
70
|
+
"@restatedev/restate-sdk": "1.17.3",
|
|
71
|
+
"@restatedev/restate-sdk-clients": "1.17.3",
|
|
72
72
|
"@s2-dev/streamstore": "0.28.0",
|
|
73
73
|
"aws4fetch": "1.0.20",
|
|
74
|
-
"
|
|
74
|
+
"croner": "^9.1.0",
|
|
75
|
+
"drizzle-orm": "^0.45.4",
|
|
75
76
|
"hono": "^4.13.13",
|
|
76
77
|
"jose": "^6.2.12",
|
|
77
78
|
"just-bash": "3.6.0",
|
|
@@ -80,18 +81,18 @@
|
|
|
80
81
|
"postgres": "^3.4.9",
|
|
81
82
|
"ws": "^8.22.0",
|
|
82
83
|
"yaml": "^2.9.1",
|
|
83
|
-
"zod": "^4.6.
|
|
84
|
+
"zod": "^4.6.7"
|
|
84
85
|
},
|
|
85
86
|
"devDependencies": {
|
|
86
87
|
"@a2a-js/sdk": "~1.3.0",
|
|
87
88
|
"@ag-ui/client": "1.0.2",
|
|
88
|
-
"@scalar/openapi-parser": "^0.29.
|
|
89
|
-
"@types/node": "^26.6.
|
|
89
|
+
"@scalar/openapi-parser": "^0.29.13",
|
|
90
|
+
"@types/node": "^26.6.5",
|
|
90
91
|
"@types/pg": "^8.23.1",
|
|
91
92
|
"@types/ws": "^8.18.2",
|
|
92
93
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
93
94
|
"drizzle-kit": "^0.31.11",
|
|
94
95
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
95
|
-
"vitest": "^5.0.
|
|
96
|
+
"vitest": "^5.0.4"
|
|
96
97
|
}
|
|
97
98
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment manifests (`/v1/environment-manifests/**`, protocol 14, D63): save, read, list and
|
|
3
|
-
* delete the named, versioned definitions Environments are made from. A save never changes an
|
|
4
|
-
* Environment. Reading needs what reading an Environment needs; saving and deleting need
|
|
5
|
-
* `environments:write`, from any client (Q12).
|
|
6
|
-
*/
|
|
7
|
-
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
8
|
-
import type { TenantEnv } from "../app.js";
|
|
9
|
-
export declare function environmentManifestRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { isEnvironmentManifestName, PutEnvironmentManifestRequestSchema } from "@nylorun/core/contracts";
|
|
3
|
-
import { DeleteEnvironmentManifestResponse, EnvironmentManifestPlan, EnvironmentManifestVersions, EnvironmentManifestView, ListEnvironmentManifestsResponse, PutEnvironmentManifestRequest, SaveEnvironmentManifestResponse, } from "../../components.js";
|
|
4
|
-
import { fail } from "../../../tenant/http.js";
|
|
5
|
-
import { deleteEnvironmentManifest, environmentManifestVersions, getEnvironmentManifest, listEnvironmentManifests, saveEnvironmentManifest, } from "../../../tenant/environment-manifests.js";
|
|
6
|
-
import { readJson } from "../body.js";
|
|
7
|
-
import { tenantRoute } from "../define.js";
|
|
8
|
-
import { jsonResponse } from "../respond.js";
|
|
9
|
-
const READ = {
|
|
10
|
-
credentials: ["application", "subject", "token"],
|
|
11
|
-
scopes: ["sessions:own", "environments:write"],
|
|
12
|
-
};
|
|
13
|
-
const WRITE = {
|
|
14
|
-
credentials: ["application", "subject", "token"],
|
|
15
|
-
scopes: ["environments:write"],
|
|
16
|
-
};
|
|
17
|
-
const json = (schema, description) => ({
|
|
18
|
-
description,
|
|
19
|
-
content: { "application/json": { schema } },
|
|
20
|
-
});
|
|
21
|
-
const namePath = z.object({
|
|
22
|
-
name: z.string().meta({ description: "The environment manifest's name, such as `analyst-box`" }),
|
|
23
|
-
});
|
|
24
|
-
function nameOf(value) {
|
|
25
|
-
if (!isEnvironmentManifestName(value))
|
|
26
|
-
return fail(400, "An environment manifest's name is 1-64 letters, digits, '.', '_' and '-', starting with a letter or digit");
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
function versionOf(value) {
|
|
30
|
-
const version = Number(value);
|
|
31
|
-
if (!Number.isInteger(version) || version < 1)
|
|
32
|
-
return fail(400, "version is a positive integer");
|
|
33
|
-
return version;
|
|
34
|
-
}
|
|
35
|
-
/** `If-Match: <version>` (or `"<version>"`), when sent. */
|
|
36
|
-
function ifMatchOf(value) {
|
|
37
|
-
if (value === undefined || value.trim() === "")
|
|
38
|
-
return undefined;
|
|
39
|
-
const version = Number(value.trim().replace(/^W\//, "").replace(/^"|"$/g, ""));
|
|
40
|
-
if (!Number.isInteger(version) || version < 0)
|
|
41
|
-
return fail(400, "If-Match is the version you read: a whole number, 0 for none yet");
|
|
42
|
-
return version;
|
|
43
|
-
}
|
|
44
|
-
export function environmentManifestRoutes(api) {
|
|
45
|
-
tenantRoute(api, READ, {
|
|
46
|
-
method: "get",
|
|
47
|
-
path: "/v1/environment-manifests",
|
|
48
|
-
tags: ["Environment manifests"],
|
|
49
|
-
summary: "List environment manifests",
|
|
50
|
-
description: "Each manifest's latest version, by name, with how many Environments were made from it.",
|
|
51
|
-
responses: { 200: json(ListEnvironmentManifestsResponse, "The manifests") },
|
|
52
|
-
}, async (c) => jsonResponse(200, await listEnvironmentManifests(c.env.tenant)));
|
|
53
|
-
tenantRoute(api, WRITE, {
|
|
54
|
-
method: "put",
|
|
55
|
-
path: "/v1/environment-manifests/{name}",
|
|
56
|
-
tags: ["Environment manifests"],
|
|
57
|
-
summary: "Save an environment manifest",
|
|
58
|
-
description: "Saves the manifest as its next version, or answers the latest unchanged when nothing differs. No Environment changes: an Environment keeps the version it was made from, and a fork moves it to another (D63). `If-Match: <version>` refuses the save with `412 manifest_changed` when the latest version is no longer the one you read (`0` for a manifest that does not exist yet). With `?dryRun=true` the answer is the plan: the changes, every reason a save would be refused (`errors`), warnings, and how many Environments stay on older versions; nothing is saved. Clients drop a file's `$schema` before they send it.",
|
|
59
|
-
request: {
|
|
60
|
-
params: namePath,
|
|
61
|
-
query: z.object({
|
|
62
|
-
dryRun: z.enum(["true", "false"]).optional().meta({ description: "`true`: answer the plan and save nothing" }),
|
|
63
|
-
}),
|
|
64
|
-
body: { required: true, content: { "application/json": { schema: PutEnvironmentManifestRequest } } },
|
|
65
|
-
},
|
|
66
|
-
responses: {
|
|
67
|
-
200: json(z.union([SaveEnvironmentManifestResponse, EnvironmentManifestPlan]), "The version saved, or the plan with dryRun"),
|
|
68
|
-
400: { description: "The manifest breaks the Tenant's limits or names files the Runtime cannot use" },
|
|
69
|
-
412: { description: "If-Match named a version that is no longer the latest (`manifest_changed`)" },
|
|
70
|
-
},
|
|
71
|
-
}, async (c) => {
|
|
72
|
-
const name = nameOf(c.req.param("name"));
|
|
73
|
-
const body = PutEnvironmentManifestRequestSchema.parse(await readJson(c));
|
|
74
|
-
const ifMatch = ifMatchOf(c.req.header("if-match"));
|
|
75
|
-
const options = ifMatch === undefined ? {} : { ifMatch };
|
|
76
|
-
return jsonResponse(200, c.req.query("dryRun") === "true"
|
|
77
|
-
? await saveEnvironmentManifest(c.env.tenant, name, body, c.get("scope"), { ...options, dryRun: true })
|
|
78
|
-
: await saveEnvironmentManifest(c.env.tenant, name, body, c.get("scope"), options));
|
|
79
|
-
});
|
|
80
|
-
tenantRoute(api, READ, {
|
|
81
|
-
method: "get",
|
|
82
|
-
path: "/v1/environment-manifests/{name}",
|
|
83
|
-
tags: ["Environment manifests"],
|
|
84
|
-
summary: "Get an environment manifest",
|
|
85
|
-
description: "Its latest version.",
|
|
86
|
-
request: { params: namePath },
|
|
87
|
-
responses: { 200: json(EnvironmentManifestView, "The latest version") },
|
|
88
|
-
}, async (c) => jsonResponse(200, await getEnvironmentManifest(c.env.tenant, nameOf(c.req.param("name")))));
|
|
89
|
-
tenantRoute(api, READ, {
|
|
90
|
-
method: "get",
|
|
91
|
-
path: "/v1/environment-manifests/{name}/versions",
|
|
92
|
-
tags: ["Environment manifests"],
|
|
93
|
-
summary: "List an environment manifest's versions",
|
|
94
|
-
description: "Every version, newest first, with who saved it and how many Environments were made from it.",
|
|
95
|
-
request: { params: namePath },
|
|
96
|
-
responses: { 200: json(EnvironmentManifestVersions, "The versions") },
|
|
97
|
-
}, async (c) => jsonResponse(200, await environmentManifestVersions(c.env.tenant, nameOf(c.req.param("name")))));
|
|
98
|
-
tenantRoute(api, READ, {
|
|
99
|
-
method: "get",
|
|
100
|
-
path: "/v1/environment-manifests/{name}/versions/{version}",
|
|
101
|
-
tags: ["Environment manifests"],
|
|
102
|
-
summary: "Get one version of an environment manifest",
|
|
103
|
-
request: { params: namePath.extend({ version: z.string().meta({ description: "The version number" }) }) },
|
|
104
|
-
responses: { 200: json(EnvironmentManifestView, "The version") },
|
|
105
|
-
}, async (c) => jsonResponse(200, await getEnvironmentManifest(c.env.tenant, nameOf(c.req.param("name")), versionOf(c.req.param("version")))));
|
|
106
|
-
tenantRoute(api, WRITE, {
|
|
107
|
-
method: "delete",
|
|
108
|
-
path: "/v1/environment-manifests/{name}",
|
|
109
|
-
tags: ["Environment manifests"],
|
|
110
|
-
summary: "Delete an environment manifest",
|
|
111
|
-
description: "Deletes every version. Refused while any Environment was made from one (`409 manifest_in_use`).",
|
|
112
|
-
request: { params: namePath },
|
|
113
|
-
responses: {
|
|
114
|
-
200: json(DeleteEnvironmentManifestResponse, "Deleted, or there was none"),
|
|
115
|
-
409: { description: "An Environment was made from one of its versions (`manifest_in_use`)" },
|
|
116
|
-
},
|
|
117
|
-
}, async (c) => jsonResponse(200, await deleteEnvironmentManifest(c.env.tenant, nameOf(c.req.param("name")))));
|
|
118
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environments (`/v1/environments/**`, protocol 11, D55, D56): create, find or change one by id,
|
|
3
|
-
* read it, list them by label, read its lifecycle stream, stop, reset and delete it, and write
|
|
4
|
-
* its vault's secrets. Ids may hold `/`, sent percent-encoded as one path segment
|
|
5
|
-
* (`users%2Falice%2Fweb`). A token caller reaches only the ids its Environment grants match,
|
|
6
|
-
* and changes them only with `environments:write`. Secret values are write-only: no route reads
|
|
7
|
-
* one back.
|
|
8
|
-
*/
|
|
9
|
-
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
10
|
-
import type { TenantEnv } from "../app.js";
|
|
11
|
-
export declare function environmentRoutes(api: OpenAPIHono<TenantEnv>): void;
|