@nylorun/runtime 0.24.0-beta → 0.25.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 +104 -0
- package/README.md +10 -2
- package/dist/api/a2a/card.d.ts +11 -1
- package/dist/api/a2a/card.js +26 -2
- package/dist/api/a2a/endpoint.js +4 -2
- package/dist/api/a2a/protocol.d.ts +25 -2
- package/dist/api/a2a/protocol.js +20 -3
- package/dist/api/a2a/routes.d.ts +4 -1
- package/dist/api/a2a/routes.js +65 -7
- package/dist/api/ag-ui/endpoint.js +5 -2
- package/dist/api/ag-ui/history.d.ts +6 -1
- package/dist/api/ag-ui/history.js +35 -2
- package/dist/api/ag-ui/routes.js +53 -11
- package/dist/api/components.d.ts +1165 -678
- package/dist/api/components.js +16 -1
- package/dist/api/gate/keys.d.ts +2 -1
- package/dist/api/gate/keys.js +7 -0
- package/dist/api/gate/routes.js +13 -0
- package/dist/api/http/app.js +13 -2
- package/dist/api/http/body.d.ts +3 -3
- package/dist/api/http/body.js +7 -7
- package/dist/api/http/routes/environment-manifests.d.ts +9 -0
- package/dist/api/http/routes/environment-manifests.js +118 -0
- package/dist/api/http/routes/environments.js +61 -12
- package/dist/api/http/routes/reads.d.ts +52 -3
- package/dist/api/http/routes/sessions.js +13 -3
- package/dist/api/http/routes/tenant.js +35 -7
- package/dist/api/inbound-files.d.ts +65 -0
- package/dist/api/inbound-files.js +115 -0
- package/dist/api/openapi.js +18 -3
- package/dist/artifacts/disk.js +20 -14
- package/dist/artifacts/media-types.d.ts +15 -0
- package/dist/artifacts/media-types.js +56 -4
- package/dist/artifacts/parts.d.ts +12 -3
- package/dist/artifacts/parts.js +15 -4
- package/dist/artifacts/workspace.d.ts +4 -4
- package/dist/artifacts/workspace.js +6 -18
- package/dist/core/flow-host.d.ts +1 -1
- package/dist/core/flow-host.js +2 -2
- package/dist/core/sandbox-routes.js +2 -2
- package/dist/core/turn-manifest.d.ts +3 -2
- package/dist/core/turn-manifest.js +29 -5
- package/dist/gates/egress-credentials.js +1 -1
- package/dist/gates/egress.d.ts +13 -19
- package/dist/gates/egress.js +30 -29
- package/dist/gates/http-tool.d.ts +3 -4
- package/dist/gates/http-tool.js +8 -12
- package/dist/gates/journal.js +0 -1
- package/dist/gates/mcp-handler.js +2 -3
- package/dist/gates/policy.js +1 -3
- package/dist/gates/tool-contract.d.ts +1 -1
- package/dist/harness/calls.d.ts +2 -2
- package/dist/harness/calls.js +9 -12
- package/dist/harness/main.js +7 -1
- package/dist/harness/pod.d.ts +6 -1
- package/dist/harness/pod.js +5 -0
- package/dist/harness/service.js +5 -5
- package/dist/harness/setup.d.ts +2 -0
- package/dist/harness/setup.js +25 -1
- package/dist/harness-api/record.d.ts +1 -1
- package/dist/harness-api/record.js +13 -13
- package/dist/harness-api/server.d.ts +27 -4
- package/dist/harness-api/server.js +41 -8
- package/dist/harness-api/tool-journal.d.ts +17 -8
- package/dist/harness-api/tool-journal.js +41 -11
- package/dist/harness-api/workspace.d.ts +7 -5
- package/dist/harness-api/workspace.js +25 -19
- package/dist/host/gates.js +2 -2
- package/dist/host/stack-config.js +1 -1
- package/dist/keys/keys.d.ts +9 -2
- package/dist/keys/keys.js +4 -1
- package/dist/management-openapi.json +366 -61
- package/dist/mcp/connect.d.ts +1 -2
- package/dist/mcp/connect.js +1 -4
- package/dist/mcp/pool.d.ts +1 -4
- package/dist/mcp/pool.js +13 -27
- package/dist/mcp/preview.js +0 -1
- package/dist/mcp/snapshot.d.ts +11 -13
- package/dist/mcp/snapshot.js +27 -38
- package/dist/model/capabilities.d.ts +26 -0
- package/dist/model/capabilities.js +44 -0
- package/dist/model/catalog.d.ts +34 -3
- package/dist/model/catalog.js +38 -2
- package/dist/model/models.d.ts +2 -0
- package/dist/model/models.js +1 -1
- package/dist/model/native-blocks.d.ts +35 -0
- package/dist/model/native-blocks.js +170 -0
- package/dist/model/pi-model.js +106 -94
- package/dist/openapi.json +9554 -5104
- package/dist/record/environment.js +1 -1
- package/dist/sandbox/join.js +4 -0
- package/dist/sandbox/manager.d.ts +32 -14
- package/dist/sandbox/manager.js +132 -93
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +2 -2
- package/dist/sandbox/pods/client.d.ts +3 -1
- package/dist/sandbox/pods/lifecycle.d.ts +8 -0
- package/dist/sandbox/pods/lifecycle.js +15 -0
- package/dist/sandbox/pods/spec.js +2 -1
- package/dist/sandbox/resolve.d.ts +5 -3
- package/dist/sandbox/resolve.js +9 -2
- package/dist/sandbox/runtime-tools.d.ts +9 -0
- package/dist/sandbox/runtime-tools.js +16 -0
- package/dist/sandbox/session-sandbox.d.ts +4 -6
- package/dist/sandbox/session-sandbox.js +47 -94
- package/dist/sandbox/setup.d.ts +4 -1
- package/dist/sandbox/setup.js +46 -9
- package/dist/sandbox/share.d.ts +12 -7
- package/dist/sandbox/share.js +27 -25
- package/dist/sandbox/skills.d.ts +8 -6
- package/dist/sandbox/skills.js +24 -23
- package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
- package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
- package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
- package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.js +8 -2
- package/dist/store/postgres/schema.d.ts +217 -0
- package/dist/store/postgres/schema.js +36 -2
- package/dist/store/postgres/store.js +79 -4
- package/dist/store/types.d.ts +68 -14
- package/dist/tenant/advance.js +3 -0
- package/dist/tenant/artifact-tool.d.ts +1 -1
- package/dist/tenant/artifact-tool.js +43 -22
- package/dist/tenant/commands.js +24 -4
- package/dist/tenant/context.d.ts +10 -4
- package/dist/tenant/effects.js +7 -9
- package/dist/tenant/environment-manifests.d.ts +57 -0
- package/dist/tenant/environment-manifests.js +200 -0
- package/dist/tenant/environments.d.ts +54 -47
- package/dist/tenant/environments.js +304 -83
- package/dist/tenant/model-setting.d.ts +14 -0
- package/dist/tenant/model-setting.js +51 -0
- package/dist/tenant/sessions.d.ts +5 -1
- package/dist/tenant/sessions.js +45 -12
- package/dist/tenant/skill-tool.d.ts +3 -3
- package/dist/tenant/skill-tool.js +6 -11
- package/dist/tenant/sweep.js +1 -1
- package/dist/tenant/tool-results.js +1 -1
- package/dist/tenant/tool-search.d.ts +7 -11
- package/dist/tenant/tool-search.js +8 -5
- package/dist/tenant/transcript.d.ts +51 -32
- package/dist/tenant/transcript.js +2 -1
- package/dist/traces/ids.d.ts +0 -1
- package/dist/traces/ids.js +0 -4
- package/dist/traces/map.d.ts +2 -2
- package/dist/traces/map.js +1 -29
- package/dist/vault/coverage.js +11 -13
- package/dist/vault/host-model.d.ts +4 -1
- package/dist/vault/host-model.js +10 -2
- package/dist/vault/service.d.ts +49 -4
- package/dist/vault/service.js +153 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/sandbox/capability.d.ts +0 -3
- package/dist/sandbox/capability.js +0 -10
package/dist/api/components.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* global registry.
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
|
-
import { SessionListItemSchema, ModelCallSchema, SessionPageSchema, SessionManifestViewSchema, HistoryPageSchema, SessionUsageTotalsSchema, ModelCallsPageSchema, ModelCallExportPageSchema, EnvironmentPageSchema, ToolCallSchema, ToolCallsPageSchema, TurnTraceSchema, JwksSchema, SigningKeyListSchema, SigningKeyViewSchema, RotateSigningKeysRequestSchema, RevokeSigningKeyRequestSchema, MeResponseSchema, TenantStatusSchema, ResetTenantRequestSchema, ResetTenantResponseSchema, SeedTenantConfigRequestSchema, SeedTenantConfigResponseSchema, HostModelCatalogSchema, TenantSandboxViewSchema, ModelUsageTotalsSchema, ModelBudgetsSchema, PutModelBudgetsRequestSchema, ToolPolicySchema, PutToolPolicyRequestSchema, PutTenantEnvironmentsRequestSchema, ListProvidersResponseSchema, HostModelViewSchema, PutHostModelRequestSchema, SelectHostModelRequestSchema, PutEnvironmentSecretRequestSchema, EnvironmentSecretViewSchema, ListEnvironmentSecretsResponseSchema, McpPreviewRequestSchema, McpPreviewSchema, CredentialCoverageRequestSchema, CredentialCoverageSchema, DeletedResponseSchema, ListAgentsResponseSchema, ListPublicAgentsResponseSchema, ListSessionsResponseSchema, LiveEventSchema, PutAgentRequestSchema, PutAgentResponseSchema, PutSessionRequestSchema, SessionItemsResponseSchema, SessionViewSchema, StreamClosedFrameSchema, AcceptedResponseSchema, SandboxToolOutcomeSchema, PutEnvironmentRequestSchema, EnvironmentViewSchema, EnvironmentSnapshotSchema, RestoreEnvironmentRequestSchema, EnvironmentRestoreSchema, EnvironmentVersionsSchema, ListEnvironmentsResponseSchema, DeleteEnvironmentResponseSchema, ListEnvironmentEventsResponseSchema, ArtifactViewSchema, ArtifactListItemSchema, ArtifactPageSchema, ArtifactVersionViewSchema, ListArtifactsResponseSchema, UploadArtifactResponseSchema, DefinitionFileViewSchema, DeleteArtifactResponseSchema, CreateArtifactLinkRequestSchema, ArtifactLinkSchema, PutTenantArtifactsRequestSchema, TenantArtifactsViewSchema, ArtifactTreeSchema, ArtifactDiffSchema, SessionCommandSchema, ListOperatorKeysResponseSchema, PutOperatorKeyResponseSchema, DeleteOperatorKeyResponseSchema, OperatorKeySchema, ProtocolRejectedResponseSchema, RejectedResponseSchema, EVENT_SCHEMAS, EVENT_TYPES, } from "@nylorun/core/contracts";
|
|
8
|
+
import { EnvironmentManifestSchema, EnvironmentSecretSlotsSchema, DeleteEnvironmentManifestResponseSchema, EnvironmentManifestPlanSchema, EnvironmentManifestVersionsSchema, EnvironmentManifestViewSchema, ListEnvironmentManifestsResponseSchema, PutEnvironmentManifestRequestSchema, PutEnvironmentSecretValueRequestSchema, SaveEnvironmentManifestResponseSchema, SessionListItemSchema, ModelCallSchema, SessionPageSchema, SessionManifestViewSchema, HistoryPageSchema, SessionUsageTotalsSchema, ModelCallsPageSchema, ModelCallExportPageSchema, EnvironmentPageSchema, ToolCallSchema, ToolCallsPageSchema, TurnTraceSchema, JwksSchema, SigningKeyListSchema, SigningKeyViewSchema, RotateSigningKeysRequestSchema, RevokeSigningKeyRequestSchema, MeResponseSchema, TenantStatusSchema, ResetTenantRequestSchema, ResetTenantResponseSchema, SeedTenantConfigRequestSchema, SeedTenantConfigResponseSchema, HostModelCatalogSchema, TenantSandboxViewSchema, ModelUsageTotalsSchema, ModelBudgetsSchema, PutModelBudgetsRequestSchema, ToolPolicySchema, PutToolPolicyRequestSchema, PutModelInputsRequestSchema, ModelInputsViewSchema, PutTenantEnvironmentsRequestSchema, ListProvidersResponseSchema, HostModelViewSchema, PutHostModelRequestSchema, SelectHostModelRequestSchema, PutEnvironmentSecretRequestSchema, EnvironmentSecretViewSchema, ListEnvironmentSecretsResponseSchema, McpPreviewRequestSchema, McpPreviewSchema, CredentialCoverageRequestSchema, CredentialCoverageSchema, DeletedResponseSchema, ListAgentsResponseSchema, ListPublicAgentsResponseSchema, ListSessionsResponseSchema, LiveEventSchema, PutAgentRequestSchema, PutAgentResponseSchema, PutSessionRequestSchema, SessionItemsResponseSchema, SessionViewSchema, StreamClosedFrameSchema, AcceptedResponseSchema, SandboxToolOutcomeSchema, PutEnvironmentRequestSchema, EnvironmentViewSchema, EnvironmentSnapshotSchema, RestoreEnvironmentRequestSchema, ForkEnvironmentRequestSchema, EnvironmentForkPlanSchema, ForkEnvironmentResponseSchema, EnvironmentRestoreSchema, EnvironmentVersionsSchema, ListEnvironmentsResponseSchema, DeleteEnvironmentResponseSchema, ListEnvironmentEventsResponseSchema, ArtifactViewSchema, ArtifactListItemSchema, ArtifactPageSchema, ArtifactVersionViewSchema, ListArtifactsResponseSchema, UploadArtifactResponseSchema, DefinitionFileViewSchema, DeleteArtifactResponseSchema, CreateArtifactLinkRequestSchema, ArtifactLinkSchema, PutTenantArtifactsRequestSchema, TenantArtifactsViewSchema, ArtifactTreeSchema, ArtifactDiffSchema, SessionCommandSchema, ListOperatorKeysResponseSchema, PutOperatorKeyResponseSchema, DeleteOperatorKeyResponseSchema, OperatorKeySchema, ProtocolRejectedResponseSchema, RejectedResponseSchema, EVENT_SCHEMAS, EVENT_TYPES, } from "@nylorun/core/contracts";
|
|
9
9
|
function named(id, schema) {
|
|
10
10
|
return schema.meta({ id });
|
|
11
11
|
}
|
|
@@ -18,9 +18,22 @@ export const DeleteOperatorKeyResponse = named("DeleteOperatorKeyResponse", Dele
|
|
|
18
18
|
export const SandboxToolOutcome = named("SandboxToolOutcome", SandboxToolOutcomeSchema);
|
|
19
19
|
export const PutEnvironmentRequest = named("PutEnvironmentRequest", PutEnvironmentRequestSchema);
|
|
20
20
|
export const EnvironmentView = named("EnvironmentView", EnvironmentViewSchema);
|
|
21
|
+
export const EnvironmentSecretSlots = named("EnvironmentSecretSlots", EnvironmentSecretSlotsSchema);
|
|
22
|
+
export const EnvironmentManifest = named("EnvironmentManifest", EnvironmentManifestSchema);
|
|
23
|
+
export const PutEnvironmentManifestRequest = named("PutEnvironmentManifestRequest", PutEnvironmentManifestRequestSchema);
|
|
24
|
+
export const EnvironmentManifestView = named("EnvironmentManifestView", EnvironmentManifestViewSchema);
|
|
25
|
+
export const EnvironmentManifestPlan = named("EnvironmentManifestPlan", EnvironmentManifestPlanSchema);
|
|
26
|
+
export const SaveEnvironmentManifestResponse = named("SaveEnvironmentManifestResponse", SaveEnvironmentManifestResponseSchema);
|
|
27
|
+
export const ListEnvironmentManifestsResponse = named("ListEnvironmentManifestsResponse", ListEnvironmentManifestsResponseSchema);
|
|
28
|
+
export const EnvironmentManifestVersions = named("EnvironmentManifestVersions", EnvironmentManifestVersionsSchema);
|
|
29
|
+
export const DeleteEnvironmentManifestResponse = named("DeleteEnvironmentManifestResponse", DeleteEnvironmentManifestResponseSchema);
|
|
30
|
+
export const PutEnvironmentSecretValueRequest = named("PutEnvironmentSecretValueRequest", PutEnvironmentSecretValueRequestSchema);
|
|
21
31
|
export const EnvironmentSnapshot = named("EnvironmentSnapshot", EnvironmentSnapshotSchema);
|
|
22
32
|
export const RestoreEnvironmentRequest = named("RestoreEnvironmentRequest", RestoreEnvironmentRequestSchema);
|
|
23
33
|
export const EnvironmentRestore = named("EnvironmentRestore", EnvironmentRestoreSchema);
|
|
34
|
+
export const ForkEnvironmentRequest = named("ForkEnvironmentRequest", ForkEnvironmentRequestSchema);
|
|
35
|
+
export const EnvironmentForkPlan = named("EnvironmentForkPlan", EnvironmentForkPlanSchema);
|
|
36
|
+
export const ForkEnvironmentResponse = named("ForkEnvironmentResponse", ForkEnvironmentResponseSchema);
|
|
24
37
|
export const EnvironmentVersions = named("EnvironmentVersions", EnvironmentVersionsSchema);
|
|
25
38
|
export const ListEnvironmentsResponse = named("ListEnvironmentsResponse", ListEnvironmentsResponseSchema);
|
|
26
39
|
export const DeleteEnvironmentResponse = named("DeleteEnvironmentResponse", DeleteEnvironmentResponseSchema);
|
|
@@ -72,6 +85,8 @@ export const ModelBudgets = named("ModelBudgets", ModelBudgetsSchema);
|
|
|
72
85
|
export const PutModelBudgetsRequest = named("PutModelBudgetsRequest", PutModelBudgetsRequestSchema);
|
|
73
86
|
export const ToolPolicy = named("ToolPolicy", ToolPolicySchema);
|
|
74
87
|
export const PutToolPolicyRequest = named("PutToolPolicyRequest", PutToolPolicyRequestSchema);
|
|
88
|
+
export const PutModelInputsRequest = named("PutModelInputsRequest", PutModelInputsRequestSchema);
|
|
89
|
+
export const ModelInputsView = named("ModelInputsView", ModelInputsViewSchema);
|
|
75
90
|
export const PutTenantEnvironmentsRequest = named("PutTenantEnvironmentsRequest", PutTenantEnvironmentsRequestSchema);
|
|
76
91
|
export const ListProvidersResponse = named("ListProvidersResponse", ListProvidersResponseSchema);
|
|
77
92
|
export const HostModelView = named("HostModelView", HostModelViewSchema);
|
package/dist/api/gate/keys.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `keys` service's route on the gateway's listener (F4.2, `contract.ts`): one operation of
|
|
3
3
|
* `Keys` per request, run with the vault key of the gateway's Tenant. Errors keep their status,
|
|
4
|
-
* code and details. Logs the operation
|
|
4
|
+
* code and details. Logs the operation, its outcome and an internal failure's cause, never an
|
|
5
|
+
* argument or a result.
|
|
5
6
|
*/
|
|
6
7
|
import type { Env, Hono, MiddlewareHandler } from "hono";
|
|
7
8
|
import type { Logger } from "../../tenant/types.js";
|
package/dist/api/gate/keys.js
CHANGED
|
@@ -29,6 +29,13 @@ export function mountKeysRoutes(app, options) {
|
|
|
29
29
|
}
|
|
30
30
|
catch (error) {
|
|
31
31
|
answer = { error: errorOf(error) };
|
|
32
|
+
// The caller sees only "The keys service failed": the cause is logged, never the args.
|
|
33
|
+
if (answer.error.status === 500)
|
|
34
|
+
options.logger.error("keys_request_failed", {
|
|
35
|
+
operation,
|
|
36
|
+
error: error?.message ?? String(error),
|
|
37
|
+
stack: error?.stack,
|
|
38
|
+
});
|
|
32
39
|
}
|
|
33
40
|
options.logger.info("keys_request", {
|
|
34
41
|
operation,
|
package/dist/api/gate/routes.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { createHash } from "node:crypto";
|
|
21
21
|
import { Hono } from "hono";
|
|
22
22
|
import { bodyLimit } from "hono/body-limit";
|
|
23
|
+
import { HTTPException } from "hono/http-exception";
|
|
23
24
|
import { isTenantId } from "@nylorun/core/compatibility";
|
|
24
25
|
import { MAX_MODEL_CALL_BYTES, MODEL_CALLS_PATH, ModelCallBodySchema, TENANT_HEADER, } from "../../gates/contract.js";
|
|
25
26
|
import { InflightConflict, InflightStale } from "../../gates/inflight.js";
|
|
@@ -38,6 +39,18 @@ export function createGatesApp(options) {
|
|
|
38
39
|
const app = new Hono();
|
|
39
40
|
const maxSize = options.maxBodyBytes ?? MAX_MODEL_CALL_BYTES;
|
|
40
41
|
const logger = options.logger ?? { info() { }, warn() { }, error() { } };
|
|
42
|
+
// Hono's default, but logged through the logger: never the body, which may hold secrets.
|
|
43
|
+
app.onError((error, c) => {
|
|
44
|
+
if (error instanceof HTTPException)
|
|
45
|
+
return error.getResponse();
|
|
46
|
+
logger.error("request_failed", {
|
|
47
|
+
method: c.req.method,
|
|
48
|
+
route: c.req.routePath,
|
|
49
|
+
error: error.message,
|
|
50
|
+
stack: error.stack,
|
|
51
|
+
});
|
|
52
|
+
return c.text("Internal Server Error", 500);
|
|
53
|
+
});
|
|
41
54
|
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
42
55
|
app.get("/ready", async (c) => (await options.ready()) ? c.json({ ready: true }) : c.json({ ready: false }, 503));
|
|
43
56
|
const bearerOf = (c) => /^Bearer (.+)$/.exec(c.req.header("authorization") ?? "")?.[1];
|
package/dist/api/http/app.js
CHANGED
|
@@ -13,6 +13,7 @@ import { jsonResponse, rejectionOf } from "./respond.js";
|
|
|
13
13
|
import { accessRoutes } from "./routes/access.js";
|
|
14
14
|
import { meRoutes } from "./routes/me.js";
|
|
15
15
|
import { environmentRoutes } from "./routes/environments.js";
|
|
16
|
+
import { environmentManifestRoutes } from "./routes/environment-manifests.js";
|
|
16
17
|
import { artifactRoutes } from "./routes/artifacts.js";
|
|
17
18
|
import { readRoutes } from "./routes/reads.js";
|
|
18
19
|
import { sessionRoutes } from "./routes/sessions.js";
|
|
@@ -45,6 +46,7 @@ function build() {
|
|
|
45
46
|
sessionRoutes(api);
|
|
46
47
|
fileRoutes(api);
|
|
47
48
|
environmentRoutes(api);
|
|
49
|
+
environmentManifestRoutes(api);
|
|
48
50
|
artifactRoutes(api);
|
|
49
51
|
tenantRoutes(api);
|
|
50
52
|
keyRoutes(api);
|
|
@@ -56,13 +58,22 @@ function build() {
|
|
|
56
58
|
a2aRoutes(api);
|
|
57
59
|
api.notFound(routeNotFound);
|
|
58
60
|
api.onError((error, c) => {
|
|
59
|
-
const { outgoing } = c.env;
|
|
61
|
+
const { outgoing, tenant } = c.env;
|
|
62
|
+
const rejection = rejectionOf(error);
|
|
63
|
+
// The client sees only `internal_error`: the operator's log has the cause. The route's
|
|
64
|
+
// pattern, not its path, and never the body, which may hold secrets.
|
|
65
|
+
if (rejection.status === 500)
|
|
66
|
+
tenant.config.logger.error("request_failed", {
|
|
67
|
+
method: c.req.method,
|
|
68
|
+
route: c.req.routePath,
|
|
69
|
+
error: error.message,
|
|
70
|
+
stack: error.stack,
|
|
71
|
+
});
|
|
60
72
|
// Once a response has started, the rejection can only end it.
|
|
61
73
|
if (outgoing.headersSent) {
|
|
62
74
|
outgoing.end();
|
|
63
75
|
return RESPONSE_ALREADY_SENT;
|
|
64
76
|
}
|
|
65
|
-
const rejection = rejectionOf(error);
|
|
66
77
|
return jsonResponse(rejection.status, rejection.body, rejection.headers);
|
|
67
78
|
});
|
|
68
79
|
readRoutes(api);
|
package/dist/api/http/body.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The body as text
|
|
2
|
-
export declare function readText(request: Request): Promise<string>;
|
|
1
|
+
/** The body as text; past `maxBytes`, `413 Request too large`. */
|
|
2
|
+
export declare function readText(request: Request, maxBytes?: number): Promise<string>;
|
|
3
3
|
/** The body as JSON, before any schema. */
|
|
4
|
-
export declare function readJson(request: Request): Promise<unknown>;
|
|
4
|
+
export declare function readJson(request: Request, maxBytes?: number): Promise<unknown>;
|
package/dist/api/http/body.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Request bodies of Tenant routes, read as the router they replace read them
|
|
3
|
-
* (`tenant/http.ts`): at most 1 MiB
|
|
4
|
-
* `400 Invalid JSON`.
|
|
3
|
+
* (`tenant/http.ts`): at most 1 MiB unless a route allows more (an endpoint that takes files
|
|
4
|
+
* inline), UTF-8, and a missing or malformed JSON body is `400 Invalid JSON`.
|
|
5
5
|
*/
|
|
6
6
|
import { fail } from "../../tenant/http.js";
|
|
7
7
|
const MAX_BODY_BYTES = 1024 * 1024;
|
|
8
|
-
/** The body as text
|
|
9
|
-
export async function readText(request) {
|
|
8
|
+
/** The body as text; past `maxBytes`, `413 Request too large`. */
|
|
9
|
+
export async function readText(request, maxBytes = MAX_BODY_BYTES) {
|
|
10
10
|
if (request.body === null)
|
|
11
11
|
return "";
|
|
12
12
|
const chunks = [];
|
|
@@ -17,7 +17,7 @@ export async function readText(request) {
|
|
|
17
17
|
if (done)
|
|
18
18
|
break;
|
|
19
19
|
bytes += value.byteLength;
|
|
20
|
-
if (bytes >
|
|
20
|
+
if (bytes > maxBytes) {
|
|
21
21
|
await reader.cancel();
|
|
22
22
|
fail(413, "Request too large");
|
|
23
23
|
}
|
|
@@ -26,8 +26,8 @@ export async function readText(request) {
|
|
|
26
26
|
return Buffer.concat(chunks).toString("utf8");
|
|
27
27
|
}
|
|
28
28
|
/** The body as JSON, before any schema. */
|
|
29
|
-
export async function readJson(request) {
|
|
30
|
-
const text = await readText(request);
|
|
29
|
+
export async function readJson(request, maxBytes = MAX_BODY_BYTES) {
|
|
30
|
+
const text = await readText(request, maxBytes);
|
|
31
31
|
try {
|
|
32
32
|
return JSON.parse(text);
|
|
33
33
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
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;
|
|
@@ -0,0 +1,118 @@
|
|
|
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.req.raw));
|
|
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,9 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { isEnvironmentId, PutEnvironmentRequestSchema,
|
|
2
|
+
import { ENVIRONMENT_EVENT_TYPES, ForkEnvironmentRequestSchema, isEnvironmentId, PutEnvironmentRequestSchema, RestoreEnvironmentRequestSchema, } from "@nylorun/core/contracts";
|
|
3
3
|
import { deleteEnvironmentVersion, environmentVersions, restoreEnvironment, snapshotEnvironment, } from "../../../artifacts/disk.js";
|
|
4
|
-
import { DeleteEnvironmentResponse, DeletedResponse, EnvironmentPage, EnvironmentRestore, EnvironmentSnapshot, EnvironmentVersions, RestoreEnvironmentRequest, EnvironmentSecretView, EnvironmentView, ListEnvironmentEventsResponse, ListEnvironmentSecretsResponse, ListEnvironmentsResponse, PutEnvironmentRequest, PutEnvironmentSecretRequest, } from "../../components.js";
|
|
4
|
+
import { DeleteEnvironmentResponse, DeletedResponse, EnvironmentPage, EnvironmentRestore, EnvironmentSnapshot, EnvironmentVersions, ForkEnvironmentRequest, ForkEnvironmentResponse, RestoreEnvironmentRequest, EnvironmentSecretView, EnvironmentView, ListEnvironmentEventsResponse, ListEnvironmentSecretsResponse, ListEnvironmentsResponse, PutEnvironmentRequest, PutEnvironmentSecretRequest, PutEnvironmentSecretValueRequest, } from "../../components.js";
|
|
5
5
|
import { fail } from "../../../tenant/http.js";
|
|
6
|
-
import { actorOf, assertReaches, deleteEnvironment, environmentEventsOf, getEnvironment, listEnvironments, putEnvironment, resetEnvironment, stopEnvironment, } from "../../../tenant/environments.js";
|
|
6
|
+
import { actorOf, assertReaches, deleteEnvironment, environmentEventsOf, forkEnvironment, getEnvironment, listEnvironments, putEnvironment, resetEnvironment, secretRequestFor, stopEnvironment, } from "../../../tenant/environments.js";
|
|
7
7
|
import { readJson } from "../body.js";
|
|
8
8
|
import { tenantRoute } from "../define.js";
|
|
9
9
|
import { environmentPage, pageQuery } from "./reads.js";
|
|
@@ -75,7 +75,7 @@ export function environmentRoutes(api) {
|
|
|
75
75
|
path: "/v1/environments/{environmentId}",
|
|
76
76
|
tags: ["Environments"],
|
|
77
77
|
summary: "Create, find or change an Environment",
|
|
78
|
-
description: "Creates the Environment and its vault within the Tenant's limits, or answers the one with this id, so get-or-create is one call.
|
|
78
|
+
description: "Creates the Environment and its vault within the Tenant's limits, or answers the one with this id, so get-or-create is one call. It is made from one version of an environment manifest (`manifest: \"name\"` takes the latest, `\"name@n\"` version n) or from the inline fields, and never changes what it runs after that (protocol 14, D63): on an existing one, labels replace, `ownerUserId` sets or (with `null`) clears the owner guard, fields that match what it runs are accepted, and anything else is `409 environment_immutable`, which names the fork that makes a new Environment instead. Kind `pod` needs sandbox pods (`nylorun local sandbox enable`) and is created at once.",
|
|
79
79
|
request: {
|
|
80
80
|
params: environmentId,
|
|
81
81
|
body: { required: true, content: { "application/json": { schema: PutEnvironmentRequest } } },
|
|
@@ -83,7 +83,7 @@ export function environmentRoutes(api) {
|
|
|
83
83
|
responses: {
|
|
84
84
|
200: json(EnvironmentView, "The Environment"),
|
|
85
85
|
409: {
|
|
86
|
-
description: "An Environment with this id
|
|
86
|
+
description: "An Environment with this id runs something else (`environment_immutable`), the Tenant holds as many Environments as it allows (`limit_exceeded`), kind pod without sandbox pods (`environment_unavailable`), or it is being deleted (`environment_busy`)",
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
89
|
}, async (c) => {
|
|
@@ -104,12 +104,15 @@ export function environmentRoutes(api) {
|
|
|
104
104
|
method: "get",
|
|
105
105
|
path: "/v1/environments/{environmentId}/events",
|
|
106
106
|
tags: ["Environments"],
|
|
107
|
-
summary: "Read an Environment's
|
|
108
|
-
description: "`environment.created`, `.attached`, `.detached`, `.deleted
|
|
107
|
+
summary: "Read an Environment's events",
|
|
108
|
+
description: "`environment.created`, `.attached`, `.detached`, `.deleted`, a pod's `.running`, `.suspended`, `.relaunched`, `.lost`, `.reset` and `.failed`, and `environment.egress` for every connection its sandbox opens through egress-gate, naming the turns that were running (D67), in order, numbered from 0, at most 1000 per call.",
|
|
109
109
|
request: {
|
|
110
110
|
params: environmentId,
|
|
111
111
|
query: z.object({
|
|
112
112
|
from: z.string().optional().meta({ description: "The first `seq` to return" }),
|
|
113
|
+
types: z.string().optional().meta({ description: "Only these event types, comma-separated (`environment.egress`)" }),
|
|
114
|
+
since: z.string().optional().meta({ description: "Only events recorded at or after this ISO time" }),
|
|
115
|
+
until: z.string().optional().meta({ description: "Only events recorded before this ISO time" }),
|
|
113
116
|
}),
|
|
114
117
|
},
|
|
115
118
|
responses: { 200: json(ListEnvironmentEventsResponse, "The events") },
|
|
@@ -117,7 +120,27 @@ export function environmentRoutes(api) {
|
|
|
117
120
|
const from = c.req.query("from");
|
|
118
121
|
if (from !== undefined && !/^\d+$/.test(from))
|
|
119
122
|
fail(400, "from must be a seq");
|
|
120
|
-
|
|
123
|
+
const types = c.req.query("types")?.split(",").map((type) => type.trim()).filter(Boolean);
|
|
124
|
+
const unknown = types?.find((type) => !ENVIRONMENT_EVENT_TYPES.includes(type));
|
|
125
|
+
if (unknown !== undefined)
|
|
126
|
+
fail(400, `types: ${unknown} is not an Environment event type`);
|
|
127
|
+
const time = (name) => {
|
|
128
|
+
const value = c.req.query(name);
|
|
129
|
+
if (value === undefined)
|
|
130
|
+
return undefined;
|
|
131
|
+
const at = Date.parse(value);
|
|
132
|
+
if (!Number.isFinite(at))
|
|
133
|
+
fail(400, `${name} must be an ISO time`);
|
|
134
|
+
return new Date(at).toISOString();
|
|
135
|
+
};
|
|
136
|
+
const since = time("since");
|
|
137
|
+
const until = time("until");
|
|
138
|
+
return jsonResponse(200, await environmentEventsOf(c.env.tenant, idOf(c.req.param("environmentId")), c.get("scope"), {
|
|
139
|
+
...(from === undefined ? {} : { fromSeq: Number(from) }),
|
|
140
|
+
...(types === undefined || types.length === 0 ? {} : { types }),
|
|
141
|
+
...(since === undefined ? {} : { since }),
|
|
142
|
+
...(until === undefined ? {} : { until }),
|
|
143
|
+
}));
|
|
121
144
|
});
|
|
122
145
|
tenantRoute(api, WRITE, {
|
|
123
146
|
method: "delete",
|
|
@@ -193,6 +216,28 @@ export function environmentRoutes(api) {
|
|
|
193
216
|
const body = RestoreEnvironmentRequestSchema.parse(await readJson(c.req.raw));
|
|
194
217
|
return jsonResponse(200, await restoreEnvironment(c.env.tenant, idOf(c.req.param("environmentId")), c.get("scope"), body.version));
|
|
195
218
|
});
|
|
219
|
+
tenantRoute(api, WRITE, {
|
|
220
|
+
method: "post",
|
|
221
|
+
path: "/v1/environments/{environmentId}/fork",
|
|
222
|
+
tags: ["Environments"],
|
|
223
|
+
summary: "Fork an Environment",
|
|
224
|
+
description: "How an Environment gets a new manifest version (Q15): a new Environment `id`, made from `manifest` (default the source's manifest at its latest version), its disk started from a version of this one's (`disk`: `latest`, the default, takes a snapshot first; a version number; or `empty`) and its secrets copied inside the Runtime (`secrets`: `copy`, the default, copies those the new manifest declares; `none`). On a fork onto other setup the new manifest's setup runs on the copied disk before its first turn. This Environment keeps what it runs, its disk and its sessions. `dryRun` answers the plan and makes nothing.",
|
|
225
|
+
request: {
|
|
226
|
+
params: environmentId,
|
|
227
|
+
body: { required: true, content: { "application/json": { schema: ForkEnvironmentRequest } } },
|
|
228
|
+
},
|
|
229
|
+
responses: {
|
|
230
|
+
200: json(ForkEnvironmentResponse, "The plan (`dryRun`)"),
|
|
231
|
+
201: json(ForkEnvironmentResponse, "The new Environment, and the plan it ran"),
|
|
232
|
+
400: { description: "The source was made from inline fields and no manifest is named, or the manifest does not resolve" },
|
|
233
|
+
404: { description: "No such Environment, manifest version (`manifest_not_found`) or disk version" },
|
|
234
|
+
409: { description: "The id exists, or a turn or another copy holds the source's disk (`environment_busy`)" },
|
|
235
|
+
},
|
|
236
|
+
}, async (c) => {
|
|
237
|
+
const body = ForkEnvironmentRequestSchema.parse(await readJson(c.req.raw));
|
|
238
|
+
const answer = await forkEnvironment(c.env.tenant, idOf(c.req.param("environmentId")), body, c.get("scope"));
|
|
239
|
+
return jsonResponse("dryRun" in answer ? 200 : 201, answer);
|
|
240
|
+
});
|
|
196
241
|
tenantRoute(api, READ, {
|
|
197
242
|
method: "get",
|
|
198
243
|
path: "/v1/environments/{environmentId}/versions",
|
|
@@ -250,10 +295,13 @@ export function environmentRoutes(api) {
|
|
|
250
295
|
path: "/v1/environments/{environmentId}/secrets/{name}",
|
|
251
296
|
tags: ["Environments"],
|
|
252
297
|
summary: "Write an Environment's secret",
|
|
253
|
-
description: "Creates or replaces one credential of the Environment's vault: an `environment_secret` (the variable `name` reads the sentinel `nylorun-managed` in the sandbox, and egress-gate sets the value as a header on requests to `allowedHosts`), an `environment_variable` (a plain variable), or a `bearer` token or `headers` map for the MCP servers and HTTP tools at `url`. The same name and type re-seals the value and binding; another type replaces it. A rotated value is used from the next request. A second credential for a host or a URL is `409 credential_conflict`.",
|
|
298
|
+
description: "Creates or replaces one credential of the Environment's vault: an `environment_secret` (the variable `name` reads the sentinel `nylorun-managed` in the sandbox, and egress-gate sets the value as a header on requests to `allowedHosts`), an `environment_variable` (a plain variable), or a `bearer` token or `headers` map for the MCP servers and HTTP tools at `url`. The same name and type re-seals the value and binding; another type replaces it. A rotated value is used from the next request. A second credential for a host or a URL is `409 credential_conflict`. When what the Environment runs declares secret slots (protocol 14, D64), send only the value (`{ value }`, or `{ headers }` for a `headers` slot): the type and binding come from the slot, and a name it does not declare is `409 secret_not_in_manifest`.",
|
|
254
299
|
request: {
|
|
255
300
|
params: secretPath,
|
|
256
|
-
body: {
|
|
301
|
+
body: {
|
|
302
|
+
required: true,
|
|
303
|
+
content: { "application/json": { schema: z.union([PutEnvironmentSecretRequest, PutEnvironmentSecretValueRequest]) } },
|
|
304
|
+
},
|
|
257
305
|
},
|
|
258
306
|
responses: {
|
|
259
307
|
200: json(EnvironmentSecretView, "The secret, without its value"),
|
|
@@ -263,8 +311,9 @@ export function environmentRoutes(api) {
|
|
|
263
311
|
const id = idOf(c.req.param("environmentId"));
|
|
264
312
|
const scope = c.get("scope");
|
|
265
313
|
assertReaches(scope, id);
|
|
266
|
-
const
|
|
267
|
-
|
|
314
|
+
const name = c.req.param("name") ?? "";
|
|
315
|
+
const body = await secretRequestFor(c.env.tenant, id, name, await readJson(c.req.raw));
|
|
316
|
+
return jsonResponse(200, await c.env.tenant.keys.putEnvironmentSecret(id, name, body, actorOf(scope)));
|
|
268
317
|
});
|
|
269
318
|
tenantRoute(api, WRITE, {
|
|
270
319
|
method: "delete",
|
|
@@ -44,7 +44,7 @@ export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], sc
|
|
|
44
44
|
id: string;
|
|
45
45
|
kind: "none" | "pod" | "virtual";
|
|
46
46
|
labels: Record<string, string>;
|
|
47
|
-
|
|
47
|
+
manifest: {
|
|
48
48
|
image?: string | undefined;
|
|
49
49
|
resources?: {
|
|
50
50
|
cpus: number;
|
|
@@ -64,12 +64,60 @@ export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], sc
|
|
|
64
64
|
cwd?: string | undefined;
|
|
65
65
|
timeout?: string | undefined;
|
|
66
66
|
}[] | undefined;
|
|
67
|
-
files?: {
|
|
67
|
+
files?: ({
|
|
68
68
|
artifactId: string;
|
|
69
69
|
version: number;
|
|
70
70
|
path: string;
|
|
71
|
-
}
|
|
71
|
+
} | {
|
|
72
|
+
path: string;
|
|
73
|
+
files: Record<string, string>;
|
|
74
|
+
})[] | undefined;
|
|
75
|
+
secrets?: Record<string, {
|
|
76
|
+
required?: boolean | undefined;
|
|
77
|
+
description?: string | undefined;
|
|
78
|
+
type: "environment_secret";
|
|
79
|
+
allowedHosts: string[];
|
|
80
|
+
inject?: {
|
|
81
|
+
header: string;
|
|
82
|
+
format: string;
|
|
83
|
+
} | undefined;
|
|
84
|
+
} | {
|
|
85
|
+
required?: boolean | undefined;
|
|
86
|
+
description?: string | undefined;
|
|
87
|
+
type: "environment_variable";
|
|
88
|
+
} | {
|
|
89
|
+
via?: string | undefined;
|
|
90
|
+
identity?: {
|
|
91
|
+
header: string;
|
|
92
|
+
} | undefined;
|
|
93
|
+
required?: boolean | undefined;
|
|
94
|
+
description?: string | undefined;
|
|
95
|
+
type: "bearer";
|
|
96
|
+
url: string;
|
|
97
|
+
} | {
|
|
98
|
+
via?: string | undefined;
|
|
99
|
+
identity?: {
|
|
100
|
+
header: string;
|
|
101
|
+
} | undefined;
|
|
102
|
+
required?: boolean | undefined;
|
|
103
|
+
description?: string | undefined;
|
|
104
|
+
type: "headers";
|
|
105
|
+
url: string;
|
|
106
|
+
}> | undefined;
|
|
72
107
|
};
|
|
108
|
+
manifestName?: string | undefined;
|
|
109
|
+
manifestVersion?: number | undefined;
|
|
110
|
+
manifestHash?: string | undefined;
|
|
111
|
+
forkedFrom?: {
|
|
112
|
+
environment: string;
|
|
113
|
+
disk: number | null;
|
|
114
|
+
} | undefined;
|
|
115
|
+
slots?: {
|
|
116
|
+
name: string;
|
|
117
|
+
type: string;
|
|
118
|
+
required: boolean;
|
|
119
|
+
set: boolean;
|
|
120
|
+
}[] | undefined;
|
|
73
121
|
version: number;
|
|
74
122
|
appliedVersion: number;
|
|
75
123
|
ownerUserId: string | null;
|
|
@@ -80,6 +128,7 @@ export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], sc
|
|
|
80
128
|
volumeGeneration: number;
|
|
81
129
|
hostEpoch: number;
|
|
82
130
|
reason?: string | undefined;
|
|
131
|
+
imageDigest?: string | undefined;
|
|
83
132
|
} | undefined;
|
|
84
133
|
lastUsedAt: string;
|
|
85
134
|
disk?: {
|
|
@@ -57,6 +57,9 @@ export function sessionRoutes(api) {
|
|
|
57
57
|
responses: {
|
|
58
58
|
200: json(AcceptedResponse, "The command, accepted"),
|
|
59
59
|
409: { description: "A turn is running, or the session does not wait on this" },
|
|
60
|
+
422: {
|
|
61
|
+
description: "A message names a file the Tenant's model does not read (`attachment_unsupported`; `details.parts` lists each with its reason). No turn starts.",
|
|
62
|
+
},
|
|
60
63
|
},
|
|
61
64
|
}, async (c) => {
|
|
62
65
|
// A `traceparent` joins the turn to the caller's trace (R7.4); a malformed one is ignored.
|
|
@@ -87,10 +90,17 @@ export function sessionRoutes(api) {
|
|
|
87
90
|
path: "/v1/agents/{agentId}",
|
|
88
91
|
tags: ["Agents"],
|
|
89
92
|
summary: "Put an agent's definition",
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
description: "Saves the agent's definition. With `?dryRun=true` (protocol 14) every check runs and nothing is saved: the answer says what a save would record.",
|
|
94
|
+
request: {
|
|
95
|
+
params: z.object({ agentId: z.string() }),
|
|
96
|
+
query: z.object({
|
|
97
|
+
dryRun: z.enum(["true", "false"]).optional().meta({ description: "`true`: check and save nothing" }),
|
|
98
|
+
}),
|
|
99
|
+
body: body(PutAgentRequest),
|
|
100
|
+
},
|
|
101
|
+
responses: { 200: json(PutAgentResponse, "The definition, stored (or checked, with dryRun)") },
|
|
92
102
|
}, async (c) => {
|
|
93
|
-
return jsonResponse(200, await putDefinition(c.env.tenant, c.req.param("agentId"), PutAgentRequestSchema.parse(await readJson(c.req.raw))));
|
|
103
|
+
return jsonResponse(200, await putDefinition(c.env.tenant, c.req.param("agentId"), PutAgentRequestSchema.parse(await readJson(c.req.raw)), { dryRun: c.req.query("dryRun") === "true" }));
|
|
94
104
|
});
|
|
95
105
|
tenantRoute(api, OWN_SESSIONS, {
|
|
96
106
|
method: "get",
|