@stigmer/server 3.22.1 → 3.23.1-dev.20260923075205
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/dist/artifactstorage/artifact-storage.d.ts +29 -31
- package/dist/artifactstorage/artifact-storage.d.ts.map +1 -1
- package/dist/artifactstorage/artifact-storage.js +5 -7
- package/dist/artifactstorage/artifact-storage.js.map +1 -1
- package/dist/artifactstorage/r2-storage.d.ts +12 -7
- package/dist/artifactstorage/r2-storage.d.ts.map +1 -1
- package/dist/artifactstorage/r2-storage.js +6 -14
- package/dist/artifactstorage/r2-storage.js.map +1 -1
- package/dist/authorization/authorizer.d.ts +4 -8
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +5 -9
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/derived-tuples.d.ts.map +1 -1
- package/dist/authorization/derived-tuples.js +10 -25
- package/dist/authorization/derived-tuples.js.map +1 -1
- package/dist/authorization/evaluator.d.ts +7 -8
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js +4 -20
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +5 -9
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/agent.d.ts.map +1 -1
- package/dist/authorization/model/agent.js +4 -5
- package/dist/authorization/model/agent.js.map +1 -1
- package/dist/authorization/model/agent_instance.d.ts.map +1 -1
- package/dist/authorization/model/agent_instance.js +2 -2
- package/dist/authorization/model/agent_instance.js.map +1 -1
- package/dist/authorization/model/mcp_server.d.ts.map +1 -1
- package/dist/authorization/model/mcp_server.js +2 -2
- package/dist/authorization/model/mcp_server.js.map +1 -1
- package/dist/authorization/model/plugin.d.ts.map +1 -1
- package/dist/authorization/model/plugin.js +3 -4
- package/dist/authorization/model/plugin.js.map +1 -1
- package/dist/authorization/model/rewrite.d.ts +8 -10
- package/dist/authorization/model/rewrite.d.ts.map +1 -1
- package/dist/authorization/model/rewrite.js +0 -3
- package/dist/authorization/model/rewrite.js.map +1 -1
- package/dist/authorization/model/skill.d.ts.map +1 -1
- package/dist/authorization/model/skill.js +2 -2
- package/dist/authorization/model/skill.js.map +1 -1
- package/dist/authorization/model/workflow.d.ts.map +1 -1
- package/dist/authorization/model/workflow.js +2 -2
- package/dist/authorization/model/workflow.js.map +1 -1
- package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
- package/dist/authorization/model/workflow_instance.js +2 -2
- package/dist/authorization/model/workflow_instance.js.map +1 -1
- package/dist/authorization/organization-directory.d.ts.map +1 -1
- package/dist/authorization/organization-directory.js +2 -3
- package/dist/authorization/organization-directory.js.map +1 -1
- package/dist/authorization/store-test-kit.d.ts +0 -6
- package/dist/authorization/store-test-kit.d.ts.map +1 -1
- package/dist/authorization/store-test-kit.js +16 -62
- package/dist/authorization/store-test-kit.js.map +1 -1
- package/dist/authorization/tuples.d.ts +13 -32
- package/dist/authorization/tuples.d.ts.map +1 -1
- package/dist/authorization/tuples.js +3 -11
- package/dist/authorization/tuples.js.map +1 -1
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +49 -24
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/config.d.ts +4 -3
- package/dist/boot/config.d.ts.map +1 -1
- package/dist/boot/config.js.map +1 -1
- package/dist/boot/skill-transfer-origin.d.ts +52 -0
- package/dist/boot/skill-transfer-origin.d.ts.map +1 -0
- package/dist/boot/skill-transfer-origin.js +54 -0
- package/dist/boot/skill-transfer-origin.js.map +1 -0
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +4 -4
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/agentchannel/controller.d.ts.map +1 -1
- package/dist/domain/agentchannel/controller.js +3 -1
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +3 -1
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +3 -4
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentshare/constants.d.ts +6 -11
- package/dist/domain/agentshare/constants.d.ts.map +1 -1
- package/dist/domain/agentshare/constants.js +8 -16
- package/dist/domain/agentshare/constants.js.map +1 -1
- package/dist/domain/agentshare/controller.d.ts.map +1 -1
- package/dist/domain/agentshare/controller.js +3 -1
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +18 -25
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +41 -142
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +2 -3
- package/dist/domain/environment/controller.js.map +1 -1
- package/dist/domain/executioncontext/controller.d.ts.map +1 -1
- package/dist/domain/executioncontext/controller.js +2 -1
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +3 -4
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts +3 -7
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +9 -11
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/plugin/push.d.ts +7 -5
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +8 -14
- package/dist/domain/plugin/push.js.map +1 -1
- package/dist/domain/schedule/controller.d.ts.map +1 -1
- package/dist/domain/schedule/controller.js +3 -1
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/session/controller.d.ts.map +1 -1
- package/dist/domain/session/controller.js +3 -2
- package/dist/domain/session/controller.js.map +1 -1
- package/dist/domain/skill/constants.d.ts +26 -3
- package/dist/domain/skill/constants.d.ts.map +1 -1
- package/dist/domain/skill/constants.js +26 -3
- package/dist/domain/skill/constants.js.map +1 -1
- package/dist/domain/skill/controller.d.ts +6 -11
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +33 -24
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/skill/push.d.ts +2 -2
- package/dist/domain/skill/push.d.ts.map +1 -1
- package/dist/domain/skill/push.js +2 -2
- package/dist/domain/skill/push.js.map +1 -1
- package/dist/domain/skill/transfer/handler.d.ts +17 -9
- package/dist/domain/skill/transfer/handler.d.ts.map +1 -1
- package/dist/domain/skill/transfer/handler.js +19 -8
- package/dist/domain/skill/transfer/handler.js.map +1 -1
- package/dist/domain/skill/transfer/slots.d.ts +26 -41
- package/dist/domain/skill/transfer/slots.d.ts.map +1 -1
- package/dist/domain/skill/transfer/slots.js +80 -87
- package/dist/domain/skill/transfer/slots.js.map +1 -1
- package/dist/domain/skill/transfer/staging.d.ts +48 -0
- package/dist/domain/skill/transfer/staging.d.ts.map +1 -0
- package/dist/domain/skill/transfer/staging.js +127 -0
- package/dist/domain/skill/transfer/staging.js.map +1 -0
- package/dist/domain/workflow/agent-call-references.d.ts +54 -0
- package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
- package/dist/domain/workflow/agent-call-references.js +97 -0
- package/dist/domain/workflow/agent-call-references.js.map +1 -0
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +14 -6
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
- package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +4 -2
- package/dist/domain/workflowexecution/controller.js.map +1 -1
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +3 -4
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/extensions/authorization-queries.d.ts +6 -5
- package/dist/extensions/authorization-queries.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +1 -1
- package/dist/extensions/resource-authorization.d.ts +3 -2
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +12 -3
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +21 -10
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +9 -11
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/references.d.ts +178 -20
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +344 -43
- package/dist/pipeline/steps/references.js.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
- package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
- package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
- package/dist/query/search/controller.js +0 -1
- package/dist/query/search/controller.js.map +1 -1
- package/dist/query/search/criteria.d.ts +1 -5
- package/dist/query/search/criteria.d.ts.map +1 -1
- package/dist/query/search/criteria.js +3 -13
- package/dist/query/search/criteria.js.map +1 -1
- package/dist/query/search/handler.d.ts +5 -4
- package/dist/query/search/handler.d.ts.map +1 -1
- package/dist/query/search/handler.js +7 -6
- package/dist/query/search/handler.js.map +1 -1
- package/dist/query/search/query-store.d.ts.map +1 -1
- package/dist/query/search/query-store.js +0 -2
- package/dist/query/search/query-store.js.map +1 -1
- package/dist/store/interface.d.ts +3 -6
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +3 -1
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +35 -1
- package/dist/store/postgres/migrations.js.map +1 -1
- package/dist/store/postgres/store.d.ts.map +1 -1
- package/dist/store/postgres/store.js +4 -9
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/public-visibility-retired.d.ts +67 -0
- package/dist/store/public-visibility-retired.d.ts.map +1 -0
- package/dist/store/public-visibility-retired.js +55 -0
- package/dist/store/public-visibility-retired.js.map +1 -0
- package/dist/store/sqlite/migrations.d.ts +3 -1
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +36 -1
- package/dist/store/sqlite/migrations.js.map +1 -1
- package/dist/store/sqlite/store.d.ts.map +1 -1
- package/dist/store/sqlite/store.js +4 -8
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
- package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
- package/src/artifactstorage/artifact-storage.ts +37 -33
- package/src/artifactstorage/r2-storage.ts +6 -15
- package/src/authorization/README.md +24 -26
- package/src/authorization/__tests__/authorizer.test.ts +10 -9
- package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
- package/src/authorization/__tests__/evaluator.test.ts +14 -73
- package/src/authorization/__tests__/facts.test.ts +2 -2
- package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +19 -27
- package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
- package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
- package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +1 -15
- package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
- package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
- package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
- package/src/authorization/__tests__/list-read-scope.test.ts +18 -17
- package/src/authorization/__tests__/store-tests.test.ts +2 -6
- package/src/authorization/__tests__/tuples.test.ts +12 -11
- package/src/authorization/authorizer.ts +4 -9
- package/src/authorization/derived-tuples.ts +14 -31
- package/src/authorization/evaluator.ts +8 -44
- package/src/authorization/list-read-scope.ts +5 -11
- package/src/authorization/model/agent.ts +2 -5
- package/src/authorization/model/agent_instance.ts +0 -2
- package/src/authorization/model/mcp_server.ts +0 -2
- package/src/authorization/model/plugin.ts +1 -4
- package/src/authorization/model/rewrite.ts +8 -13
- package/src/authorization/model/skill.ts +0 -2
- package/src/authorization/model/workflow.ts +0 -2
- package/src/authorization/model/workflow_instance.ts +0 -2
- package/src/authorization/organization-directory.ts +1 -3
- package/src/authorization/store-test-kit.ts +16 -75
- package/src/authorization/tuples.ts +16 -39
- package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
- package/src/boot/compose.ts +62 -25
- package/src/boot/config.ts +4 -3
- package/src/boot/skill-transfer-origin.ts +76 -0
- package/src/domain/agent/__tests__/agent.test.ts +11 -4
- package/src/domain/agent/controller.ts +7 -7
- package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
- package/src/domain/agentchannel/controller.ts +6 -1
- package/src/domain/agentexecution/controller.ts +6 -1
- package/src/domain/agentinstance/controller.ts +6 -12
- package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +16 -31
- package/src/domain/agentshare/constants.ts +14 -26
- package/src/domain/agentshare/controller.ts +6 -1
- package/src/domain/agentshare/steps.ts +41 -194
- package/src/domain/environment/controller.ts +5 -8
- package/src/domain/executioncontext/controller.ts +5 -1
- package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
- package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
- package/src/domain/mcpserver/controller.ts +6 -12
- package/src/domain/plugin/controller.ts +16 -25
- package/src/domain/plugin/push.ts +8 -16
- package/src/domain/schedule/controller.ts +6 -1
- package/src/domain/session/controller.ts +12 -4
- package/src/domain/skill/__tests__/skill.test.ts +5 -3
- package/src/domain/skill/__tests__/slots.test.ts +113 -60
- package/src/domain/skill/__tests__/staging.test.ts +304 -0
- package/src/domain/skill/constants.ts +28 -3
- package/src/domain/skill/controller.ts +44 -42
- package/src/domain/skill/push.ts +3 -3
- package/src/domain/skill/transfer/handler.ts +33 -15
- package/src/domain/skill/transfer/slots.ts +89 -100
- package/src/domain/skill/transfer/staging.ts +191 -0
- package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
- package/src/domain/workflow/agent-call-references.ts +157 -0
- package/src/domain/workflow/controller.ts +28 -10
- package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
- package/src/domain/workflowexecution/controller.ts +7 -2
- package/src/domain/workflowinstance/controller.ts +6 -12
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
- package/src/extensions/__tests__/extension-composition.test.ts +4 -4
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +9 -6
- package/src/extensions/authorization-queries.ts +6 -5
- package/src/extensions/list-read-scope.ts +1 -1
- package/src/extensions/resource-authorization.ts +3 -5
- package/src/index.ts +0 -1
- package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
- package/src/pipeline/apiresource-meta.ts +21 -10
- package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
- package/src/pipeline/steps/__tests__/references.test.ts +703 -0
- package/src/pipeline/steps/authorization-tuples.ts +9 -11
- package/src/pipeline/steps/references.ts +578 -70
- package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
- package/src/query/search/__tests__/criteria.test.ts +0 -4
- package/src/query/search/__tests__/query-store.test.ts +11 -40
- package/src/query/search/controller.ts +0 -1
- package/src/query/search/criteria.ts +0 -14
- package/src/query/search/handler.ts +6 -7
- package/src/query/search/query-store.ts +0 -2
- package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
- package/src/store/__tests__/store-contract.ts +6 -51
- package/src/store/interface.ts +3 -6
- package/src/store/postgres/__tests__/migrations.test.ts +187 -6
- package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
- package/src/store/postgres/migrations.ts +48 -1
- package/src/store/postgres/store.ts +4 -11
- package/src/store/public-visibility-retired.ts +119 -0
- package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
- package/src/store/sqlite/migrations.ts +45 -1
- package/src/store/sqlite/store.ts +4 -10
- package/src/transport/registry/__tests__/lanes.test.ts +1 -1
- package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
- package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
- package/dist/pipeline/steps/visibility-gates.js +0 -139
- package/dist/pipeline/steps/visibility-gates.js.map +0 -1
- package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
- package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
- package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
- package/src/pipeline/steps/visibility-gates.ts +0 -174
|
@@ -2,6 +2,7 @@ import { SKILL_ARTIFACTS_PATH_PREFIX } from "../../../transport/constants.js";
|
|
|
2
2
|
import { DOWNLOAD_KEY_PREFIX, UPLOADS_SEGMENT } from "../constants.js";
|
|
3
3
|
import { ArtifactNotFoundError } from "../storage/artifact-storage.js";
|
|
4
4
|
import { SizeMismatchError, SlotConsumedError, SlotUnknownError, } from "./slots.js";
|
|
5
|
+
import { stagingKeyOf } from "./staging.js";
|
|
5
6
|
/**
|
|
6
7
|
* Renders the capability URL for a minted reference against the lane's
|
|
7
8
|
* externally-reachable base URL.
|
|
@@ -9,9 +10,13 @@ import { SizeMismatchError, SlotConsumedError, SlotUnknownError, } from "./slots
|
|
|
9
10
|
export function uploadUrl(baseUrl, ref) {
|
|
10
11
|
return `${trimTrailingSlash(baseUrl)}${SKILL_ARTIFACTS_PATH_PREFIX}${UPLOADS_SEGMENT}${ref}`;
|
|
11
12
|
}
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The lane's download origin: the local skill driver's serve URL, so that
|
|
15
|
+
* `${serveUrl}/${storageKey}` (LocalArtifactStorage.getSignedUrl's shape)
|
|
16
|
+
* is exactly the GET route this handler dispatches.
|
|
17
|
+
*/
|
|
18
|
+
export function transferServeUrl(baseUrl) {
|
|
19
|
+
return `${trimTrailingSlash(baseUrl)}${SKILL_ARTIFACTS_PATH_PREFIX}`;
|
|
15
20
|
}
|
|
16
21
|
function trimTrailingSlash(url) {
|
|
17
22
|
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
@@ -51,17 +56,23 @@ async function handleUpload(request, response, slots, ref, logger) {
|
|
|
51
56
|
writeText(response, 405, "method not allowed");
|
|
52
57
|
return;
|
|
53
58
|
}
|
|
59
|
+
// Deliberately one shape for "malformed", "never existed" and "expired":
|
|
60
|
+
// distinguishing them would let an unauthorized caller probe which
|
|
61
|
+
// tokens were once valid.
|
|
62
|
+
const unknown = () => writeText(response, 404, "upload reference unknown or expired — request a new upload URL");
|
|
63
|
+
const key = stagingKeyOf(ref);
|
|
64
|
+
if (key === undefined) {
|
|
65
|
+
unknown();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
54
68
|
try {
|
|
55
|
-
await slots.receive(
|
|
69
|
+
await slots.receive(key, request);
|
|
56
70
|
response.statusCode = 204;
|
|
57
71
|
response.end();
|
|
58
72
|
}
|
|
59
73
|
catch (error) {
|
|
60
74
|
if (error instanceof SlotUnknownError) {
|
|
61
|
-
|
|
62
|
-
// distinguishing them would let an unauthorized caller probe which
|
|
63
|
-
// tokens were once valid.
|
|
64
|
-
writeText(response, 404, "upload reference unknown or expired — request a new upload URL");
|
|
75
|
+
unknown();
|
|
65
76
|
}
|
|
66
77
|
else if (error instanceof SlotConsumedError) {
|
|
67
78
|
writeText(response, 409, "upload reference already used — request a new upload URL");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,72 +7,57 @@ export declare class SlotUnknownError extends Error {
|
|
|
7
7
|
export declare class SlotConsumedError extends Error {
|
|
8
8
|
constructor();
|
|
9
9
|
}
|
|
10
|
-
/** Go
|
|
11
|
-
export declare class SlotEmptyError extends Error {
|
|
12
|
-
constructor();
|
|
13
|
-
}
|
|
14
|
-
/** Go errSizeMismatch — the body disagreed with the minted declaration. */
|
|
10
|
+
/** Go errSizeMismatch — the body disagreed with the reserved declaration. */
|
|
15
11
|
export declare class SizeMismatchError extends Error {
|
|
16
12
|
constructor(received: number, declared: number);
|
|
17
13
|
}
|
|
18
14
|
export declare class UploadSlots {
|
|
19
|
-
private readonly
|
|
20
|
-
private readonly
|
|
15
|
+
private readonly root;
|
|
16
|
+
private readonly stagingPrefix;
|
|
21
17
|
private readonly ttlMs;
|
|
22
18
|
private readonly maxSize;
|
|
19
|
+
private readonly slots;
|
|
20
|
+
private readonly stagingDir;
|
|
23
21
|
/** Injectable for expiry tests, mirroring Go's `now` field. */
|
|
24
22
|
private readonly now;
|
|
25
23
|
/**
|
|
26
|
-
* Creates the registry
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* never reached their
|
|
24
|
+
* Creates the registry over `root` (the local blob driver's root) and
|
|
25
|
+
* prepares the staging directory `root/stagingPrefix`. Any file already
|
|
26
|
+
* present is an orphan from a previous process (the registry that knew
|
|
27
|
+
* about it died with that process), so the directory is emptied — this
|
|
28
|
+
* is also the crash-recovery story for uploads that never reached their
|
|
29
|
+
* push.
|
|
31
30
|
*/
|
|
32
|
-
constructor(
|
|
31
|
+
constructor(root: string, stagingPrefix: string, ttlMs: number, maxSize: number, now?: () => number);
|
|
33
32
|
/**
|
|
34
|
-
* Reserves an upload slot for an artifact of declaredSize bytes
|
|
35
|
-
*
|
|
33
|
+
* Reserves an upload slot for an artifact of declaredSize bytes at the
|
|
34
|
+
* staging key; returns the TTL granted. The caller has already
|
|
36
35
|
* authorized the request and validated declaredSize against the skill
|
|
37
|
-
* size limit;
|
|
36
|
+
* size limit; the bound here is the registry's own invariant.
|
|
38
37
|
*/
|
|
39
|
-
|
|
40
|
-
ref: string;
|
|
38
|
+
reserve(key: string, declaredSize: number): {
|
|
41
39
|
ttlMs: number;
|
|
42
40
|
};
|
|
43
41
|
/**
|
|
44
42
|
* Streams an upload's body into the slot's staging file. The body must
|
|
45
|
-
* match the size declared at
|
|
43
|
+
* match the size declared at reservation exactly: a shorter body means a
|
|
46
44
|
* truncated transfer, a longer one means the client lied — both reject
|
|
47
45
|
* rather than staging bytes that would fail (or worse, surprise)
|
|
48
|
-
* validation later. The staged file only becomes
|
|
49
|
-
* resolves.
|
|
50
|
-
*/
|
|
51
|
-
receive(ref: string, body: Readable): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Returns the staged bytes for ref and retires the slot — an upload
|
|
54
|
-
* reference is strictly single-use. Push calls this when it sees
|
|
55
|
-
* artifact_upload_ref; whatever happens downstream (validation failure
|
|
56
|
-
* included), the slot is gone and the client must re-mint to retry.
|
|
46
|
+
* validation later. The staged file only becomes readable through the
|
|
47
|
+
* driver once this resolves.
|
|
57
48
|
*/
|
|
58
|
-
|
|
49
|
+
receive(key: string, body: Readable): Promise<void>;
|
|
59
50
|
/**
|
|
60
|
-
* Drops expired slots and their staged files. Called from
|
|
61
|
-
* bounds the registry: it can hold at most the slots
|
|
51
|
+
* Drops expired slots and their staged files. Called from reserve, which
|
|
52
|
+
* bounds the registry: it can hold at most the slots reserved within one
|
|
62
53
|
* TTL window.
|
|
63
54
|
*/
|
|
64
55
|
private sweep;
|
|
65
56
|
/**
|
|
66
|
-
*
|
|
67
|
-
* driver's
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* with nothing to catch it.
|
|
71
|
-
*/
|
|
72
|
-
stagedFileName(ref: string): string;
|
|
73
|
-
/**
|
|
74
|
-
* Maps a reference to its staging file. refs are server-generated hex
|
|
75
|
-
* (never client-supplied paths), so simple joining is safe.
|
|
57
|
+
* Maps a staging key to its file: the key resolved under the driver's
|
|
58
|
+
* root, which is how the driver's download(key) will look for it. The
|
|
59
|
+
* key must carry the staging prefix and a plain hex file name — anything
|
|
60
|
+
* else is a caller bug, refused before it touches the filesystem.
|
|
76
61
|
*/
|
|
77
62
|
private stagePath;
|
|
78
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/slots.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/slots.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,4DAA4D;AAC5D,qBAAa,gBAAiB,SAAQ,KAAK;;CAK1C;AAED,+DAA+D;AAC/D,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAM/C;AAgBD,qBAAa,WAAW;IAepB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC;;;;;;;OAOG;gBAEgB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAChC,GAAG,GAAE,MAAM,MAAiB;IAQ9B;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;IAmB7D;;;;;;;OAOG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDzD;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAUb;;;;;OAKG;IACH,OAAO,CAAC,SAAS;CAUlB"}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Skill artifact upload slots —
|
|
3
|
-
*
|
|
4
|
-
* staging
|
|
2
|
+
* Skill artifact upload slots — the local blob driver's staging mechanism,
|
|
3
|
+
* ported from pkg/domain/skill/transfer/slots.go: an in-memory registry of
|
|
4
|
+
* single-use upload capabilities plus the staging files their bytes land
|
|
5
|
+
* in (#675).
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
+
* A slot is keyed by the STAGING KEY the domain names (`skills/staging/
|
|
8
|
+
* <hex>.zip`, transfer/staging.ts), and its file is that key resolved
|
|
9
|
+
* under the blob driver's root — so the driver's own download(key) reads
|
|
10
|
+
* what the lane received and its delete(key) retires the bytes, exactly
|
|
11
|
+
* as a bucket driver's would. The registry therefore knows nothing of
|
|
12
|
+
* consumption: it reserves, receives, and sweeps; the domain reads and
|
|
13
|
+
* deletes through the driver, one path for every backend.
|
|
14
|
+
*
|
|
15
|
+
* In-memory is deliberate: the local driver is single-instance (the same
|
|
7
16
|
* assumption the in-process router transport and SQLite store already
|
|
8
17
|
* make), and a slot is worthless across restarts anyway — its bytes live
|
|
9
18
|
* in the staging directory, which is swept on boot.
|
|
@@ -11,17 +20,14 @@
|
|
|
11
20
|
* Sentinel error classes replace Go's sentinel error values so the HTTP
|
|
12
21
|
* handler maps registry failures onto honest status codes without string
|
|
13
22
|
* matching; their message texts are Go's, verbatim (they ride wire-visible
|
|
14
|
-
* copy:
|
|
15
|
-
* body).
|
|
23
|
+
* copy: the handler's 404, 409 and 400 bodies).
|
|
16
24
|
*
|
|
17
25
|
* Proven by __tests__/slots.test.ts (injected clock for expiry) and the
|
|
18
26
|
* conformance suite's transfer-lane tests.
|
|
19
27
|
*/
|
|
20
|
-
import { randomBytes } from "node:crypto";
|
|
21
28
|
import fs from "node:fs";
|
|
22
29
|
import path from "node:path";
|
|
23
30
|
import { pipeline } from "node:stream/promises";
|
|
24
|
-
import { REF_BYTE_LEN, REF_PREFIX } from "../constants.js";
|
|
25
31
|
/** Go errSlotUnknown — never existed, expired, or swept. */
|
|
26
32
|
export class SlotUnknownError extends Error {
|
|
27
33
|
constructor() {
|
|
@@ -36,71 +42,79 @@ export class SlotConsumedError extends Error {
|
|
|
36
42
|
this.name = "SlotConsumedError";
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
|
-
/** Go
|
|
40
|
-
export class SlotEmptyError extends Error {
|
|
41
|
-
constructor() {
|
|
42
|
-
super("upload reference has no uploaded bytes");
|
|
43
|
-
this.name = "SlotEmptyError";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
/** Go errSizeMismatch — the body disagreed with the minted declaration. */
|
|
45
|
+
/** Go errSizeMismatch — the body disagreed with the reserved declaration. */
|
|
47
46
|
export class SizeMismatchError extends Error {
|
|
48
47
|
constructor(received, declared) {
|
|
49
48
|
super(`upload size mismatch: received ${received} bytes, declared ${declared}`);
|
|
50
49
|
this.name = "SizeMismatchError";
|
|
51
50
|
}
|
|
52
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The one file-name shape a staging key may carry past its prefix: the
|
|
54
|
+
* domain's hex reference plus the archive suffix. Keys are server-minted,
|
|
55
|
+
* never client-supplied, so this is an invariant check, not input
|
|
56
|
+
* validation — a violation is a programming error and throws.
|
|
57
|
+
*/
|
|
58
|
+
const STAGED_FILE_NAME = /^[0-9a-f]+\.zip$/;
|
|
53
59
|
export class UploadSlots {
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
root;
|
|
61
|
+
stagingPrefix;
|
|
56
62
|
ttlMs;
|
|
57
63
|
maxSize;
|
|
64
|
+
slots = new Map();
|
|
65
|
+
stagingDir;
|
|
58
66
|
/** Injectable for expiry tests, mirroring Go's `now` field. */
|
|
59
67
|
now;
|
|
60
68
|
/**
|
|
61
|
-
* Creates the registry
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* never reached their
|
|
69
|
+
* Creates the registry over `root` (the local blob driver's root) and
|
|
70
|
+
* prepares the staging directory `root/stagingPrefix`. Any file already
|
|
71
|
+
* present is an orphan from a previous process (the registry that knew
|
|
72
|
+
* about it died with that process), so the directory is emptied — this
|
|
73
|
+
* is also the crash-recovery story for uploads that never reached their
|
|
74
|
+
* push.
|
|
66
75
|
*/
|
|
67
|
-
constructor(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.stagingDir = stagingDir;
|
|
76
|
+
constructor(root, stagingPrefix, ttlMs, maxSize, now = Date.now) {
|
|
77
|
+
this.root = root;
|
|
78
|
+
this.stagingPrefix = stagingPrefix;
|
|
71
79
|
this.ttlMs = ttlMs;
|
|
72
80
|
this.maxSize = maxSize;
|
|
81
|
+
this.stagingDir = path.join(root, stagingPrefix);
|
|
82
|
+
fs.rmSync(this.stagingDir, { recursive: true, force: true });
|
|
83
|
+
fs.mkdirSync(this.stagingDir, { recursive: true, mode: 0o700 });
|
|
73
84
|
this.now = now;
|
|
74
85
|
}
|
|
75
86
|
/**
|
|
76
|
-
* Reserves an upload slot for an artifact of declaredSize bytes
|
|
77
|
-
*
|
|
87
|
+
* Reserves an upload slot for an artifact of declaredSize bytes at the
|
|
88
|
+
* staging key; returns the TTL granted. The caller has already
|
|
78
89
|
* authorized the request and validated declaredSize against the skill
|
|
79
|
-
* size limit;
|
|
90
|
+
* size limit; the bound here is the registry's own invariant.
|
|
80
91
|
*/
|
|
81
|
-
|
|
92
|
+
reserve(key, declaredSize) {
|
|
82
93
|
if (declaredSize <= 0 || declaredSize > this.maxSize) {
|
|
83
94
|
throw new Error(`declared size ${declaredSize} outside (0, ${this.maxSize}]`);
|
|
84
95
|
}
|
|
85
|
-
|
|
96
|
+
this.stagePath(key);
|
|
97
|
+
if (this.slots.has(key)) {
|
|
98
|
+
throw new Error(`staging key ${key} is already reserved`);
|
|
99
|
+
}
|
|
86
100
|
this.sweep();
|
|
87
|
-
this.slots.set(
|
|
101
|
+
this.slots.set(key, {
|
|
88
102
|
declaredSize,
|
|
89
103
|
expiresAtMs: this.now() + this.ttlMs,
|
|
90
104
|
uploaded: false,
|
|
91
105
|
});
|
|
92
|
-
return {
|
|
106
|
+
return { ttlMs: this.ttlMs };
|
|
93
107
|
}
|
|
94
108
|
/**
|
|
95
109
|
* Streams an upload's body into the slot's staging file. The body must
|
|
96
|
-
* match the size declared at
|
|
110
|
+
* match the size declared at reservation exactly: a shorter body means a
|
|
97
111
|
* truncated transfer, a longer one means the client lied — both reject
|
|
98
112
|
* rather than staging bytes that would fail (or worse, surprise)
|
|
99
|
-
* validation later. The staged file only becomes
|
|
100
|
-
* resolves.
|
|
113
|
+
* validation later. The staged file only becomes readable through the
|
|
114
|
+
* driver once this resolves.
|
|
101
115
|
*/
|
|
102
|
-
async receive(
|
|
103
|
-
const slot = this.slots.get(
|
|
116
|
+
async receive(key, body) {
|
|
117
|
+
const slot = this.slots.get(key);
|
|
104
118
|
if (slot === undefined || this.now() > slot.expiresAtMs) {
|
|
105
119
|
throw new SlotUnknownError();
|
|
106
120
|
}
|
|
@@ -108,9 +122,16 @@ export class UploadSlots {
|
|
|
108
122
|
throw new SlotConsumedError();
|
|
109
123
|
}
|
|
110
124
|
const declared = slot.declaredSize;
|
|
111
|
-
const filePath = this.stagePath(
|
|
125
|
+
const filePath = this.stagePath(key);
|
|
112
126
|
let written = 0;
|
|
113
127
|
try {
|
|
128
|
+
// The driver's delete(key) prunes directories it empties, so the
|
|
129
|
+
// staging directory may be gone between two uploads; recreate it
|
|
130
|
+
// rather than fail the second one.
|
|
131
|
+
await fs.promises.mkdir(path.dirname(filePath), {
|
|
132
|
+
recursive: true,
|
|
133
|
+
mode: 0o700,
|
|
134
|
+
});
|
|
114
135
|
// Consume at most declared+1 bytes: seeing the extra byte proves the
|
|
115
136
|
// body exceeds the declaration without buffering an unbounded stream
|
|
116
137
|
// (Go's io.LimitReader(declared+1) + written != declared check).
|
|
@@ -128,7 +149,7 @@ export class UploadSlots {
|
|
|
128
149
|
}
|
|
129
150
|
// Re-check after the write: the slot may have expired mid-upload
|
|
130
151
|
// (Go re-checks under the lock for the same reason).
|
|
131
|
-
const current = this.slots.get(
|
|
152
|
+
const current = this.slots.get(key);
|
|
132
153
|
if (current === undefined || this.now() > current.expiresAtMs) {
|
|
133
154
|
await fs.promises.rm(filePath, { force: true });
|
|
134
155
|
throw new SlotUnknownError();
|
|
@@ -136,62 +157,34 @@ export class UploadSlots {
|
|
|
136
157
|
current.uploaded = true;
|
|
137
158
|
}
|
|
138
159
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* artifact_upload_ref; whatever happens downstream (validation failure
|
|
142
|
-
* included), the slot is gone and the client must re-mint to retry.
|
|
143
|
-
*/
|
|
144
|
-
async consume(ref) {
|
|
145
|
-
const slot = this.slots.get(ref);
|
|
146
|
-
if (slot === undefined || this.now() > slot.expiresAtMs) {
|
|
147
|
-
throw new SlotUnknownError();
|
|
148
|
-
}
|
|
149
|
-
if (!slot.uploaded) {
|
|
150
|
-
throw new SlotEmptyError();
|
|
151
|
-
}
|
|
152
|
-
this.slots.delete(ref);
|
|
153
|
-
const filePath = this.stagePath(ref);
|
|
154
|
-
try {
|
|
155
|
-
const data = await fs.promises.readFile(filePath);
|
|
156
|
-
return data;
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
throw new Error(`failed to read staged artifact: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
-
}
|
|
161
|
-
finally {
|
|
162
|
-
await fs.promises.rm(filePath, { force: true });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Drops expired slots and their staged files. Called from mint, which
|
|
167
|
-
* bounds the registry: it can hold at most the slots minted within one
|
|
160
|
+
* Drops expired slots and their staged files. Called from reserve, which
|
|
161
|
+
* bounds the registry: it can hold at most the slots reserved within one
|
|
168
162
|
* TTL window.
|
|
169
163
|
*/
|
|
170
164
|
sweep() {
|
|
171
165
|
const nowMs = this.now();
|
|
172
|
-
for (const [
|
|
166
|
+
for (const [key, slot] of this.slots) {
|
|
173
167
|
if (nowMs > slot.expiresAtMs) {
|
|
174
|
-
this.slots.delete(
|
|
175
|
-
fs.rmSync(this.stagePath(
|
|
168
|
+
this.slots.delete(key);
|
|
169
|
+
fs.rmSync(this.stagePath(key), { force: true });
|
|
176
170
|
}
|
|
177
171
|
}
|
|
178
172
|
}
|
|
179
173
|
/**
|
|
180
|
-
*
|
|
181
|
-
* driver's
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* with nothing to catch it.
|
|
174
|
+
* Maps a staging key to its file: the key resolved under the driver's
|
|
175
|
+
* root, which is how the driver's download(key) will look for it. The
|
|
176
|
+
* key must carry the staging prefix and a plain hex file name — anything
|
|
177
|
+
* else is a caller bug, refused before it touches the filesystem.
|
|
185
178
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return path.join(this.
|
|
179
|
+
stagePath(key) {
|
|
180
|
+
if (!key.startsWith(this.stagingPrefix)) {
|
|
181
|
+
throw new Error(`staging key ${key} is outside ${this.stagingPrefix}`);
|
|
182
|
+
}
|
|
183
|
+
const fileName = key.slice(this.stagingPrefix.length);
|
|
184
|
+
if (!STAGED_FILE_NAME.test(fileName)) {
|
|
185
|
+
throw new Error(`staging key ${key} does not name a staged archive`);
|
|
186
|
+
}
|
|
187
|
+
return path.join(this.root, key);
|
|
195
188
|
}
|
|
196
189
|
}
|
|
197
190
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slots.js","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/slots.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"slots.js","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/slots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ArtifactStorage } from "../../../artifactstorage/artifact-storage.js";
|
|
2
|
+
import type { Logger } from "../../../boot/logger.js";
|
|
3
|
+
/** A fresh upload reference: the prefix and 128 random bits, hex. */
|
|
4
|
+
export declare function newUploadRef(): string;
|
|
5
|
+
/**
|
|
6
|
+
* The staging key a reference's bytes land under, or undefined when the
|
|
7
|
+
* reference is not one this server could have minted. Refs arrive from
|
|
8
|
+
* clients (the push request, the lane's URL path), so the shape is
|
|
9
|
+
* checked before it becomes a storage key.
|
|
10
|
+
*/
|
|
11
|
+
export declare function stagingKeyOf(ref: string): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The reference for a staging key this module minted. Keys reach here from
|
|
14
|
+
* the domain's own mint, never from a client, so a foreign shape is a
|
|
15
|
+
* programming error and throws.
|
|
16
|
+
*/
|
|
17
|
+
export declare function uploadRefOf(stagingKey: string): string;
|
|
18
|
+
/** What createArtifactUploadUrl hands the client. */
|
|
19
|
+
export interface StagedUpload {
|
|
20
|
+
/** The single-use reference the push presents. */
|
|
21
|
+
readonly ref: string;
|
|
22
|
+
/** Accepts one HTTP PUT of exactly the declared byte count. */
|
|
23
|
+
readonly url: string;
|
|
24
|
+
/** How long the reference and the URL stay valid. */
|
|
25
|
+
readonly ttlMs: number;
|
|
26
|
+
}
|
|
27
|
+
/** What getArtifactDownloadUrl hands the client. */
|
|
28
|
+
export interface DownloadCapability {
|
|
29
|
+
readonly url: string;
|
|
30
|
+
/** The floor of the URL's validity (DOWNLOAD_URL_TTL_MS). */
|
|
31
|
+
readonly ttlMs: number;
|
|
32
|
+
}
|
|
33
|
+
/** The staging port both archive kinds (skills, plugins) push through. */
|
|
34
|
+
export interface ArchiveStaging {
|
|
35
|
+
/** Mints a reference and the URL its bytes are PUT to. */
|
|
36
|
+
mint(declaredSizeBytes: number): Promise<StagedUpload>;
|
|
37
|
+
/**
|
|
38
|
+
* Reads the staged bytes for a reference and retires it. Throws
|
|
39
|
+
* SlotUnknownError when the driver holds nothing under the reference;
|
|
40
|
+
* any other failure is the driver's and propagates as an infrastructure
|
|
41
|
+
* fault.
|
|
42
|
+
*/
|
|
43
|
+
consume(ref: string): Promise<Uint8Array>;
|
|
44
|
+
/** A time-limited download URL for a stored archive key. */
|
|
45
|
+
downloadUrl(storageKey: string): Promise<DownloadCapability>;
|
|
46
|
+
}
|
|
47
|
+
export declare function newArchiveStaging(driver: ArtifactStorage, logger: Logger): ArchiveStaging;
|
|
48
|
+
//# sourceMappingURL=staging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../../../../src/domain/skill/transfer/staging.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAC;AAEpF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AA4BtD,qEAAqE;AACrE,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK5D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,oDAAoD;AACpD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvD;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,4DAA4D;IAC5D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC9D;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,GACb,cAAc,CA8DhB"}
|