@the-open-engine/zeroshot 6.29.0 → 6.30.0
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 +4 -0
- package/cli/index.js +2 -4
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +0 -1
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/agent-cli-provider/contract-actions.d.ts +1 -1
- package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -1
- package/lib/agent-cli-provider/contract-actions.js +5 -5
- package/lib/agent-cli-provider/contract-actions.js.map +1 -1
- package/lib/agent-cli-provider/contract-invoke.d.ts +1 -1
- package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -1
- package/lib/agent-cli-provider/contract-invoke.js +2 -2
- package/lib/agent-cli-provider/contract-invoke.js.map +1 -1
- package/lib/agent-cli-provider/contract-support.d.ts +1 -1
- package/lib/agent-cli-provider/contract-support.d.ts.map +1 -1
- package/lib/agent-cli-provider/contract-support.js +2 -2
- package/lib/agent-cli-provider/contract-support.js.map +1 -1
- package/lib/agent-cli-provider/contract.d.ts +1 -0
- package/lib/agent-cli-provider/contract.d.ts.map +1 -1
- package/lib/agent-cli-provider/contract.js +1 -1
- package/lib/agent-cli-provider/contract.js.map +1 -1
- package/lib/agent-cli-provider/index.d.ts +1 -1
- package/lib/agent-cli-provider/index.d.ts.map +1 -1
- package/lib/agent-cli-provider/index.js +2 -1
- package/lib/agent-cli-provider/index.js.map +1 -1
- package/lib/agent-cli-provider/provider-registry.d.ts +1 -0
- package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
- package/lib/agent-cli-provider/provider-registry.js +4 -0
- package/lib/agent-cli-provider/provider-registry.js.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.d.ts +3 -3
- package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.js +22 -48
- package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
- package/lib/cluster/client.cjs +30 -7
- package/lib/cluster/client.d.cts +52 -0
- package/lib/cluster/client.d.mts +52 -0
- package/lib/cluster/client.d.ts +4 -6
- package/lib/cluster/client.mjs +32 -9
- package/lib/cluster/connection-state.cjs +25 -0
- package/lib/cluster/connection-state.d.cts +13 -0
- package/lib/cluster/connection-state.d.mts +13 -0
- package/lib/cluster/connection-state.d.ts +13 -0
- package/lib/cluster/connection-state.mjs +21 -0
- package/lib/{target/hosted-run/contracts.js → cluster/connection-types.cjs} +0 -1
- package/lib/cluster/connection-types.d.cts +33 -0
- package/lib/cluster/connection-types.d.mts +33 -0
- package/lib/cluster/connection-types.d.ts +33 -0
- package/lib/cluster/connection-types.mjs +1 -0
- package/lib/cluster/connection.cjs +18 -46
- package/lib/cluster/connection.d.cts +26 -0
- package/lib/cluster/connection.d.mts +26 -0
- package/lib/cluster/connection.d.ts +7 -25
- package/lib/cluster/connection.mjs +12 -42
- package/lib/cluster/errors.cjs +9 -1
- package/lib/cluster/errors.d.cts +29 -0
- package/lib/cluster/errors.d.mts +29 -0
- package/lib/cluster/errors.d.ts +4 -0
- package/lib/cluster/errors.mjs +7 -0
- package/lib/cluster/frames.d.cts +12 -0
- package/lib/cluster/frames.d.mts +12 -0
- package/lib/cluster/generated/protocol-schema.d.cts +1 -0
- package/lib/cluster/generated/protocol-schema.d.mts +1 -0
- package/lib/cluster/generated/protocol.d.cts +781 -0
- package/lib/cluster/generated/protocol.d.mts +781 -0
- package/lib/cluster/index.cjs +2 -2
- package/lib/cluster/index.d.cts +13 -0
- package/lib/cluster/index.d.mts +13 -0
- package/lib/cluster/index.d.ts +3 -3
- package/lib/cluster/index.mjs +2 -2
- package/lib/cluster/json-source.cjs +1 -0
- package/lib/cluster/json-source.d.cts +5 -0
- package/lib/cluster/json-source.d.mts +5 -0
- package/lib/cluster/json-source.d.ts +1 -0
- package/lib/cluster/json-source.mjs +1 -0
- package/lib/cluster/payload-value.cjs +1 -0
- package/lib/cluster/payload-value.d.cts +8 -0
- package/lib/cluster/payload-value.d.mts +8 -0
- package/lib/cluster/payload-value.d.ts +1 -0
- package/lib/cluster/payload-value.mjs +1 -0
- package/lib/cluster/queue.d.cts +15 -0
- package/lib/cluster/queue.d.mts +15 -0
- package/lib/cluster/socket.cjs +8 -0
- package/lib/cluster/socket.d.cts +13 -0
- package/lib/cluster/socket.d.mts +13 -0
- package/lib/cluster/socket.d.ts +2 -0
- package/lib/cluster/socket.mjs +7 -0
- package/lib/cluster/subscriptions.d.cts +73 -0
- package/lib/cluster/subscriptions.d.mts +73 -0
- package/lib/cluster/subscriptions.d.ts +5 -1
- package/lib/cluster/validators.cjs +1 -0
- package/lib/cluster/validators.d.cts +7 -0
- package/lib/cluster/validators.d.mts +7 -0
- package/lib/cluster/validators.d.ts +1 -0
- package/lib/cluster/validators.mjs +1 -0
- package/lib/cluster-worker/engine-adapter-common.js +37 -0
- package/lib/cluster-worker/engine-adapter.js +24 -30
- package/lib/cluster-worker/engine-start.js +59 -0
- package/lib/cluster-worker/index.js +49 -67
- package/lib/cluster-worker/profiles.js +1 -42
- package/lib/cluster-worker/runtime-dependencies.js +49 -0
- package/lib/cluster-worker/runtime-support.js +2 -34
- package/lib/cluster-worker/terminal-normalizer.js +9 -10
- package/lib/hosted-session/authority.cjs +61 -0
- package/lib/hosted-session/authority.d.cts +3 -0
- package/lib/hosted-session/authority.d.mts +3 -0
- package/lib/hosted-session/authority.d.ts +3 -0
- package/lib/hosted-session/authority.mjs +57 -0
- package/lib/hosted-session/coordinator.cjs +78 -51
- package/lib/hosted-session/coordinator.d.cts +11 -0
- package/lib/hosted-session/coordinator.d.mts +11 -0
- package/lib/hosted-session/coordinator.d.ts +4 -2
- package/lib/hosted-session/coordinator.mjs +75 -51
- package/lib/hosted-session/errors.cjs +25 -0
- package/lib/hosted-session/errors.d.cts +10 -0
- package/lib/hosted-session/errors.d.mts +10 -0
- package/lib/hosted-session/errors.d.ts +10 -0
- package/lib/hosted-session/errors.mjs +19 -0
- package/lib/hosted-session/index.cjs +4 -1
- package/lib/hosted-session/index.d.cts +2 -0
- package/lib/hosted-session/index.d.mts +2 -0
- package/lib/hosted-session/index.d.ts +2 -2
- package/lib/hosted-session/index.mjs +1 -1
- package/lib/hosted-session/reconnecting-watch.cjs +131 -0
- package/lib/hosted-session/reconnecting-watch.d.cts +13 -0
- package/lib/hosted-session/reconnecting-watch.d.mts +13 -0
- package/lib/hosted-session/reconnecting-watch.d.ts +13 -0
- package/lib/hosted-session/reconnecting-watch.mjs +127 -0
- package/lib/hosted-session/types.d.cts +32 -0
- package/lib/hosted-session/types.d.mts +32 -0
- package/lib/hosted-session/types.d.ts +19 -7
- package/lib/hosted-target/access-url.cjs +44 -0
- package/lib/hosted-target/access-url.d.cts +2 -0
- package/lib/hosted-target/access-url.d.mts +2 -0
- package/lib/hosted-target/access-url.d.ts +2 -0
- package/lib/hosted-target/access-url.mjs +41 -0
- package/lib/hosted-target/adapter-request.cjs +12 -0
- package/lib/hosted-target/adapter-request.d.cts +17 -0
- package/lib/hosted-target/adapter-request.d.mts +17 -0
- package/lib/hosted-target/adapter-request.d.ts +17 -0
- package/lib/hosted-target/adapter-request.mjs +9 -0
- package/lib/hosted-target/adapter-types.cjs +2 -0
- package/lib/hosted-target/adapter-types.d.cts +27 -0
- package/lib/hosted-target/adapter-types.d.mts +27 -0
- package/lib/hosted-target/adapter-types.d.ts +27 -0
- package/lib/hosted-target/adapter-types.mjs +1 -0
- package/lib/hosted-target/bounds.cjs +10 -0
- package/lib/hosted-target/bounds.d.cts +7 -0
- package/lib/hosted-target/bounds.d.mts +7 -0
- package/lib/hosted-target/bounds.d.ts +7 -0
- package/lib/hosted-target/bounds.mjs +7 -0
- package/lib/hosted-target/capsule-error-response.cjs +76 -0
- package/lib/hosted-target/capsule-error-response.d.cts +2 -0
- package/lib/hosted-target/capsule-error-response.d.mts +2 -0
- package/lib/hosted-target/capsule-error-response.d.ts +2 -0
- package/lib/hosted-target/capsule-error-response.mjs +73 -0
- package/lib/hosted-target/errors.cjs +88 -0
- package/lib/hosted-target/errors.d.cts +36 -0
- package/lib/hosted-target/errors.d.mts +36 -0
- package/lib/hosted-target/errors.d.ts +36 -0
- package/lib/hosted-target/errors.mjs +75 -0
- package/lib/hosted-target/index.cjs +16 -0
- package/lib/hosted-target/index.d.cts +3 -0
- package/lib/hosted-target/index.d.mts +3 -0
- package/lib/hosted-target/index.d.ts +3 -0
- package/lib/hosted-target/index.mjs +2 -0
- package/lib/hosted-target/response-validation.cjs +169 -0
- package/lib/hosted-target/response-validation.d.cts +5 -0
- package/lib/hosted-target/response-validation.d.mts +5 -0
- package/lib/hosted-target/response-validation.d.ts +5 -0
- package/lib/hosted-target/response-validation.mjs +163 -0
- package/lib/hosted-target/retry-executor.cjs +51 -0
- package/lib/hosted-target/retry-executor.d.cts +8 -0
- package/lib/hosted-target/retry-executor.d.mts +8 -0
- package/lib/hosted-target/retry-executor.d.ts +8 -0
- package/lib/hosted-target/retry-executor.mjs +48 -0
- package/lib/hosted-target/retry.cjs +78 -0
- package/lib/hosted-target/retry.d.cts +9 -0
- package/lib/hosted-target/retry.d.mts +9 -0
- package/lib/hosted-target/retry.d.ts +9 -0
- package/lib/hosted-target/retry.mjs +73 -0
- package/lib/hosted-target/target-adapter.cjs +10 -0
- package/lib/hosted-target/target-adapter.d.cts +3 -0
- package/lib/hosted-target/target-adapter.d.mts +3 -0
- package/lib/hosted-target/target-adapter.d.ts +3 -0
- package/lib/hosted-target/target-adapter.mjs +7 -0
- package/lib/hosted-target/types.cjs +4 -0
- package/lib/hosted-target/types.d.cts +50 -0
- package/lib/hosted-target/types.d.mts +50 -0
- package/lib/hosted-target/types.d.ts +50 -0
- package/lib/hosted-target/types.mjs +1 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.cjs +185 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.d.cts +13 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.d.mts +13 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.d.ts +13 -0
- package/lib/hosted-target/zero-cloud-v1-adapter.mjs +181 -0
- package/lib/start-cluster.js +3 -3
- package/lib/target/bounded-response.cjs +51 -0
- package/lib/target/bounded-response.d.cts +1 -0
- package/lib/target/bounded-response.d.mts +1 -0
- package/lib/target/bounded-response.d.ts +1 -0
- package/lib/target/bounded-response.js +51 -0
- package/lib/target/bounded-response.mjs +48 -0
- package/lib/target/credential-lock.js +1 -3
- package/lib/target/credential-store.js +9 -4
- package/lib/target/device-flow.cjs +213 -0
- package/lib/target/device-flow.d.cts +54 -0
- package/lib/target/device-flow.d.mts +54 -0
- package/lib/target/device-flow.d.ts +26 -14
- package/lib/target/device-flow.js +162 -58
- package/lib/target/device-flow.mjs +203 -0
- package/lib/target/discovery-errors.cjs +10 -0
- package/lib/target/discovery-errors.d.cts +3 -0
- package/lib/target/discovery-errors.d.mts +3 -0
- package/lib/target/discovery-errors.d.ts +3 -0
- package/lib/target/discovery-errors.js +10 -0
- package/lib/target/discovery-errors.mjs +6 -0
- package/lib/target/discovery-sections.cjs +191 -0
- package/lib/target/discovery-sections.d.cts +52 -0
- package/lib/target/discovery-sections.d.mts +52 -0
- package/lib/target/discovery-sections.d.ts +52 -0
- package/lib/target/discovery-sections.js +191 -0
- package/lib/target/discovery-sections.mjs +179 -0
- package/lib/target/discovery-validation.cjs +109 -0
- package/lib/target/discovery-validation.d.cts +28 -0
- package/lib/target/discovery-validation.d.mts +28 -0
- package/lib/target/discovery-validation.d.ts +28 -0
- package/lib/target/discovery-validation.js +109 -0
- package/lib/target/discovery-validation.mjs +99 -0
- package/lib/target/discovery.cjs +112 -0
- package/lib/target/discovery.d.cts +74 -0
- package/lib/target/discovery.d.mts +74 -0
- package/lib/target/discovery.d.ts +67 -5
- package/lib/target/discovery.js +94 -79
- package/lib/target/discovery.mjs +105 -0
- package/lib/target/index.d.ts +6 -6
- package/lib/target/index.js +36 -36
- package/lib/target/oauth-http.d.ts +2 -0
- package/lib/target/oauth-http.js +25 -0
- package/lib/target/refresh-exchange.d.ts +11 -0
- package/lib/target/refresh-exchange.js +24 -0
- package/lib/target/refresh-revocation.d.ts +8 -0
- package/lib/target/refresh-revocation.js +19 -0
- package/lib/target/route-template.cjs +85 -0
- package/lib/target/route-template.d.cts +7 -0
- package/lib/target/route-template.d.mts +7 -0
- package/lib/target/route-template.d.ts +7 -0
- package/lib/target/route-template.js +85 -0
- package/lib/target/route-template.mjs +81 -0
- package/lib/target/session-errors.d.ts +4 -0
- package/lib/target/session-errors.js +12 -0
- package/lib/target/session-verification.d.ts +10 -0
- package/lib/target/session-verification.js +42 -0
- package/lib/target/target-registry.d.ts +7 -3
- package/lib/target/target-registry.js +41 -10
- package/lib/target/target-session-manager.d.ts +48 -0
- package/lib/target/target-session-manager.js +226 -0
- package/lib/target/target-session.d.ts +39 -32
- package/lib/target/target-session.js +63 -151
- package/lib/target/token-response.cjs +51 -0
- package/lib/target/token-response.d.cts +7 -0
- package/lib/target/token-response.d.mts +7 -0
- package/lib/target/token-response.d.ts +7 -0
- package/lib/target/token-response.js +51 -0
- package/lib/target/token-response.mjs +48 -0
- package/package.json +14 -7
- package/protocol/openengine-cluster/v1/worker.schema.json +171 -9
- package/scripts/build-cluster.js +23 -3
- package/scripts/opcore-introduced-check.js +0 -2
- package/src/agent-cli-provider/adapters/codex.ts +0 -1
- package/src/agent-cli-provider/contract-actions.ts +9 -5
- package/src/agent-cli-provider/contract-invoke.ts +3 -2
- package/src/agent-cli-provider/contract-support.ts +12 -6
- package/src/agent-cli-provider/contract.ts +6 -1
- package/src/agent-cli-provider/index.ts +1 -0
- package/src/agent-cli-provider/provider-registry.ts +4 -0
- package/src/agent-cli-provider/single-agent-runtime.ts +32 -45
- package/src/cluster/client.ts +42 -15
- package/src/cluster/connection-state.ts +33 -0
- package/src/cluster/connection-types.ts +28 -0
- package/src/cluster/connection.ts +37 -68
- package/src/cluster/errors.ts +5 -0
- package/src/cluster/index.ts +3 -1
- package/src/cluster/json-source.ts +1 -0
- package/src/cluster/payload-value.ts +1 -0
- package/src/cluster/socket.ts +13 -0
- package/src/cluster/subscriptions.ts +7 -2
- package/src/cluster/validators.ts +1 -0
- package/src/cluster/ws.d.ts +1 -1
- package/src/hosted-session/authority.ts +77 -0
- package/src/hosted-session/coordinator.ts +113 -56
- package/src/hosted-session/errors.ts +21 -0
- package/src/hosted-session/index.ts +14 -2
- package/src/hosted-session/reconnecting-watch.ts +148 -0
- package/src/hosted-session/types.ts +22 -8
- package/src/hosted-target/access-url.ts +46 -0
- package/src/hosted-target/adapter-request.ts +28 -0
- package/src/hosted-target/adapter-types.ts +39 -0
- package/src/hosted-target/bounds.ts +1 -0
- package/src/hosted-target/capsule-error-response.ts +107 -0
- package/src/hosted-target/errors.ts +36 -35
- package/src/hosted-target/index.ts +10 -23
- package/src/hosted-target/response-validation.ts +170 -62
- package/src/hosted-target/retry-executor.ts +62 -0
- package/src/hosted-target/retry.ts +47 -11
- package/src/hosted-target/target-adapter.ts +12 -8
- package/src/hosted-target/types.ts +19 -18
- package/src/hosted-target/zero-cloud-v1-adapter.ts +229 -316
- package/src/isolation-manager.js +1 -16
- package/src/target/bounded-response.ts +68 -0
- package/src/target/credential-lock.ts +1 -3
- package/src/target/credential-store.ts +14 -10
- package/src/target/device-flow.ts +209 -85
- package/src/target/discovery-errors.ts +6 -0
- package/src/target/discovery-sections.ts +251 -0
- package/src/target/discovery-validation.ts +144 -0
- package/src/target/discovery.ts +163 -97
- package/src/target/index.ts +15 -11
- package/src/target/oauth-http.ts +27 -0
- package/src/target/refresh-exchange.ts +36 -0
- package/src/target/refresh-revocation.ts +29 -0
- package/src/target/route-template.ts +105 -0
- package/src/target/session-errors.ts +9 -0
- package/src/target/session-verification.ts +51 -0
- package/src/target/target-registry.ts +60 -27
- package/src/target/target-session-manager.ts +285 -0
- package/src/target/target-session.ts +105 -226
- package/src/target/token-response.ts +62 -0
- package/docker/zeroshot-oecp/Cargo.toml +0 -12
- package/docker/zeroshot-oecp/Dockerfile +0 -65
- package/docker/zeroshot-oecp/src/main.rs +0 -32
- package/lib/target/bounded-json.d.ts +0 -6
- package/lib/target/bounded-json.js +0 -43
- package/lib/target/hosted-run/client.d.ts +0 -26
- package/lib/target/hosted-run/client.js +0 -158
- package/lib/target/hosted-run/commands.d.ts +0 -4
- package/lib/target/hosted-run/commands.js +0 -113
- package/lib/target/hosted-run/contracts.d.ts +0 -49
- package/lib/target/hosted-run/input.d.ts +0 -5
- package/lib/target/hosted-run/input.js +0 -200
- package/lib/target/hosted-run.d.ts +0 -4
- package/lib/target/hosted-run.js +0 -12
- package/src/target/bounded-json.ts +0 -48
- package/src/target/hosted-run/client.ts +0 -198
- package/src/target/hosted-run/commands.ts +0 -140
- package/src/target/hosted-run/contracts.ts +0 -53
- package/src/target/hosted-run/input.ts +0 -199
- package/src/target/hosted-run.ts +0 -8
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { TargetDiscoveryError } from './discovery-errors.js';
|
|
2
|
+
import {
|
|
3
|
+
closedRecord,
|
|
4
|
+
exact,
|
|
5
|
+
exactStringSet,
|
|
6
|
+
integer,
|
|
7
|
+
parseCredentialInstall,
|
|
8
|
+
sameOriginUrl,
|
|
9
|
+
stringField,
|
|
10
|
+
type CredentialInstallDescriptor,
|
|
11
|
+
} from './discovery-validation.js';
|
|
12
|
+
import { routeTemplate } from './route-template.js';
|
|
13
|
+
|
|
14
|
+
export function parseAdapter(discovery: Record<string, unknown>): {
|
|
15
|
+
readonly name: 'fargate' | 'docker' | 'local';
|
|
16
|
+
readonly majorVersion: 1;
|
|
17
|
+
} {
|
|
18
|
+
const adapter = closedRecord(discovery.adapter, 'adapter', ['name', 'major_version']);
|
|
19
|
+
if (!['fargate', 'docker', 'local'].includes(String(adapter.name))) {
|
|
20
|
+
throw new TargetDiscoveryError('adapter.name is not supported');
|
|
21
|
+
}
|
|
22
|
+
exact(adapter.major_version, 1, 'adapter.major_version');
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
name: adapter.name as 'fargate' | 'docker' | 'local',
|
|
25
|
+
majorVersion: 1 as const,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function validateCachePolicy(discovery: Record<string, unknown>): void {
|
|
30
|
+
const cache = closedRecord(discovery.cache_policy, 'cache_policy', ['control', 'discovery']);
|
|
31
|
+
exact(cache.control, 'no-store', 'cache_policy.control');
|
|
32
|
+
if (cache.discovery !== undefined && cache.discovery !== null &&
|
|
33
|
+
typeof cache.discovery !== 'string') {
|
|
34
|
+
throw new TargetDiscoveryError('cache_policy.discovery must be a string or null');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function parseSizes(discovery: Record<string, unknown>): {
|
|
39
|
+
readonly catalog: readonly ('tiny' | 'small' | 'standard' | 'large')[];
|
|
40
|
+
readonly default: 'tiny' | 'small' | 'standard' | 'large';
|
|
41
|
+
} {
|
|
42
|
+
const sizes = closedRecord(discovery.sizes, 'sizes', ['catalog', 'default']);
|
|
43
|
+
if (!Array.isArray(sizes.catalog) || sizes.catalog.length === 0 ||
|
|
44
|
+
new Set(sizes.catalog).size !== sizes.catalog.length ||
|
|
45
|
+
sizes.catalog.some((size) => !['tiny', 'small', 'standard', 'large'].includes(String(size)))) {
|
|
46
|
+
throw new TargetDiscoveryError('sizes.catalog contains an unsupported size');
|
|
47
|
+
}
|
|
48
|
+
if (!sizes.catalog.includes(sizes.default)) {
|
|
49
|
+
throw new TargetDiscoveryError('sizes.default is not in sizes.catalog');
|
|
50
|
+
}
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
catalog: Object.freeze([...(sizes.catalog as Array<'tiny' | 'small' | 'standard' | 'large'>)]),
|
|
53
|
+
default: sizes.default as 'tiny' | 'small' | 'standard' | 'large',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function parseExtensions(
|
|
58
|
+
discovery: Record<string, unknown>,
|
|
59
|
+
origin: string,
|
|
60
|
+
): CredentialInstallDescriptor | null {
|
|
61
|
+
if (discovery.extensions === undefined || discovery.extensions === null) return null;
|
|
62
|
+
const extensions = closedRecord(discovery.extensions, 'extensions', [
|
|
63
|
+
'connections', 'credential_install',
|
|
64
|
+
]);
|
|
65
|
+
if (extensions.connections === undefined) {
|
|
66
|
+
throw new TargetDiscoveryError('extensions.connections is required');
|
|
67
|
+
}
|
|
68
|
+
const connections = closedRecord(extensions.connections, 'extensions.connections', [
|
|
69
|
+
'kind', 'base_url', 'route_templates',
|
|
70
|
+
]);
|
|
71
|
+
exact(connections.kind, 'zerocloud.connections/v1', 'extensions.connections.kind');
|
|
72
|
+
sameOriginUrl(connections.base_url, 'extensions.connections.base_url', origin);
|
|
73
|
+
const routes = closedRecord(connections.route_templates, 'extensions.connections.route_templates', [
|
|
74
|
+
'list', 'create', 'update',
|
|
75
|
+
]);
|
|
76
|
+
routeTemplate(routes.list, 'extensions.connections.route_templates.list', []);
|
|
77
|
+
routeTemplate(routes.create, 'extensions.connections.route_templates.create', []);
|
|
78
|
+
routeTemplate(routes.update, 'extensions.connections.route_templates.update', ['connection_id']);
|
|
79
|
+
return parseCredentialInstall(extensions.credential_install);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function validateOAuthMetadata(
|
|
83
|
+
metadata: Record<string, unknown>,
|
|
84
|
+
origin: string,
|
|
85
|
+
expected: readonly [string, string, string],
|
|
86
|
+
): void {
|
|
87
|
+
const device = sameOriginUrl(
|
|
88
|
+
metadata.device_authorization_endpoint,
|
|
89
|
+
'OAuth metadata device_authorization_endpoint',
|
|
90
|
+
origin,
|
|
91
|
+
);
|
|
92
|
+
const token = sameOriginUrl(metadata.token_endpoint, 'OAuth metadata token_endpoint', origin);
|
|
93
|
+
const revoke = sameOriginUrl(
|
|
94
|
+
metadata.revocation_endpoint,
|
|
95
|
+
'OAuth metadata revocation_endpoint',
|
|
96
|
+
origin,
|
|
97
|
+
);
|
|
98
|
+
if (device !== expected[0] || token !== expected[1] || revoke !== expected[2]) {
|
|
99
|
+
throw new TargetDiscoveryError('OAuth metadata does not match hosted-target discovery');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function parseEndpoint(discovery: Record<string, unknown>, origin: string) {
|
|
104
|
+
const protocol = closedRecord(discovery.protocol, 'protocol', ['name', 'major_version']);
|
|
105
|
+
exact(protocol.name, 'openengine.cluster/v1', 'protocol.name');
|
|
106
|
+
exact(protocol.major_version, 1, 'protocol.major_version');
|
|
107
|
+
const binding = closedRecord(discovery.binding, 'binding', ['scope', 'auth_location']);
|
|
108
|
+
exact(binding.scope, 'organization', 'binding.scope');
|
|
109
|
+
exact(binding.auth_location, 'authorization_header', 'binding.auth_location');
|
|
110
|
+
const endpoint = closedRecord(discovery.endpoint, 'endpoint', ['url', 'capabilities']);
|
|
111
|
+
const capabilities = exactStringSet(
|
|
112
|
+
endpoint.capabilities,
|
|
113
|
+
'endpoint.capabilities',
|
|
114
|
+
['exec', 'log_stream'],
|
|
115
|
+
) as readonly ['exec', 'log_stream'];
|
|
116
|
+
const pagination = closedRecord(discovery.pagination, 'pagination', [
|
|
117
|
+
'default_page_size',
|
|
118
|
+
'max_page_size',
|
|
119
|
+
]);
|
|
120
|
+
const defaultPageSize = integer(
|
|
121
|
+
pagination.default_page_size,
|
|
122
|
+
'pagination.default_page_size',
|
|
123
|
+
1,
|
|
124
|
+
);
|
|
125
|
+
const maxPageSize = integer(pagination.max_page_size, 'pagination.max_page_size', 1);
|
|
126
|
+
if (defaultPageSize > maxPageSize) {
|
|
127
|
+
throw new TargetDiscoveryError('pagination.default_page_size exceeds maximum');
|
|
128
|
+
}
|
|
129
|
+
validateCachePolicy(discovery);
|
|
130
|
+
const schemaLinks = closedRecord(discovery.schema_links, 'schema_links', [
|
|
131
|
+
'self',
|
|
132
|
+
'problem',
|
|
133
|
+
'errors',
|
|
134
|
+
]);
|
|
135
|
+
sameOriginUrl(schemaLinks.self, 'schema_links.self', origin);
|
|
136
|
+
sameOriginUrl(schemaLinks.problem, 'schema_links.problem', origin);
|
|
137
|
+
sameOriginUrl(schemaLinks.errors, 'schema_links.errors', origin);
|
|
138
|
+
return Object.freeze({
|
|
139
|
+
url: sameOriginUrl(endpoint.url, 'endpoint.url', origin),
|
|
140
|
+
capabilities,
|
|
141
|
+
pagination: Object.freeze({ defaultPageSize, maxPageSize }),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function parseCapsule(discovery: Record<string, unknown>, origin: string) {
|
|
146
|
+
const capsule = closedRecord(discovery.capsule_protocol, 'capsule_protocol', [
|
|
147
|
+
'name',
|
|
148
|
+
'major_version',
|
|
149
|
+
'base_url',
|
|
150
|
+
'route_templates',
|
|
151
|
+
]);
|
|
152
|
+
exact(capsule.name, 'openengine.capsules/v1', 'capsule_protocol.name');
|
|
153
|
+
exact(capsule.major_version, 1, 'capsule_protocol.major_version');
|
|
154
|
+
const routes = closedRecord(
|
|
155
|
+
capsule.route_templates,
|
|
156
|
+
'capsule_protocol.route_templates',
|
|
157
|
+
['allocate', 'list', 'inspect', 'terminate', 'limits', 'access'],
|
|
158
|
+
);
|
|
159
|
+
const route = (name: string, variables: readonly string[]) =>
|
|
160
|
+
routeTemplate(routes[name], `capsule_protocol.route_templates.${name}`, variables);
|
|
161
|
+
return Object.freeze({
|
|
162
|
+
baseUrl: sameOriginUrl(capsule.base_url, 'capsule_protocol.base_url', origin),
|
|
163
|
+
routes: Object.freeze({
|
|
164
|
+
allocate: route('allocate', ['org_id']),
|
|
165
|
+
list: route('list', ['org_id', 'cursor', 'limit']),
|
|
166
|
+
inspect: route('inspect', ['org_id', 'capsule_id']),
|
|
167
|
+
terminate: route('terminate', ['org_id', 'capsule_id']),
|
|
168
|
+
limits: route('limits', ['org_id']),
|
|
169
|
+
access: route('access', ['capsule_id']),
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function parseOAuth(discovery: Record<string, unknown>, origin: string) {
|
|
175
|
+
const oauth = closedRecord(discovery.oauth, 'oauth', [
|
|
176
|
+
'metadata_url',
|
|
177
|
+
'device_authorization_endpoint',
|
|
178
|
+
'token_endpoint',
|
|
179
|
+
'revocation_endpoint',
|
|
180
|
+
'client_id',
|
|
181
|
+
'device_grant_type',
|
|
182
|
+
'device_exchange_fields',
|
|
183
|
+
'audience',
|
|
184
|
+
]);
|
|
185
|
+
exact(
|
|
186
|
+
oauth.device_grant_type,
|
|
187
|
+
'urn:ietf:params:oauth:grant-type:device_code',
|
|
188
|
+
'oauth.device_grant_type',
|
|
189
|
+
);
|
|
190
|
+
exactStringSet(
|
|
191
|
+
oauth.device_exchange_fields,
|
|
192
|
+
'oauth.device_exchange_fields',
|
|
193
|
+
['device_token', 'device_label'],
|
|
194
|
+
);
|
|
195
|
+
exact(oauth.audience, 'capsule', 'oauth.audience');
|
|
196
|
+
return Object.freeze({
|
|
197
|
+
metadataUrl: sameOriginUrl(oauth.metadata_url, 'oauth.metadata_url', origin),
|
|
198
|
+
deviceAuthorizationEndpoint: sameOriginUrl(
|
|
199
|
+
oauth.device_authorization_endpoint,
|
|
200
|
+
'oauth.device_authorization_endpoint',
|
|
201
|
+
origin,
|
|
202
|
+
),
|
|
203
|
+
tokenEndpoint: sameOriginUrl(oauth.token_endpoint, 'oauth.token_endpoint', origin),
|
|
204
|
+
revocationEndpoint: sameOriginUrl(
|
|
205
|
+
oauth.revocation_endpoint,
|
|
206
|
+
'oauth.revocation_endpoint',
|
|
207
|
+
origin,
|
|
208
|
+
),
|
|
209
|
+
clientId: stringField(oauth, 'client_id', 'oauth.'),
|
|
210
|
+
deviceGrantType: 'urn:ietf:params:oauth:grant-type:device_code' as const,
|
|
211
|
+
audience: 'capsule' as const,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function parseSession(discovery: Record<string, unknown>) {
|
|
216
|
+
const session = closedRecord(discovery.session, 'session', [
|
|
217
|
+
'route_template',
|
|
218
|
+
'method',
|
|
219
|
+
'cache_policy',
|
|
220
|
+
]);
|
|
221
|
+
exact(session.method, 'GET', 'session.method');
|
|
222
|
+
exact(session.cache_policy, 'no-store', 'session.cache_policy');
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
routeTemplate: routeTemplate(session.route_template, 'session.route_template', []),
|
|
225
|
+
method: 'GET' as const,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function parseTransport(discovery: Record<string, unknown>) {
|
|
230
|
+
const transport = closedRecord(discovery.transport, 'transport', [
|
|
231
|
+
'websocket_route_template',
|
|
232
|
+
'unauthorized_status',
|
|
233
|
+
'close_codes',
|
|
234
|
+
]);
|
|
235
|
+
exact(transport.unauthorized_status, 401, 'transport.unauthorized_status');
|
|
236
|
+
const closeCodes = closedRecord(transport.close_codes, 'transport.close_codes', [
|
|
237
|
+
'expired',
|
|
238
|
+
'revoked',
|
|
239
|
+
]);
|
|
240
|
+
exact(closeCodes.expired, 4401, 'transport.close_codes.expired');
|
|
241
|
+
exact(closeCodes.revoked, 4403, 'transport.close_codes.revoked');
|
|
242
|
+
return Object.freeze({
|
|
243
|
+
websocketRouteTemplate: routeTemplate(
|
|
244
|
+
transport.websocket_route_template,
|
|
245
|
+
'transport.websocket_route_template',
|
|
246
|
+
['capsule_id'],
|
|
247
|
+
),
|
|
248
|
+
unauthorizedStatus: 401 as const,
|
|
249
|
+
closeCodes: Object.freeze({ expired: 4401 as const, revoked: 4403 as const }),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { TargetDiscoveryError } from './discovery-errors.js';
|
|
2
|
+
import { routeTemplate, type RouteTemplate } from './route-template.js';
|
|
3
|
+
|
|
4
|
+
export interface CredentialInstallDescriptor {
|
|
5
|
+
readonly kind: 'openengine.capsule-credential-install/v1';
|
|
6
|
+
readonly grant: { readonly routeTemplate: RouteTemplate; readonly method: 'POST' };
|
|
7
|
+
readonly install: { readonly routeTemplate: RouteTemplate; readonly method: 'PUT' };
|
|
8
|
+
readonly uploadUrlOrigin: 'same_origin';
|
|
9
|
+
readonly sealedEnvelopeAlgorithms: readonly ['RSA-OAEP-3072-SHA256'];
|
|
10
|
+
readonly bounds: {
|
|
11
|
+
readonly maxEnvelopeBytes: number;
|
|
12
|
+
readonly maxBodyBytes: number;
|
|
13
|
+
readonly grantTtlSeconds: number;
|
|
14
|
+
readonly maxClockSkewSeconds: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function record(value: unknown, field: string): Record<string, unknown> {
|
|
19
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
20
|
+
throw new TargetDiscoveryError(`${field} must be an object`);
|
|
21
|
+
}
|
|
22
|
+
return value as Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function closedRecord(
|
|
26
|
+
value: unknown,
|
|
27
|
+
field: string,
|
|
28
|
+
fields: readonly string[],
|
|
29
|
+
): Record<string, unknown> {
|
|
30
|
+
const result = record(value, field);
|
|
31
|
+
const unknown = Object.keys(result).find((key) => !fields.includes(key));
|
|
32
|
+
if (unknown !== undefined) throw new TargetDiscoveryError(`${field}.${unknown} is not supported`);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function stringField(
|
|
37
|
+
source: Record<string, unknown>,
|
|
38
|
+
field: string,
|
|
39
|
+
parent = '',
|
|
40
|
+
): string {
|
|
41
|
+
const value = source[field];
|
|
42
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
43
|
+
throw new TargetDiscoveryError(`${parent}${field} must be a non-empty string`);
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function exact(value: unknown, expected: unknown, field: string): void {
|
|
49
|
+
if (value !== expected) throw new TargetDiscoveryError(`${field} is not supported`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function integer(
|
|
53
|
+
value: unknown,
|
|
54
|
+
field: string,
|
|
55
|
+
min: number,
|
|
56
|
+
max = Number.MAX_SAFE_INTEGER,
|
|
57
|
+
): number {
|
|
58
|
+
if (!Number.isSafeInteger(value) || (value as number) < min || (value as number) > max) {
|
|
59
|
+
throw new TargetDiscoveryError(`${field} is outside the supported bounds`);
|
|
60
|
+
}
|
|
61
|
+
return value as number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function exactStringSet(
|
|
65
|
+
value: unknown,
|
|
66
|
+
field: string,
|
|
67
|
+
expected: readonly string[],
|
|
68
|
+
): readonly string[] {
|
|
69
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
70
|
+
throw new TargetDiscoveryError(`${field} must be an array of strings`);
|
|
71
|
+
}
|
|
72
|
+
if (value.length !== expected.length || new Set(value).size !== value.length ||
|
|
73
|
+
expected.some((item) => !value.includes(item))) {
|
|
74
|
+
throw new TargetDiscoveryError(`${field} does not match the supported contract`);
|
|
75
|
+
}
|
|
76
|
+
return Object.freeze([...value]) as readonly string[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function hasForbiddenUrlComponent(
|
|
80
|
+
url: URL,
|
|
81
|
+
value: string,
|
|
82
|
+
protocols: readonly string[],
|
|
83
|
+
): boolean {
|
|
84
|
+
return !protocols.includes(url.protocol) ||
|
|
85
|
+
url.username !== '' ||
|
|
86
|
+
url.password !== '' ||
|
|
87
|
+
url.search !== '' ||
|
|
88
|
+
url.hash !== '' ||
|
|
89
|
+
url.href !== value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function sameOriginUrl(
|
|
93
|
+
value: unknown,
|
|
94
|
+
field: string,
|
|
95
|
+
origin: string,
|
|
96
|
+
protocols: readonly string[] = ['https:', 'http:'],
|
|
97
|
+
): string {
|
|
98
|
+
if (typeof value !== 'string' || /[\u0000-\u0020\u007f]|\s/u.test(value)) {
|
|
99
|
+
throw new TargetDiscoveryError(`${field} must be a canonical absolute URL`);
|
|
100
|
+
}
|
|
101
|
+
let url: URL;
|
|
102
|
+
try {
|
|
103
|
+
url = new URL(value);
|
|
104
|
+
} catch {
|
|
105
|
+
throw new TargetDiscoveryError(`${field} must be an absolute URL`);
|
|
106
|
+
}
|
|
107
|
+
if (hasForbiddenUrlComponent(url, value, protocols)) {
|
|
108
|
+
throw new TargetDiscoveryError(`${field} contains forbidden URL components`);
|
|
109
|
+
}
|
|
110
|
+
if (url.origin !== origin) {
|
|
111
|
+
throw new TargetDiscoveryError(`${field} must remain on the target origin`);
|
|
112
|
+
}
|
|
113
|
+
return url.href;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function parseCredentialInstall(value: unknown): CredentialInstallDescriptor | null {
|
|
117
|
+
if (value === undefined || value === null) return null;
|
|
118
|
+
const extension = closedRecord(value, 'extensions.credential_install', [
|
|
119
|
+
'kind', 'grant', 'install', 'upload_url_origin', 'sealed_envelope_algorithms', 'bounds',
|
|
120
|
+
]);
|
|
121
|
+
exact(extension.kind, 'openengine.capsule-credential-install/v1', 'extensions.credential_install.kind');
|
|
122
|
+
const grant = closedRecord(extension.grant, 'extensions.credential_install.grant', ['route_template', 'method']);
|
|
123
|
+
const install = closedRecord(extension.install, 'extensions.credential_install.install', ['route_template', 'method']);
|
|
124
|
+
exact(grant.method, 'POST', 'extensions.credential_install.grant.method');
|
|
125
|
+
exact(install.method, 'PUT', 'extensions.credential_install.install.method');
|
|
126
|
+
exact(extension.upload_url_origin, 'same_origin', 'extensions.credential_install.upload_url_origin');
|
|
127
|
+
exactStringSet(extension.sealed_envelope_algorithms, 'extensions.credential_install.sealed_envelope_algorithms', ['RSA-OAEP-3072-SHA256']);
|
|
128
|
+
const bounds = closedRecord(extension.bounds, 'extensions.credential_install.bounds', [
|
|
129
|
+
'max_envelope_bytes', 'max_body_bytes', 'grant_ttl_seconds', 'max_clock_skew_seconds',
|
|
130
|
+
]);
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
kind: 'openengine.capsule-credential-install/v1' as const,
|
|
133
|
+
grant: Object.freeze({ routeTemplate: routeTemplate(grant.route_template, 'extensions.credential_install.grant.route_template', ['capsule_id']), method: 'POST' as const }),
|
|
134
|
+
install: Object.freeze({ routeTemplate: routeTemplate(install.route_template, 'extensions.credential_install.install.route_template', ['capsule_id']), method: 'PUT' as const }),
|
|
135
|
+
uploadUrlOrigin: 'same_origin' as const,
|
|
136
|
+
sealedEnvelopeAlgorithms: Object.freeze(['RSA-OAEP-3072-SHA256'] as const),
|
|
137
|
+
bounds: Object.freeze({
|
|
138
|
+
maxEnvelopeBytes: integer(bounds.max_envelope_bytes, 'extensions.credential_install.bounds.max_envelope_bytes', 1, 1_048_576),
|
|
139
|
+
maxBodyBytes: integer(bounds.max_body_bytes, 'extensions.credential_install.bounds.max_body_bytes', 1, 1_048_576),
|
|
140
|
+
grantTtlSeconds: integer(bounds.grant_ttl_seconds, 'extensions.credential_install.bounds.grant_ttl_seconds', 1, 3_600),
|
|
141
|
+
maxClockSkewSeconds: integer(bounds.max_clock_skew_seconds, 'extensions.credential_install.bounds.max_clock_skew_seconds', 0, 300),
|
|
142
|
+
}),
|
|
143
|
+
});
|
|
144
|
+
}
|