@the-open-engine/zeroshot 6.32.0 → 6.33.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/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +14 -6
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/agent-cli-provider/provider-registry.d.ts +4 -2
- package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
- package/lib/agent-cli-provider/provider-registry.js +13 -3
- package/lib/agent-cli-provider/provider-registry.js.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.js +7 -4
- package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
- package/lib/agent-cli-provider/types.d.ts +2 -0
- package/lib/agent-cli-provider/types.d.ts.map +1 -1
- package/lib/agent-cli-provider/types.js.map +1 -1
- package/lib/detached-startup.js +4 -0
- package/lib/hosted-target/adapter-request.cjs +6 -3
- package/lib/hosted-target/adapter-request.mjs +6 -3
- package/lib/target/discovery-sections.cjs +35 -13
- package/lib/target/discovery-sections.d.cts +5 -1
- package/lib/target/discovery-sections.d.mts +5 -1
- package/lib/target/discovery-sections.d.ts +5 -1
- package/lib/target/discovery-sections.js +35 -13
- package/lib/target/discovery-sections.mjs +35 -13
- package/lib/target/discovery.cjs +49 -38
- package/lib/target/discovery.d.cts +3 -0
- package/lib/target/discovery.d.mts +3 -0
- package/lib/target/discovery.d.ts +3 -0
- package/lib/target/discovery.js +49 -38
- package/lib/target/discovery.mjs +49 -38
- package/lib/target/index.d.ts +1 -1
- package/lib/target/run-intent-discovery.cjs +30 -0
- package/lib/target/run-intent-discovery.d.cts +11 -0
- package/lib/target/run-intent-discovery.d.mts +11 -0
- package/lib/target/run-intent-discovery.d.ts +11 -0
- package/lib/target/run-intent-discovery.js +30 -0
- package/lib/target/run-intent-discovery.mjs +27 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -3
- package/src/agent/agent-lifecycle.js +11 -1
- package/src/agent/agent-task-executor.js +25 -7
- package/src/agent/structured-output-error.js +42 -0
- package/src/agent-cli-provider/adapters/codex.ts +15 -16
- package/src/agent-cli-provider/provider-registry.ts +15 -3
- package/src/agent-cli-provider/single-agent-runtime.ts +11 -11
- package/src/agent-cli-provider/types.ts +2 -0
- package/src/hosted-target/adapter-request.ts +8 -3
- package/src/isolation-manager.js +52 -0
- package/src/orchestrator.js +6 -0
- package/src/target/discovery-sections.ts +59 -41
- package/src/target/discovery.ts +71 -54
- package/src/target/index.ts +1 -0
- package/src/target/run-intent-discovery.ts +39 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { TargetProtocolError } from './errors.mjs';
|
|
2
2
|
export function requestUrl(path, descriptor) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const baseUrl = new globalThis.URL(descriptor.capsule.baseUrl);
|
|
4
|
+
const requestPath = `${baseUrl.pathname.replace(/\/$/, '')}${path}`;
|
|
5
|
+
const url = new globalThis.URL(requestPath, baseUrl.origin);
|
|
6
|
+
if (url.origin !== descriptor.origin ||
|
|
7
|
+
url.hash ||
|
|
8
|
+
`${url.pathname}${url.search}` !== requestPath) {
|
|
6
9
|
throw new TargetProtocolError('Capsule route changed during URL canonicalization');
|
|
7
10
|
}
|
|
8
11
|
return url;
|
|
@@ -12,6 +12,7 @@ exports.parseSession = parseSession;
|
|
|
12
12
|
exports.parseTransport = parseTransport;
|
|
13
13
|
const discovery_errors_js_1 = require("./discovery-errors.cjs");
|
|
14
14
|
const discovery_validation_js_1 = require("./discovery-validation.cjs");
|
|
15
|
+
const run_intent_discovery_js_1 = require("./run-intent-discovery.cjs");
|
|
15
16
|
const route_template_js_1 = require("./route-template.cjs");
|
|
16
17
|
function parseAdapter(discovery) {
|
|
17
18
|
const adapter = (0, discovery_validation_js_1.closedRecord)(discovery.adapter, 'adapter', ['name', 'major_version']);
|
|
@@ -27,14 +28,16 @@ function parseAdapter(discovery) {
|
|
|
27
28
|
function validateCachePolicy(discovery) {
|
|
28
29
|
const cache = (0, discovery_validation_js_1.closedRecord)(discovery.cache_policy, 'cache_policy', ['control', 'discovery']);
|
|
29
30
|
(0, discovery_validation_js_1.exact)(cache.control, 'no-store', 'cache_policy.control');
|
|
30
|
-
if (cache.discovery !== undefined &&
|
|
31
|
+
if (cache.discovery !== undefined &&
|
|
32
|
+
cache.discovery !== null &&
|
|
31
33
|
typeof cache.discovery !== 'string') {
|
|
32
34
|
throw new discovery_errors_js_1.TargetDiscoveryError('cache_policy.discovery must be a string or null');
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
function parseSizes(discovery) {
|
|
36
38
|
const sizes = (0, discovery_validation_js_1.closedRecord)(discovery.sizes, 'sizes', ['catalog', 'default']);
|
|
37
|
-
if (!Array.isArray(sizes.catalog) ||
|
|
39
|
+
if (!Array.isArray(sizes.catalog) ||
|
|
40
|
+
sizes.catalog.length === 0 ||
|
|
38
41
|
new Set(sizes.catalog).size !== sizes.catalog.length ||
|
|
39
42
|
sizes.catalog.some((size) => !['tiny', 'small', 'standard', 'large'].includes(String(size)))) {
|
|
40
43
|
throw new discovery_errors_js_1.TargetDiscoveryError('sizes.catalog contains an unsupported size');
|
|
@@ -48,26 +51,32 @@ function parseSizes(discovery) {
|
|
|
48
51
|
});
|
|
49
52
|
}
|
|
50
53
|
function parseExtensions(discovery, origin) {
|
|
51
|
-
if (discovery.extensions === undefined || discovery.extensions === null)
|
|
52
|
-
return null;
|
|
54
|
+
if (discovery.extensions === undefined || discovery.extensions === null) {
|
|
55
|
+
return Object.freeze({ credentialInstall: null, runIntent: null });
|
|
56
|
+
}
|
|
53
57
|
const extensions = (0, discovery_validation_js_1.closedRecord)(discovery.extensions, 'extensions', [
|
|
54
|
-
'connections',
|
|
58
|
+
'connections',
|
|
59
|
+
'credential_install',
|
|
60
|
+
'run_intent',
|
|
55
61
|
]);
|
|
56
62
|
if (extensions.connections === undefined) {
|
|
57
63
|
throw new discovery_errors_js_1.TargetDiscoveryError('extensions.connections is required');
|
|
58
64
|
}
|
|
59
65
|
const connections = (0, discovery_validation_js_1.closedRecord)(extensions.connections, 'extensions.connections', [
|
|
60
|
-
'kind',
|
|
66
|
+
'kind',
|
|
67
|
+
'base_url',
|
|
68
|
+
'route_templates',
|
|
61
69
|
]);
|
|
62
70
|
(0, discovery_validation_js_1.exact)(connections.kind, 'zerocloud.connections/v1', 'extensions.connections.kind');
|
|
63
71
|
(0, discovery_validation_js_1.sameOriginUrl)(connections.base_url, 'extensions.connections.base_url', origin);
|
|
64
|
-
const routes = (0, discovery_validation_js_1.closedRecord)(connections.route_templates, 'extensions.connections.route_templates', [
|
|
65
|
-
'list', 'create', 'update',
|
|
66
|
-
]);
|
|
72
|
+
const routes = (0, discovery_validation_js_1.closedRecord)(connections.route_templates, 'extensions.connections.route_templates', ['list', 'create', 'update']);
|
|
67
73
|
(0, route_template_js_1.routeTemplate)(routes.list, 'extensions.connections.route_templates.list', []);
|
|
68
74
|
(0, route_template_js_1.routeTemplate)(routes.create, 'extensions.connections.route_templates.create', []);
|
|
69
75
|
(0, route_template_js_1.routeTemplate)(routes.update, 'extensions.connections.route_templates.update', ['connection_id']);
|
|
70
|
-
return
|
|
76
|
+
return Object.freeze({
|
|
77
|
+
credentialInstall: (0, discovery_validation_js_1.parseCredentialInstall)(extensions.credential_install),
|
|
78
|
+
runIntent: (0, run_intent_discovery_js_1.parseRunIntent)(extensions.run_intent, origin),
|
|
79
|
+
});
|
|
71
80
|
}
|
|
72
81
|
function validateOAuthMetadata(metadata, origin, expected) {
|
|
73
82
|
const device = (0, discovery_validation_js_1.sameOriginUrl)(metadata.device_authorization_endpoint, 'OAuth metadata device_authorization_endpoint', origin);
|
|
@@ -85,7 +94,10 @@ function parseEndpoint(discovery, origin) {
|
|
|
85
94
|
(0, discovery_validation_js_1.exact)(binding.scope, 'organization', 'binding.scope');
|
|
86
95
|
(0, discovery_validation_js_1.exact)(binding.auth_location, 'authorization_header', 'binding.auth_location');
|
|
87
96
|
const endpoint = (0, discovery_validation_js_1.closedRecord)(discovery.endpoint, 'endpoint', ['url', 'capabilities']);
|
|
88
|
-
const capabilities = (0, discovery_validation_js_1.exactStringSet)(endpoint.capabilities, 'endpoint.capabilities', [
|
|
97
|
+
const capabilities = (0, discovery_validation_js_1.exactStringSet)(endpoint.capabilities, 'endpoint.capabilities', [
|
|
98
|
+
'exec',
|
|
99
|
+
'log_stream',
|
|
100
|
+
]);
|
|
89
101
|
const pagination = (0, discovery_validation_js_1.closedRecord)(discovery.pagination, 'pagination', [
|
|
90
102
|
'default_page_size',
|
|
91
103
|
'max_page_size',
|
|
@@ -119,7 +131,14 @@ function parseCapsule(discovery, origin) {
|
|
|
119
131
|
]);
|
|
120
132
|
(0, discovery_validation_js_1.exact)(capsule.name, 'openengine.capsules/v1', 'capsule_protocol.name');
|
|
121
133
|
(0, discovery_validation_js_1.exact)(capsule.major_version, 1, 'capsule_protocol.major_version');
|
|
122
|
-
const routes = (0, discovery_validation_js_1.closedRecord)(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
134
|
+
const routes = (0, discovery_validation_js_1.closedRecord)(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
135
|
+
'allocate',
|
|
136
|
+
'list',
|
|
137
|
+
'inspect',
|
|
138
|
+
'terminate',
|
|
139
|
+
'limits',
|
|
140
|
+
'access',
|
|
141
|
+
]);
|
|
123
142
|
const route = (name, variables) => (0, route_template_js_1.routeTemplate)(routes[name], `capsule_protocol.route_templates.${name}`, variables);
|
|
124
143
|
return Object.freeze({
|
|
125
144
|
baseUrl: (0, discovery_validation_js_1.sameOriginUrl)(capsule.base_url, 'capsule_protocol.base_url', origin),
|
|
@@ -145,7 +164,10 @@ function parseOAuth(discovery, origin) {
|
|
|
145
164
|
'audience',
|
|
146
165
|
]);
|
|
147
166
|
(0, discovery_validation_js_1.exact)(oauth.device_grant_type, 'urn:ietf:params:oauth:grant-type:device_code', 'oauth.device_grant_type');
|
|
148
|
-
(0, discovery_validation_js_1.exactStringSet)(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
167
|
+
(0, discovery_validation_js_1.exactStringSet)(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
168
|
+
'device_token',
|
|
169
|
+
'device_label',
|
|
170
|
+
]);
|
|
149
171
|
(0, discovery_validation_js_1.exact)(oauth.audience, 'capsule', 'oauth.audience');
|
|
150
172
|
return Object.freeze({
|
|
151
173
|
metadataUrl: (0, discovery_validation_js_1.sameOriginUrl)(oauth.metadata_url, 'oauth.metadata_url', origin),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
2
|
+
import { type RunIntentDescriptor } from './run-intent-discovery.js';
|
|
2
3
|
export declare function parseAdapter(discovery: Record<string, unknown>): {
|
|
3
4
|
readonly name: 'fargate' | 'docker' | 'local';
|
|
4
5
|
readonly majorVersion: 1;
|
|
@@ -8,7 +9,10 @@ export declare function parseSizes(discovery: Record<string, unknown>): {
|
|
|
8
9
|
readonly catalog: readonly ('tiny' | 'small' | 'standard' | 'large')[];
|
|
9
10
|
readonly default: 'tiny' | 'small' | 'standard' | 'large';
|
|
10
11
|
};
|
|
11
|
-
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string):
|
|
12
|
+
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string): {
|
|
13
|
+
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
14
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
15
|
+
};
|
|
12
16
|
export declare function validateOAuthMetadata(metadata: Record<string, unknown>, origin: string, expected: readonly [string, string, string]): void;
|
|
13
17
|
export declare function parseEndpoint(discovery: Record<string, unknown>, origin: string): Readonly<{
|
|
14
18
|
url: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
2
|
+
import { type RunIntentDescriptor } from './run-intent-discovery.js';
|
|
2
3
|
export declare function parseAdapter(discovery: Record<string, unknown>): {
|
|
3
4
|
readonly name: 'fargate' | 'docker' | 'local';
|
|
4
5
|
readonly majorVersion: 1;
|
|
@@ -8,7 +9,10 @@ export declare function parseSizes(discovery: Record<string, unknown>): {
|
|
|
8
9
|
readonly catalog: readonly ('tiny' | 'small' | 'standard' | 'large')[];
|
|
9
10
|
readonly default: 'tiny' | 'small' | 'standard' | 'large';
|
|
10
11
|
};
|
|
11
|
-
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string):
|
|
12
|
+
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string): {
|
|
13
|
+
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
14
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
15
|
+
};
|
|
12
16
|
export declare function validateOAuthMetadata(metadata: Record<string, unknown>, origin: string, expected: readonly [string, string, string]): void;
|
|
13
17
|
export declare function parseEndpoint(discovery: Record<string, unknown>, origin: string): Readonly<{
|
|
14
18
|
url: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
2
|
+
import { type RunIntentDescriptor } from './run-intent-discovery.js';
|
|
2
3
|
export declare function parseAdapter(discovery: Record<string, unknown>): {
|
|
3
4
|
readonly name: 'fargate' | 'docker' | 'local';
|
|
4
5
|
readonly majorVersion: 1;
|
|
@@ -8,7 +9,10 @@ export declare function parseSizes(discovery: Record<string, unknown>): {
|
|
|
8
9
|
readonly catalog: readonly ('tiny' | 'small' | 'standard' | 'large')[];
|
|
9
10
|
readonly default: 'tiny' | 'small' | 'standard' | 'large';
|
|
10
11
|
};
|
|
11
|
-
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string):
|
|
12
|
+
export declare function parseExtensions(discovery: Record<string, unknown>, origin: string): {
|
|
13
|
+
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
14
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
15
|
+
};
|
|
12
16
|
export declare function validateOAuthMetadata(metadata: Record<string, unknown>, origin: string, expected: readonly [string, string, string]): void;
|
|
13
17
|
export declare function parseEndpoint(discovery: Record<string, unknown>, origin: string): Readonly<{
|
|
14
18
|
url: string;
|
|
@@ -12,6 +12,7 @@ exports.parseSession = parseSession;
|
|
|
12
12
|
exports.parseTransport = parseTransport;
|
|
13
13
|
const discovery_errors_js_1 = require("./discovery-errors.js");
|
|
14
14
|
const discovery_validation_js_1 = require("./discovery-validation.js");
|
|
15
|
+
const run_intent_discovery_js_1 = require("./run-intent-discovery.js");
|
|
15
16
|
const route_template_js_1 = require("./route-template.js");
|
|
16
17
|
function parseAdapter(discovery) {
|
|
17
18
|
const adapter = (0, discovery_validation_js_1.closedRecord)(discovery.adapter, 'adapter', ['name', 'major_version']);
|
|
@@ -27,14 +28,16 @@ function parseAdapter(discovery) {
|
|
|
27
28
|
function validateCachePolicy(discovery) {
|
|
28
29
|
const cache = (0, discovery_validation_js_1.closedRecord)(discovery.cache_policy, 'cache_policy', ['control', 'discovery']);
|
|
29
30
|
(0, discovery_validation_js_1.exact)(cache.control, 'no-store', 'cache_policy.control');
|
|
30
|
-
if (cache.discovery !== undefined &&
|
|
31
|
+
if (cache.discovery !== undefined &&
|
|
32
|
+
cache.discovery !== null &&
|
|
31
33
|
typeof cache.discovery !== 'string') {
|
|
32
34
|
throw new discovery_errors_js_1.TargetDiscoveryError('cache_policy.discovery must be a string or null');
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
function parseSizes(discovery) {
|
|
36
38
|
const sizes = (0, discovery_validation_js_1.closedRecord)(discovery.sizes, 'sizes', ['catalog', 'default']);
|
|
37
|
-
if (!Array.isArray(sizes.catalog) ||
|
|
39
|
+
if (!Array.isArray(sizes.catalog) ||
|
|
40
|
+
sizes.catalog.length === 0 ||
|
|
38
41
|
new Set(sizes.catalog).size !== sizes.catalog.length ||
|
|
39
42
|
sizes.catalog.some((size) => !['tiny', 'small', 'standard', 'large'].includes(String(size)))) {
|
|
40
43
|
throw new discovery_errors_js_1.TargetDiscoveryError('sizes.catalog contains an unsupported size');
|
|
@@ -48,26 +51,32 @@ function parseSizes(discovery) {
|
|
|
48
51
|
});
|
|
49
52
|
}
|
|
50
53
|
function parseExtensions(discovery, origin) {
|
|
51
|
-
if (discovery.extensions === undefined || discovery.extensions === null)
|
|
52
|
-
return null;
|
|
54
|
+
if (discovery.extensions === undefined || discovery.extensions === null) {
|
|
55
|
+
return Object.freeze({ credentialInstall: null, runIntent: null });
|
|
56
|
+
}
|
|
53
57
|
const extensions = (0, discovery_validation_js_1.closedRecord)(discovery.extensions, 'extensions', [
|
|
54
|
-
'connections',
|
|
58
|
+
'connections',
|
|
59
|
+
'credential_install',
|
|
60
|
+
'run_intent',
|
|
55
61
|
]);
|
|
56
62
|
if (extensions.connections === undefined) {
|
|
57
63
|
throw new discovery_errors_js_1.TargetDiscoveryError('extensions.connections is required');
|
|
58
64
|
}
|
|
59
65
|
const connections = (0, discovery_validation_js_1.closedRecord)(extensions.connections, 'extensions.connections', [
|
|
60
|
-
'kind',
|
|
66
|
+
'kind',
|
|
67
|
+
'base_url',
|
|
68
|
+
'route_templates',
|
|
61
69
|
]);
|
|
62
70
|
(0, discovery_validation_js_1.exact)(connections.kind, 'zerocloud.connections/v1', 'extensions.connections.kind');
|
|
63
71
|
(0, discovery_validation_js_1.sameOriginUrl)(connections.base_url, 'extensions.connections.base_url', origin);
|
|
64
|
-
const routes = (0, discovery_validation_js_1.closedRecord)(connections.route_templates, 'extensions.connections.route_templates', [
|
|
65
|
-
'list', 'create', 'update',
|
|
66
|
-
]);
|
|
72
|
+
const routes = (0, discovery_validation_js_1.closedRecord)(connections.route_templates, 'extensions.connections.route_templates', ['list', 'create', 'update']);
|
|
67
73
|
(0, route_template_js_1.routeTemplate)(routes.list, 'extensions.connections.route_templates.list', []);
|
|
68
74
|
(0, route_template_js_1.routeTemplate)(routes.create, 'extensions.connections.route_templates.create', []);
|
|
69
75
|
(0, route_template_js_1.routeTemplate)(routes.update, 'extensions.connections.route_templates.update', ['connection_id']);
|
|
70
|
-
return
|
|
76
|
+
return Object.freeze({
|
|
77
|
+
credentialInstall: (0, discovery_validation_js_1.parseCredentialInstall)(extensions.credential_install),
|
|
78
|
+
runIntent: (0, run_intent_discovery_js_1.parseRunIntent)(extensions.run_intent, origin),
|
|
79
|
+
});
|
|
71
80
|
}
|
|
72
81
|
function validateOAuthMetadata(metadata, origin, expected) {
|
|
73
82
|
const device = (0, discovery_validation_js_1.sameOriginUrl)(metadata.device_authorization_endpoint, 'OAuth metadata device_authorization_endpoint', origin);
|
|
@@ -85,7 +94,10 @@ function parseEndpoint(discovery, origin) {
|
|
|
85
94
|
(0, discovery_validation_js_1.exact)(binding.scope, 'organization', 'binding.scope');
|
|
86
95
|
(0, discovery_validation_js_1.exact)(binding.auth_location, 'authorization_header', 'binding.auth_location');
|
|
87
96
|
const endpoint = (0, discovery_validation_js_1.closedRecord)(discovery.endpoint, 'endpoint', ['url', 'capabilities']);
|
|
88
|
-
const capabilities = (0, discovery_validation_js_1.exactStringSet)(endpoint.capabilities, 'endpoint.capabilities', [
|
|
97
|
+
const capabilities = (0, discovery_validation_js_1.exactStringSet)(endpoint.capabilities, 'endpoint.capabilities', [
|
|
98
|
+
'exec',
|
|
99
|
+
'log_stream',
|
|
100
|
+
]);
|
|
89
101
|
const pagination = (0, discovery_validation_js_1.closedRecord)(discovery.pagination, 'pagination', [
|
|
90
102
|
'default_page_size',
|
|
91
103
|
'max_page_size',
|
|
@@ -119,7 +131,14 @@ function parseCapsule(discovery, origin) {
|
|
|
119
131
|
]);
|
|
120
132
|
(0, discovery_validation_js_1.exact)(capsule.name, 'openengine.capsules/v1', 'capsule_protocol.name');
|
|
121
133
|
(0, discovery_validation_js_1.exact)(capsule.major_version, 1, 'capsule_protocol.major_version');
|
|
122
|
-
const routes = (0, discovery_validation_js_1.closedRecord)(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
134
|
+
const routes = (0, discovery_validation_js_1.closedRecord)(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
135
|
+
'allocate',
|
|
136
|
+
'list',
|
|
137
|
+
'inspect',
|
|
138
|
+
'terminate',
|
|
139
|
+
'limits',
|
|
140
|
+
'access',
|
|
141
|
+
]);
|
|
123
142
|
const route = (name, variables) => (0, route_template_js_1.routeTemplate)(routes[name], `capsule_protocol.route_templates.${name}`, variables);
|
|
124
143
|
return Object.freeze({
|
|
125
144
|
baseUrl: (0, discovery_validation_js_1.sameOriginUrl)(capsule.base_url, 'capsule_protocol.base_url', origin),
|
|
@@ -145,7 +164,10 @@ function parseOAuth(discovery, origin) {
|
|
|
145
164
|
'audience',
|
|
146
165
|
]);
|
|
147
166
|
(0, discovery_validation_js_1.exact)(oauth.device_grant_type, 'urn:ietf:params:oauth:grant-type:device_code', 'oauth.device_grant_type');
|
|
148
|
-
(0, discovery_validation_js_1.exactStringSet)(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
167
|
+
(0, discovery_validation_js_1.exactStringSet)(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
168
|
+
'device_token',
|
|
169
|
+
'device_label',
|
|
170
|
+
]);
|
|
149
171
|
(0, discovery_validation_js_1.exact)(oauth.audience, 'capsule', 'oauth.audience');
|
|
150
172
|
return Object.freeze({
|
|
151
173
|
metadataUrl: (0, discovery_validation_js_1.sameOriginUrl)(oauth.metadata_url, 'oauth.metadata_url', origin),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TargetDiscoveryError } from './discovery-errors.mjs';
|
|
2
2
|
import { closedRecord, exact, exactStringSet, integer, parseCredentialInstall, sameOriginUrl, stringField, } from './discovery-validation.mjs';
|
|
3
|
+
import { parseRunIntent } from './run-intent-discovery.mjs';
|
|
3
4
|
import { routeTemplate } from './route-template.mjs';
|
|
4
5
|
export function parseAdapter(discovery) {
|
|
5
6
|
const adapter = closedRecord(discovery.adapter, 'adapter', ['name', 'major_version']);
|
|
@@ -15,14 +16,16 @@ export function parseAdapter(discovery) {
|
|
|
15
16
|
export function validateCachePolicy(discovery) {
|
|
16
17
|
const cache = closedRecord(discovery.cache_policy, 'cache_policy', ['control', 'discovery']);
|
|
17
18
|
exact(cache.control, 'no-store', 'cache_policy.control');
|
|
18
|
-
if (cache.discovery !== undefined &&
|
|
19
|
+
if (cache.discovery !== undefined &&
|
|
20
|
+
cache.discovery !== null &&
|
|
19
21
|
typeof cache.discovery !== 'string') {
|
|
20
22
|
throw new TargetDiscoveryError('cache_policy.discovery must be a string or null');
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
export function parseSizes(discovery) {
|
|
24
26
|
const sizes = closedRecord(discovery.sizes, 'sizes', ['catalog', 'default']);
|
|
25
|
-
if (!Array.isArray(sizes.catalog) ||
|
|
27
|
+
if (!Array.isArray(sizes.catalog) ||
|
|
28
|
+
sizes.catalog.length === 0 ||
|
|
26
29
|
new Set(sizes.catalog).size !== sizes.catalog.length ||
|
|
27
30
|
sizes.catalog.some((size) => !['tiny', 'small', 'standard', 'large'].includes(String(size)))) {
|
|
28
31
|
throw new TargetDiscoveryError('sizes.catalog contains an unsupported size');
|
|
@@ -36,26 +39,32 @@ export function parseSizes(discovery) {
|
|
|
36
39
|
});
|
|
37
40
|
}
|
|
38
41
|
export function parseExtensions(discovery, origin) {
|
|
39
|
-
if (discovery.extensions === undefined || discovery.extensions === null)
|
|
40
|
-
return null;
|
|
42
|
+
if (discovery.extensions === undefined || discovery.extensions === null) {
|
|
43
|
+
return Object.freeze({ credentialInstall: null, runIntent: null });
|
|
44
|
+
}
|
|
41
45
|
const extensions = closedRecord(discovery.extensions, 'extensions', [
|
|
42
|
-
'connections',
|
|
46
|
+
'connections',
|
|
47
|
+
'credential_install',
|
|
48
|
+
'run_intent',
|
|
43
49
|
]);
|
|
44
50
|
if (extensions.connections === undefined) {
|
|
45
51
|
throw new TargetDiscoveryError('extensions.connections is required');
|
|
46
52
|
}
|
|
47
53
|
const connections = closedRecord(extensions.connections, 'extensions.connections', [
|
|
48
|
-
'kind',
|
|
54
|
+
'kind',
|
|
55
|
+
'base_url',
|
|
56
|
+
'route_templates',
|
|
49
57
|
]);
|
|
50
58
|
exact(connections.kind, 'zerocloud.connections/v1', 'extensions.connections.kind');
|
|
51
59
|
sameOriginUrl(connections.base_url, 'extensions.connections.base_url', origin);
|
|
52
|
-
const routes = closedRecord(connections.route_templates, 'extensions.connections.route_templates', [
|
|
53
|
-
'list', 'create', 'update',
|
|
54
|
-
]);
|
|
60
|
+
const routes = closedRecord(connections.route_templates, 'extensions.connections.route_templates', ['list', 'create', 'update']);
|
|
55
61
|
routeTemplate(routes.list, 'extensions.connections.route_templates.list', []);
|
|
56
62
|
routeTemplate(routes.create, 'extensions.connections.route_templates.create', []);
|
|
57
63
|
routeTemplate(routes.update, 'extensions.connections.route_templates.update', ['connection_id']);
|
|
58
|
-
return
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
credentialInstall: parseCredentialInstall(extensions.credential_install),
|
|
66
|
+
runIntent: parseRunIntent(extensions.run_intent, origin),
|
|
67
|
+
});
|
|
59
68
|
}
|
|
60
69
|
export function validateOAuthMetadata(metadata, origin, expected) {
|
|
61
70
|
const device = sameOriginUrl(metadata.device_authorization_endpoint, 'OAuth metadata device_authorization_endpoint', origin);
|
|
@@ -73,7 +82,10 @@ export function parseEndpoint(discovery, origin) {
|
|
|
73
82
|
exact(binding.scope, 'organization', 'binding.scope');
|
|
74
83
|
exact(binding.auth_location, 'authorization_header', 'binding.auth_location');
|
|
75
84
|
const endpoint = closedRecord(discovery.endpoint, 'endpoint', ['url', 'capabilities']);
|
|
76
|
-
const capabilities = exactStringSet(endpoint.capabilities, 'endpoint.capabilities', [
|
|
85
|
+
const capabilities = exactStringSet(endpoint.capabilities, 'endpoint.capabilities', [
|
|
86
|
+
'exec',
|
|
87
|
+
'log_stream',
|
|
88
|
+
]);
|
|
77
89
|
const pagination = closedRecord(discovery.pagination, 'pagination', [
|
|
78
90
|
'default_page_size',
|
|
79
91
|
'max_page_size',
|
|
@@ -107,7 +119,14 @@ export function parseCapsule(discovery, origin) {
|
|
|
107
119
|
]);
|
|
108
120
|
exact(capsule.name, 'openengine.capsules/v1', 'capsule_protocol.name');
|
|
109
121
|
exact(capsule.major_version, 1, 'capsule_protocol.major_version');
|
|
110
|
-
const routes = closedRecord(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
122
|
+
const routes = closedRecord(capsule.route_templates, 'capsule_protocol.route_templates', [
|
|
123
|
+
'allocate',
|
|
124
|
+
'list',
|
|
125
|
+
'inspect',
|
|
126
|
+
'terminate',
|
|
127
|
+
'limits',
|
|
128
|
+
'access',
|
|
129
|
+
]);
|
|
111
130
|
const route = (name, variables) => routeTemplate(routes[name], `capsule_protocol.route_templates.${name}`, variables);
|
|
112
131
|
return Object.freeze({
|
|
113
132
|
baseUrl: sameOriginUrl(capsule.base_url, 'capsule_protocol.base_url', origin),
|
|
@@ -133,7 +152,10 @@ export function parseOAuth(discovery, origin) {
|
|
|
133
152
|
'audience',
|
|
134
153
|
]);
|
|
135
154
|
exact(oauth.device_grant_type, 'urn:ietf:params:oauth:grant-type:device_code', 'oauth.device_grant_type');
|
|
136
|
-
exactStringSet(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
155
|
+
exactStringSet(oauth.device_exchange_fields, 'oauth.device_exchange_fields', [
|
|
156
|
+
'device_token',
|
|
157
|
+
'device_label',
|
|
158
|
+
]);
|
|
137
159
|
exact(oauth.audience, 'capsule', 'oauth.audience');
|
|
138
160
|
return Object.freeze({
|
|
139
161
|
metadataUrl: sameOriginUrl(oauth.metadata_url, 'oauth.metadata_url', origin),
|
package/lib/target/discovery.cjs
CHANGED
|
@@ -33,52 +33,27 @@ const ROOT_FIELDS = [
|
|
|
33
33
|
'transport',
|
|
34
34
|
'extensions',
|
|
35
35
|
];
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await response.body?.cancel().catch(() => undefined);
|
|
47
|
-
throw new discovery_errors_js_1.TargetDiscoveryError('request changed target route or authority');
|
|
48
|
-
}
|
|
49
|
-
if (!response.ok) {
|
|
50
|
-
await response.body?.cancel().catch(() => undefined);
|
|
51
|
-
throw new discovery_errors_js_1.TargetDiscoveryError(`request failed with status ${response.status}`);
|
|
52
|
-
}
|
|
53
|
-
return (0, discovery_validation_js_1.record)(await readBoundedJson(response), 'response');
|
|
54
|
-
}
|
|
55
|
-
async function discoverTarget(targetUrl, http) {
|
|
56
|
-
const target = new URL(targetUrl);
|
|
57
|
-
const origin = target.origin;
|
|
58
|
-
const discovery = await fetchDocument(http, new URL(DISCOVERY_PATH, target).href);
|
|
36
|
+
const FLAGS = [
|
|
37
|
+
'capsule_allocate',
|
|
38
|
+
'capsule_read',
|
|
39
|
+
'capsule_terminate',
|
|
40
|
+
'capsule_access',
|
|
41
|
+
'connections_onboarding',
|
|
42
|
+
];
|
|
43
|
+
const SIZE_ERROR = 'response exceeds the size limit';
|
|
44
|
+
const JSON_ERROR = 'response is not valid UTF-8 JSON';
|
|
45
|
+
function parseDiscoveryDocument(discovery, origin) {
|
|
59
46
|
(0, discovery_validation_js_1.exact)(discovery.kind, 'openengine.hosted-target/v1', 'kind');
|
|
60
47
|
const adapter = (0, discovery_sections_js_1.parseAdapter)(discovery);
|
|
61
48
|
const endpoint = (0, discovery_sections_js_1.parseEndpoint)(discovery, origin);
|
|
62
49
|
const capsule = (0, discovery_sections_js_1.parseCapsule)(discovery, origin);
|
|
63
50
|
const oauth = (0, discovery_sections_js_1.parseOAuth)(discovery, origin);
|
|
64
51
|
(0, discovery_validation_js_1.exact)(discovery.organization_binding, 'device_approval', 'organization_binding');
|
|
65
|
-
const capabilityFlags = (0, discovery_validation_js_1.exactStringSet)(discovery.capability_flags, 'capability_flags',
|
|
66
|
-
'capsule_allocate',
|
|
67
|
-
'capsule_read',
|
|
68
|
-
'capsule_terminate',
|
|
69
|
-
'capsule_access',
|
|
70
|
-
'connections_onboarding',
|
|
71
|
-
]);
|
|
52
|
+
const capabilityFlags = (0, discovery_validation_js_1.exactStringSet)(discovery.capability_flags, 'capability_flags', FLAGS);
|
|
72
53
|
const sizes = (0, discovery_sections_js_1.parseSizes)(discovery);
|
|
73
54
|
const session = (0, discovery_sections_js_1.parseSession)(discovery);
|
|
74
55
|
const transport = (0, discovery_sections_js_1.parseTransport)(discovery);
|
|
75
|
-
const
|
|
76
|
-
const metadata = await fetchDocument(http, oauth.metadataUrl);
|
|
77
|
-
(0, discovery_sections_js_1.validateOAuthMetadata)(metadata, origin, [
|
|
78
|
-
oauth.deviceAuthorizationEndpoint,
|
|
79
|
-
oauth.tokenEndpoint,
|
|
80
|
-
oauth.revocationEndpoint,
|
|
81
|
-
]);
|
|
56
|
+
const extensions = (0, discovery_sections_js_1.parseExtensions)(discovery, origin);
|
|
82
57
|
const additional = Object.freeze(Object.fromEntries(Object.entries(discovery).filter(([key]) => !ROOT_FIELDS.includes(key))));
|
|
83
58
|
return Object.freeze({
|
|
84
59
|
origin,
|
|
@@ -92,10 +67,24 @@ async function discoverTarget(targetUrl, http) {
|
|
|
92
67
|
capsule,
|
|
93
68
|
transport,
|
|
94
69
|
capabilityFlags,
|
|
95
|
-
credentialInstall,
|
|
70
|
+
credentialInstall: extensions.credentialInstall,
|
|
71
|
+
runIntent: extensions.runIntent,
|
|
96
72
|
additional,
|
|
97
73
|
});
|
|
98
74
|
}
|
|
75
|
+
async function discoverTarget(targetUrl, http) {
|
|
76
|
+
const target = new URL(targetUrl);
|
|
77
|
+
const origin = target.origin;
|
|
78
|
+
const discovery = await fetchDocument(http, new URL(DISCOVERY_PATH, target).href);
|
|
79
|
+
const descriptor = parseDiscoveryDocument(discovery, origin);
|
|
80
|
+
const metadata = await fetchDocument(http, descriptor.oauth.metadataUrl);
|
|
81
|
+
(0, discovery_sections_js_1.validateOAuthMetadata)(metadata, origin, [
|
|
82
|
+
descriptor.oauth.deviceAuthorizationEndpoint,
|
|
83
|
+
descriptor.oauth.tokenEndpoint,
|
|
84
|
+
descriptor.oauth.revocationEndpoint,
|
|
85
|
+
]);
|
|
86
|
+
return descriptor;
|
|
87
|
+
}
|
|
99
88
|
async function discoverTargetSessionEndpoints(targetUrl, http) {
|
|
100
89
|
const descriptor = await discoverTarget(targetUrl, http);
|
|
101
90
|
return Object.freeze({
|
|
@@ -110,3 +99,25 @@ async function discoverTargetSessionEndpoints(targetUrl, http) {
|
|
|
110
99
|
descriptor,
|
|
111
100
|
});
|
|
112
101
|
}
|
|
102
|
+
function boundedResponseError(kind) {
|
|
103
|
+
return new discovery_errors_js_1.TargetDiscoveryError(kind === 'size' ? SIZE_ERROR : JSON_ERROR);
|
|
104
|
+
}
|
|
105
|
+
async function readBoundedJson(response) {
|
|
106
|
+
return (0, bounded_response_js_1.readBoundedResponseJson)(response, MAX_DISCOVERY_BYTES, boundedResponseError);
|
|
107
|
+
}
|
|
108
|
+
async function fetchDocument(http, url) {
|
|
109
|
+
const response = await http.fetch(url, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
headers: { Accept: 'application/json' },
|
|
112
|
+
redirect: 'error',
|
|
113
|
+
});
|
|
114
|
+
if (response.url && new URL(response.url).href !== url) {
|
|
115
|
+
await response.body?.cancel().catch(() => undefined);
|
|
116
|
+
throw new discovery_errors_js_1.TargetDiscoveryError('request changed target route or authority');
|
|
117
|
+
}
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
await response.body?.cancel().catch(() => undefined);
|
|
120
|
+
throw new discovery_errors_js_1.TargetDiscoveryError(`request failed with status ${response.status}`);
|
|
121
|
+
}
|
|
122
|
+
return (0, discovery_validation_js_1.record)(await readBoundedJson(response), 'response');
|
|
123
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { HttpTransport } from './device-flow.js';
|
|
2
2
|
import type { RouteTemplate } from './route-template.js';
|
|
3
3
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
4
|
+
import type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
4
5
|
export type { CredentialInstallDescriptor } from './discovery-validation.js';
|
|
6
|
+
export type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
5
7
|
export { TargetDiscoveryError } from './discovery-errors.js';
|
|
6
8
|
export { expandRoute, type RouteTemplate } from './route-template.js';
|
|
7
9
|
declare const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
@@ -56,6 +58,7 @@ export interface TargetDiscoveryDescriptor {
|
|
|
56
58
|
};
|
|
57
59
|
readonly capabilityFlags: readonly string[];
|
|
58
60
|
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
61
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
59
62
|
readonly additional: Readonly<Record<string, unknown>>;
|
|
60
63
|
}
|
|
61
64
|
/** Compatibility projection. New callers should retain the complete descriptor. */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { HttpTransport } from './device-flow.js';
|
|
2
2
|
import type { RouteTemplate } from './route-template.js';
|
|
3
3
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
4
|
+
import type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
4
5
|
export type { CredentialInstallDescriptor } from './discovery-validation.js';
|
|
6
|
+
export type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
5
7
|
export { TargetDiscoveryError } from './discovery-errors.js';
|
|
6
8
|
export { expandRoute, type RouteTemplate } from './route-template.js';
|
|
7
9
|
declare const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
@@ -56,6 +58,7 @@ export interface TargetDiscoveryDescriptor {
|
|
|
56
58
|
};
|
|
57
59
|
readonly capabilityFlags: readonly string[];
|
|
58
60
|
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
61
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
59
62
|
readonly additional: Readonly<Record<string, unknown>>;
|
|
60
63
|
}
|
|
61
64
|
/** Compatibility projection. New callers should retain the complete descriptor. */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { HttpTransport } from './device-flow.js';
|
|
2
2
|
import type { RouteTemplate } from './route-template.js';
|
|
3
3
|
import { type CredentialInstallDescriptor } from './discovery-validation.js';
|
|
4
|
+
import type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
4
5
|
export type { CredentialInstallDescriptor } from './discovery-validation.js';
|
|
6
|
+
export type { RunIntentDescriptor } from './run-intent-discovery.js';
|
|
5
7
|
export { TargetDiscoveryError } from './discovery-errors.js';
|
|
6
8
|
export { expandRoute, type RouteTemplate } from './route-template.js';
|
|
7
9
|
declare const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
@@ -56,6 +58,7 @@ export interface TargetDiscoveryDescriptor {
|
|
|
56
58
|
};
|
|
57
59
|
readonly capabilityFlags: readonly string[];
|
|
58
60
|
readonly credentialInstall: CredentialInstallDescriptor | null;
|
|
61
|
+
readonly runIntent: RunIntentDescriptor | null;
|
|
59
62
|
readonly additional: Readonly<Record<string, unknown>>;
|
|
60
63
|
}
|
|
61
64
|
/** Compatibility projection. New callers should retain the complete descriptor. */
|