@the-open-engine/zeroshot 6.29.0 → 6.29.1
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/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/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.js +4 -10
- package/lib/cluster-worker/profiles.js +1 -42
- 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 +4 -7
- 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/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,33 @@
|
|
|
1
|
+
if (!Object.prototype.hasOwnProperty.call(Symbol, 'asyncDispose')) {
|
|
2
|
+
Object.defineProperty(Symbol, 'asyncDispose', {
|
|
3
|
+
configurable: false, enumerable: false,
|
|
4
|
+
value: Symbol.for('Symbol.asyncDispose'), writable: false,
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ConnectionState = 'OPEN' | 'CLOSING' | 'CLOSED';
|
|
9
|
+
export const CONNECTION_TRANSITIONS: Readonly<Record<ConnectionState, readonly ConnectionState[]>> = Object.freeze({
|
|
10
|
+
OPEN: Object.freeze(['CLOSING'] as const),
|
|
11
|
+
CLOSING: Object.freeze(['CLOSED'] as const),
|
|
12
|
+
CLOSED: Object.freeze([] as const),
|
|
13
|
+
});
|
|
14
|
+
export const PROTOCOL_DIAGNOSTIC_CAPACITY = 128;
|
|
15
|
+
export interface ConnectionCloseSnapshot {
|
|
16
|
+
readonly code: number | null;
|
|
17
|
+
readonly reason: null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Deferred<T> = {
|
|
21
|
+
readonly promise: Promise<T>;
|
|
22
|
+
readonly resolve: (value: T) => void;
|
|
23
|
+
readonly reject: (reason: unknown) => void;
|
|
24
|
+
};
|
|
25
|
+
export function deferred<T>(): Deferred<T> {
|
|
26
|
+
let resolve!: (value: T) => void;
|
|
27
|
+
let reject!: (reason: unknown) => void;
|
|
28
|
+
const promise = new Promise<T>((onResolve, onReject) => {
|
|
29
|
+
resolve = onResolve;
|
|
30
|
+
reject = onReject;
|
|
31
|
+
});
|
|
32
|
+
return { promise, resolve, reject };
|
|
33
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { FrameRecord } from './frames.js';
|
|
2
|
+
import type { BoundedQueue } from './queue.js';
|
|
3
|
+
import type { ClusterMethod } from './generated/protocol.js';
|
|
4
|
+
|
|
5
|
+
export interface CallOptions {
|
|
6
|
+
readonly signal?: AbortSignal;
|
|
7
|
+
readonly requestTimeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export type SubscriptionKind = 'watch' | 'logs' | 'agent/attach';
|
|
10
|
+
export type SubscriptionRegistration = {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly kind: SubscriptionKind;
|
|
13
|
+
readonly queue: BoundedQueue<FrameRecord>;
|
|
14
|
+
overflowed: boolean;
|
|
15
|
+
cancelSent: boolean;
|
|
16
|
+
abortHandler?: () => void;
|
|
17
|
+
abortSignal?: AbortSignal;
|
|
18
|
+
};
|
|
19
|
+
export type EstablishedSubscription<R> = {
|
|
20
|
+
readonly result: R;
|
|
21
|
+
readonly registration: SubscriptionRegistration;
|
|
22
|
+
};
|
|
23
|
+
export type PendingEntry = {
|
|
24
|
+
readonly id: string; readonly method: ClusterMethod; readonly expectedId: string;
|
|
25
|
+
readonly resolve: (value: unknown) => void; readonly reject: (reason: unknown) => void;
|
|
26
|
+
readonly subscriptionKind?: SubscriptionKind; settled: boolean;
|
|
27
|
+
abortHandler?: () => void; signal?: AbortSignal; timeout?: ReturnType<typeof setTimeout>;
|
|
28
|
+
};
|
|
@@ -13,68 +13,32 @@ import { BoundedQueue } from './queue.js';
|
|
|
13
13
|
import { addSocketListener } from './socket.js';
|
|
14
14
|
import type { WebSocketLike } from './socket.js';
|
|
15
15
|
import { assertDefinition, assertMethodResult } from './validators.js';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return retained.join('');
|
|
43
|
-
}
|
|
44
|
-
export interface CallOptions { readonly signal?: AbortSignal; readonly requestTimeoutMs?: number; }
|
|
45
|
-
|
|
46
|
-
type Deferred<T> = {
|
|
47
|
-
readonly promise: Promise<T>;
|
|
48
|
-
readonly resolve: (value: T) => void;
|
|
49
|
-
readonly reject: (reason: unknown) => void;
|
|
50
|
-
};
|
|
51
|
-
function deferred<T>(): Deferred<T> {
|
|
52
|
-
let resolve!: (value: T) => void; let reject!: (reason: unknown) => void;
|
|
53
|
-
const promise = new Promise<T>((onResolve, onReject) => {
|
|
54
|
-
resolve = onResolve; reject = onReject;
|
|
55
|
-
});
|
|
56
|
-
return { promise, resolve, reject };
|
|
57
|
-
}
|
|
58
|
-
export type SubscriptionKind = 'watch' | 'logs' | 'agent/attach';
|
|
59
|
-
export type SubscriptionRegistration = {
|
|
60
|
-
readonly id: string;
|
|
61
|
-
readonly kind: SubscriptionKind;
|
|
62
|
-
readonly queue: BoundedQueue<FrameRecord>;
|
|
63
|
-
overflowed: boolean;
|
|
64
|
-
cancelSent: boolean;
|
|
65
|
-
abortHandler?: () => void;
|
|
66
|
-
abortSignal?: AbortSignal;
|
|
67
|
-
};
|
|
68
|
-
export type EstablishedSubscription<R> = {
|
|
69
|
-
readonly result: R;
|
|
70
|
-
readonly registration: SubscriptionRegistration;
|
|
71
|
-
};
|
|
72
|
-
type PendingEntry = {
|
|
73
|
-
readonly id: string; readonly method: ClusterMethod; readonly expectedId: string;
|
|
74
|
-
readonly resolve: (value: unknown) => void; readonly reject: (reason: unknown) => void;
|
|
75
|
-
readonly subscriptionKind?: SubscriptionKind; settled: boolean;
|
|
76
|
-
abortHandler?: () => void; signal?: AbortSignal; timeout?: ReturnType<typeof setTimeout>;
|
|
77
|
-
};
|
|
16
|
+
import {
|
|
17
|
+
CONNECTION_TRANSITIONS,
|
|
18
|
+
PROTOCOL_DIAGNOSTIC_CAPACITY,
|
|
19
|
+
deferred,
|
|
20
|
+
type ConnectionCloseSnapshot,
|
|
21
|
+
type ConnectionState,
|
|
22
|
+
} from './connection-state.js';
|
|
23
|
+
export {
|
|
24
|
+
CONNECTION_TRANSITIONS,
|
|
25
|
+
PROTOCOL_DIAGNOSTIC_CAPACITY,
|
|
26
|
+
type ConnectionCloseSnapshot,
|
|
27
|
+
type ConnectionState,
|
|
28
|
+
} from './connection-state.js';
|
|
29
|
+
import type {
|
|
30
|
+
CallOptions,
|
|
31
|
+
EstablishedSubscription,
|
|
32
|
+
PendingEntry,
|
|
33
|
+
SubscriptionKind,
|
|
34
|
+
SubscriptionRegistration,
|
|
35
|
+
} from './connection-types.js';
|
|
36
|
+
export type {
|
|
37
|
+
CallOptions,
|
|
38
|
+
EstablishedSubscription,
|
|
39
|
+
SubscriptionKind,
|
|
40
|
+
SubscriptionRegistration,
|
|
41
|
+
} from './connection-types.js';
|
|
78
42
|
|
|
79
43
|
export class Connection {
|
|
80
44
|
#state: ConnectionState = 'OPEN'; #sequence = 1;
|
|
@@ -85,7 +49,9 @@ export class Connection {
|
|
|
85
49
|
readonly #ownedSubscriptions = new WeakSet<SubscriptionRegistration>();
|
|
86
50
|
#closePromise?: Promise<void>;
|
|
87
51
|
#closeCode: number | undefined;
|
|
88
|
-
#
|
|
52
|
+
readonly #closedCompletion = deferred<ConnectionCloseSnapshot>();
|
|
53
|
+
readonly closed: Promise<ConnectionCloseSnapshot> = this.#closedCompletion.promise;
|
|
54
|
+
#closeSnapshot: ConnectionCloseSnapshot | undefined;
|
|
89
55
|
readonly closeDiagnostics: unknown[] = [];
|
|
90
56
|
readonly protocolDiagnostics: ClusterProtocolError[] = [];
|
|
91
57
|
|
|
@@ -103,7 +69,8 @@ export class Connection {
|
|
|
103
69
|
get pendingSize(): number { return this.#pending.size; }
|
|
104
70
|
get subscriptionCount(): number { return this.#subscriptions.size; }
|
|
105
71
|
get closeCode(): number | undefined { return this.#closeCode; }
|
|
106
|
-
get closeReason():
|
|
72
|
+
get closeReason(): undefined { return undefined; }
|
|
73
|
+
get closeSnapshot(): ConnectionCloseSnapshot | undefined { return this.#closeSnapshot; }
|
|
107
74
|
call<M extends UnaryClusterMethod>(method: M, params: ClusterMethodParams[M], options: CallOptions = {}): Promise<ClusterMethodResults[M]> {
|
|
108
75
|
if (!(UNARY_METHODS as readonly string[]).includes(method)) {
|
|
109
76
|
throw new ClusterConfigError(`${method} is a subscription method`, 'INVALID_METHOD');
|
|
@@ -289,12 +256,9 @@ export class Connection {
|
|
|
289
256
|
const first = args[0];
|
|
290
257
|
if (typeof first === 'number') {
|
|
291
258
|
this.#closeCode = first;
|
|
292
|
-
const raw = args.length > 1 ? String(args[1]) : undefined;
|
|
293
|
-
this.#closeReason = raw === undefined ? undefined : boundedCloseReason(raw);
|
|
294
259
|
} else if (first !== null && typeof first === 'object') {
|
|
295
|
-
const event = first as { code?: unknown
|
|
260
|
+
const event = first as { code?: unknown };
|
|
296
261
|
if (typeof event.code === 'number') this.#closeCode = event.code;
|
|
297
|
-
if (typeof event.reason === 'string') this.#closeReason = boundedCloseReason(event.reason);
|
|
298
262
|
}
|
|
299
263
|
}
|
|
300
264
|
#startClose(sendCancels: boolean): Promise<void> {
|
|
@@ -319,6 +283,11 @@ export class Connection {
|
|
|
319
283
|
try { remove(); } catch (error) { this.recordDiagnostic(error); }
|
|
320
284
|
}
|
|
321
285
|
this.#transition('CLOSED');
|
|
286
|
+
this.#closeSnapshot = Object.freeze({
|
|
287
|
+
code: this.#closeCode ?? null,
|
|
288
|
+
reason: null,
|
|
289
|
+
});
|
|
290
|
+
this.#closedCompletion.resolve(this.#closeSnapshot);
|
|
322
291
|
}
|
|
323
292
|
#transition(to: ConnectionState): void {
|
|
324
293
|
if (!CONNECTION_TRANSITIONS[this.#state].includes(to)) throw new ClusterInternalError(`illegal connection transition ${this.#state} -> ${to}`, 'ILLEGAL_STATE_TRANSITION');
|
package/src/cluster/errors.ts
CHANGED
|
@@ -15,6 +15,11 @@ export class ClusterTransportError extends ClusterError {}
|
|
|
15
15
|
export class ClusterTimeoutError extends ClusterError {}
|
|
16
16
|
export class ClusterRequestError extends ClusterError {}
|
|
17
17
|
|
|
18
|
+
export class ClusterUpgradeError extends ClusterTransportError {
|
|
19
|
+
constructor(readonly status: number) {
|
|
20
|
+
super(`WebSocket upgrade rejected with HTTP ${status}`, 'UPGRADE_REJECTED');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
18
23
|
export function requestAbortError(method: string): DOMException {
|
|
19
24
|
return new DOMException(
|
|
20
25
|
`${method} aborted locally; the server may still have committed this request`,
|
package/src/cluster/index.ts
CHANGED
|
@@ -10,14 +10,16 @@ export {
|
|
|
10
10
|
ClusterStateError,
|
|
11
11
|
ClusterTimeoutError,
|
|
12
12
|
ClusterTransportError,
|
|
13
|
+
ClusterUpgradeError,
|
|
13
14
|
} from './errors.js';
|
|
14
15
|
export { assertGraphProfile, assertGraphProfileSupported, assertGraphSpec } from './validators.js';
|
|
15
16
|
export * from './payload-value.js';
|
|
16
17
|
export * from './json-source.js';
|
|
17
|
-
export {
|
|
18
|
+
export { CONNECTION_TRANSITIONS, PROTOCOL_DIAGNOSTIC_CAPACITY, Connection } from './connection.js';
|
|
18
19
|
export type {
|
|
19
20
|
CallOptions,
|
|
20
21
|
ConnectionState,
|
|
22
|
+
ConnectionCloseSnapshot,
|
|
21
23
|
} from './connection.js';
|
|
22
24
|
export type { WebSocketLike } from './socket.js';
|
|
23
25
|
export {
|
|
@@ -3,6 +3,7 @@ import { MAX_FRAME_BYTES } from './generated/protocol.js';
|
|
|
3
3
|
|
|
4
4
|
export const MAX_REQUEST_BYTES = MAX_FRAME_BYTES;
|
|
5
5
|
|
|
6
|
+
/** Decode one already-bounded request body with strict UTF-8 and JSON handling. */
|
|
6
7
|
export function decodeBoundedJson(bytes: Uint8Array): unknown {
|
|
7
8
|
if (bytes.length > MAX_REQUEST_BYTES) {
|
|
8
9
|
throw new ClusterRequestError(
|
|
@@ -65,6 +65,7 @@ function evaluate(type: PayloadType, value: unknown, path: string): InternalIssu
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/** Return the first deterministic schema issue without retaining the input value. */
|
|
68
69
|
export function firstInputValidationIssue(
|
|
69
70
|
type: PayloadType,
|
|
70
71
|
value: unknown,
|
package/src/cluster/socket.ts
CHANGED
|
@@ -4,6 +4,7 @@ export interface WebSocketLike {
|
|
|
4
4
|
readonly readyState: number;
|
|
5
5
|
send(data: string, callback?: (error?: Error) => void): void | Promise<void>;
|
|
6
6
|
close(code?: number, reason?: string): void | Promise<void>;
|
|
7
|
+
terminate?(): void;
|
|
7
8
|
addEventListener?(type: string, listener: (...args: unknown[]) => void): void;
|
|
8
9
|
removeEventListener?(type: string, listener: (...args: unknown[]) => void): void;
|
|
9
10
|
on?(type: string, listener: (...args: unknown[]) => void): void;
|
|
@@ -29,3 +30,15 @@ export function addSocketListener(
|
|
|
29
30
|
'INVALID_WEBSOCKET',
|
|
30
31
|
);
|
|
31
32
|
}
|
|
33
|
+
|
|
34
|
+
export function addSocketEmitterListener(
|
|
35
|
+
socket: WebSocketLike,
|
|
36
|
+
type: string,
|
|
37
|
+
listener: (...args: unknown[]) => void,
|
|
38
|
+
): () => void {
|
|
39
|
+
if (socket.on) {
|
|
40
|
+
socket.on(type, listener);
|
|
41
|
+
return () => (socket.off ?? socket.removeListener)?.call(socket, type, listener);
|
|
42
|
+
}
|
|
43
|
+
return addSocketListener(socket, type, listener);
|
|
44
|
+
}
|
|
@@ -22,6 +22,11 @@ export interface Subscription<T> extends AsyncIterator<SubscriptionItem<T>>, Asy
|
|
|
22
22
|
readonly retainedCount: number;
|
|
23
23
|
cancel(): Promise<void>;
|
|
24
24
|
}
|
|
25
|
+
export interface WatchSubscription {
|
|
26
|
+
readonly result: WatchResult;
|
|
27
|
+
readonly stream: WatchSubscriptionStream;
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
|
|
26
31
|
type FrameParser<T> = (frame: FrameRecord) => SubscriptionItem<T>;
|
|
27
32
|
class SubscriptionStream<T> implements Subscription<T> {
|
|
@@ -198,13 +203,13 @@ export class WatchSubscriptionStream implements AsyncIterator<WatchSubscriptionI
|
|
|
198
203
|
await this.#terminate(true); throw error;
|
|
199
204
|
}
|
|
200
205
|
cancel(): Promise<void> { return this.#terminate(true); }
|
|
201
|
-
reconnect(freshConnection: Connection): Promise<
|
|
206
|
+
reconnect(freshConnection: Connection): Promise<WatchSubscription> {
|
|
202
207
|
if (this.#reconnectConsumed) {
|
|
203
208
|
throw new ClusterStateError('watch stream reconnect is one-shot', 'RECONNECT_CONSUMED');
|
|
204
209
|
}
|
|
205
210
|
this.#reconnectConsumed = true; return this.#reconnectOn(freshConnection);
|
|
206
211
|
}
|
|
207
|
-
async #reconnectOn(freshConnection: Connection): Promise<
|
|
212
|
+
async #reconnectOn(freshConnection: Connection): Promise<WatchSubscription> {
|
|
208
213
|
await this.#terminate(true);
|
|
209
214
|
try {
|
|
210
215
|
const runId = this.#runId; const fromCursor = this.#lastDelivered;
|
|
@@ -64,6 +64,7 @@ function assertRequestDefinition(definition: string, value: unknown, code: strin
|
|
|
64
64
|
throw new ClusterRequestError(`${definition} validation failed: ${details}`, code);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/** Validate an execution graph against the frozen cluster protocol schema. */
|
|
67
68
|
export function assertGraphSpec(value: unknown): asserts value is GraphSpec {
|
|
68
69
|
assertRequestDefinition('GraphSpec', value, 'INVALID_GRAPH');
|
|
69
70
|
}
|
package/src/cluster/ws.d.ts
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ClusterConfigError } from '../cluster/index.js';
|
|
2
|
+
import type { HostedAccess } from './types.js';
|
|
3
|
+
|
|
4
|
+
const LOOPBACK_HOSTS: Readonly<Record<string, true>> = Object.freeze({
|
|
5
|
+
'127.0.0.1': true,
|
|
6
|
+
'::1': true,
|
|
7
|
+
'[::1]': true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
function parseCanonicalUrl(value: string, message: string, code: string): URL {
|
|
11
|
+
try {
|
|
12
|
+
if (/[\u0000-\u0020\u007f]/.test(value)) throw new TypeError('unsafe URL code point');
|
|
13
|
+
const url = new URL(value);
|
|
14
|
+
if (url.href !== value && url.origin !== value) throw new TypeError('non-canonical URL');
|
|
15
|
+
return url;
|
|
16
|
+
} catch {
|
|
17
|
+
throw new ClusterConfigError(message, code);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hasOriginSuffix(url: URL): boolean {
|
|
22
|
+
return Boolean(
|
|
23
|
+
url.username ||
|
|
24
|
+
url.password ||
|
|
25
|
+
url.pathname !== '/' ||
|
|
26
|
+
url.search ||
|
|
27
|
+
url.hash,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function normalizedAuthority(value: string): string {
|
|
32
|
+
const message = 'targetAuthority must be an HTTPS or literal-loopback HTTP origin';
|
|
33
|
+
const url = parseCanonicalUrl(value, message, 'INVALID_TARGET_AUTHORITY');
|
|
34
|
+
const loopbackHttp = url.protocol === 'http:' && LOOPBACK_HOSTS[url.hostname] === true;
|
|
35
|
+
if ((url.protocol !== 'https:' && !loopbackHttp) || hasOriginSuffix(url) ||
|
|
36
|
+
value !== url.origin) {
|
|
37
|
+
throw new ClusterConfigError(message, 'INVALID_TARGET_AUTHORITY');
|
|
38
|
+
}
|
|
39
|
+
return url.origin;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function accessAuthorityMatches(endpoint: URL, target: URL): boolean {
|
|
43
|
+
const expectedProtocol = target.protocol === 'http:' ? 'ws:' : 'wss:';
|
|
44
|
+
return (
|
|
45
|
+
endpoint.protocol === expectedProtocol &&
|
|
46
|
+
endpoint.host === target.host &&
|
|
47
|
+
!endpoint.username &&
|
|
48
|
+
!endpoint.password &&
|
|
49
|
+
!endpoint.search &&
|
|
50
|
+
!endpoint.hash
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function validateHostedAccess(access: HostedAccess, targetAuthority: string): void {
|
|
55
|
+
const endpoint = parseCanonicalUrl(
|
|
56
|
+
access.websocketUrl,
|
|
57
|
+
'access endpoint must be an absolute target WebSocket URL',
|
|
58
|
+
'INVALID_ACCESS_ENDPOINT',
|
|
59
|
+
);
|
|
60
|
+
if (endpoint.href !== access.websocketUrl ||
|
|
61
|
+
!accessAuthorityMatches(endpoint, new URL(targetAuthority))) {
|
|
62
|
+
throw new ClusterConfigError(
|
|
63
|
+
'access endpoint must remain on the exact target authority',
|
|
64
|
+
'INVALID_ACCESS_ENDPOINT',
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (
|
|
68
|
+
access.protocol !== 'openengine.cluster/v1' ||
|
|
69
|
+
access.tokenType !== 'Bearer' ||
|
|
70
|
+
access.accessToken.length === 0
|
|
71
|
+
) {
|
|
72
|
+
throw new ClusterConfigError(
|
|
73
|
+
'access grant does not match the hosted session contract',
|
|
74
|
+
'INVALID_ACCESS_GRANT',
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
ClusterConfigError,
|
|
3
|
+
ClusterUpgradeError,
|
|
4
|
+
connectInitialized,
|
|
5
|
+
type ServerCapabilities,
|
|
6
|
+
type GraphProfile,
|
|
7
|
+
} from '../cluster/index.js';
|
|
8
|
+
import type {
|
|
9
|
+
HostedAccess,
|
|
10
|
+
HostedSessionInit,
|
|
11
|
+
HostedWatch,
|
|
12
|
+
HostedWatchOptions,
|
|
13
|
+
InitializedSession,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
import { normalizedAuthority, validateHostedAccess } from './authority.js';
|
|
16
|
+
import { HostedAuthenticationError } from './errors.js';
|
|
17
|
+
import { ReconnectingHostedWatch } from './reconnecting-watch.js';
|
|
18
|
+
export {
|
|
19
|
+
HostedAuthenticationError,
|
|
20
|
+
HostedAuthorizationError,
|
|
21
|
+
HostedTransportUncertainError,
|
|
22
|
+
} from './errors.js';
|
|
23
|
+
|
|
5
24
|
|
|
6
25
|
function combineSignals(signals: Array<AbortSignal | undefined>): AbortSignal | undefined {
|
|
7
|
-
const defined = signals.filter((
|
|
26
|
+
const defined = signals.filter((signal): signal is AbortSignal => signal !== undefined);
|
|
8
27
|
if (defined.length === 0) return undefined;
|
|
9
28
|
if (defined.length === 1) return defined[0];
|
|
10
29
|
return AbortSignal.any(defined);
|
|
11
30
|
}
|
|
12
31
|
|
|
13
32
|
export class HostedSessionCoordinator {
|
|
14
|
-
readonly #
|
|
15
|
-
readonly #
|
|
33
|
+
readonly #init: HostedSessionInit;
|
|
34
|
+
readonly #targetAuthority: string;
|
|
16
35
|
readonly #clock: { now(): number };
|
|
17
36
|
readonly #closeController = new AbortController();
|
|
37
|
+
readonly #sessions = new Set<InitializedSession>();
|
|
18
38
|
#referenceCapabilities: ServerCapabilities | undefined;
|
|
19
39
|
#closed = false;
|
|
20
40
|
|
|
21
41
|
constructor(init: HostedSessionInit) {
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
if (init.capsuleId.length === 0)
|
|
43
|
+
throw new ClusterConfigError('capsuleId must not be empty', 'INVALID_CAPSULE_ID');
|
|
44
|
+
this.#init = init;
|
|
45
|
+
this.#targetAuthority = normalizedAuthority(init.targetAuthority);
|
|
24
46
|
this.#clock = init.clock ?? Date;
|
|
25
47
|
}
|
|
26
48
|
|
|
@@ -34,72 +56,107 @@ export class HostedSessionCoordinator {
|
|
|
34
56
|
async replace(signal?: AbortSignal): Promise<InitializedSession> {
|
|
35
57
|
this.#requireNotClosed();
|
|
36
58
|
const session = await this.#createSession(signal);
|
|
37
|
-
|
|
38
|
-
|
|
59
|
+
try {
|
|
60
|
+
if (this.#referenceCapabilities !== undefined) {
|
|
61
|
+
this.#verifyCapabilities(
|
|
62
|
+
this.#referenceCapabilities,
|
|
63
|
+
session.initializeResult.capabilities
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return session;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
await session.connection.close();
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async watch(options: HostedWatchOptions): Promise<HostedWatch> {
|
|
74
|
+
const session = await this.open(options.signal);
|
|
75
|
+
try {
|
|
76
|
+
const subscription = await session.client.watch(
|
|
77
|
+
options.params,
|
|
78
|
+
options.signal === undefined ? {} : { signal: options.signal }
|
|
79
|
+
);
|
|
80
|
+
const hosted = new ReconnectingHostedWatch(
|
|
81
|
+
(replacementSignal) => this.replace(replacementSignal),
|
|
82
|
+
session,
|
|
83
|
+
subscription,
|
|
84
|
+
options.signal,
|
|
85
|
+
);
|
|
86
|
+
options.signal?.addEventListener(
|
|
87
|
+
'abort',
|
|
88
|
+
() => {
|
|
89
|
+
void hosted.cancel().catch(() => undefined);
|
|
90
|
+
},
|
|
91
|
+
{ once: true }
|
|
92
|
+
);
|
|
93
|
+
if (options.signal?.aborted) {
|
|
94
|
+
await hosted.cancel();
|
|
95
|
+
throw options.signal.reason ?? new DOMException('hosted watch aborted', 'AbortError');
|
|
96
|
+
}
|
|
97
|
+
return hosted;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
await session.connection.close();
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
39
102
|
}
|
|
40
103
|
|
|
41
|
-
renewalDeadline(access:
|
|
104
|
+
renewalDeadline(access: HostedAccess, receivedAt: number): number {
|
|
42
105
|
const expiresAt = Date.parse(access.expiresAt);
|
|
43
|
-
if (Number.
|
|
44
|
-
throw new ClusterConfigError(
|
|
106
|
+
if (!Number.isFinite(expiresAt) || expiresAt <= receivedAt) {
|
|
107
|
+
throw new ClusterConfigError(
|
|
108
|
+
'access expiry must be a future RFC 3339 timestamp',
|
|
109
|
+
'INVALID_ACCESS_EXPIRY'
|
|
110
|
+
);
|
|
45
111
|
}
|
|
46
112
|
const lifetime = expiresAt - receivedAt;
|
|
47
|
-
|
|
113
|
+
const lead = Math.max(5_000, Math.min(60_000, Math.floor(lifetime * 0.1)));
|
|
114
|
+
return Math.max(receivedAt, expiresAt - lead);
|
|
48
115
|
}
|
|
49
116
|
|
|
50
117
|
async close(): Promise<void> {
|
|
118
|
+
if (this.#closed) return;
|
|
51
119
|
this.#closed = true;
|
|
52
|
-
this.#closeController.abort();
|
|
120
|
+
this.#closeController.abort(new DOMException('coordinator closed', 'AbortError'));
|
|
121
|
+
const sessions = [...this.#sessions];
|
|
122
|
+
await Promise.all(sessions.map((session) => session.connection.close()));
|
|
123
|
+
this.#sessions.clear();
|
|
53
124
|
}
|
|
54
125
|
|
|
55
126
|
async #createSession(signal?: AbortSignal): Promise<InitializedSession> {
|
|
56
127
|
const combined = combineSignals([signal, this.#closeController.signal]);
|
|
57
|
-
const access = await this.#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
if (expiresAt <= this.#clock.now()) {
|
|
63
|
-
throw new ClusterConfigError('access token is already expired', 'ACCESS_EXPIRED');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let endpoint: URL;
|
|
128
|
+
const access = await this.#init.adapter.access(this.#init.capsuleId, combined);
|
|
129
|
+
validateHostedAccess(access, this.#targetAuthority);
|
|
130
|
+
const receivedAt = this.#clock.now();
|
|
131
|
+
this.renewalDeadline(access, receivedAt);
|
|
67
132
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
133
|
+
const session = await connectInitialized(access.websocketUrl, {
|
|
134
|
+
...this.#init.connectOptions,
|
|
135
|
+
headers: { Authorization: `Bearer ${access.accessToken}` },
|
|
136
|
+
...(combined === undefined ? {} : { signal: combined }),
|
|
137
|
+
});
|
|
138
|
+
this.#sessions.add(session);
|
|
139
|
+
void session.connection.closed.then(() => this.#sessions.delete(session));
|
|
140
|
+
return session;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof ClusterUpgradeError && error.status === 401)
|
|
143
|
+
throw new HostedAuthenticationError();
|
|
144
|
+
throw error;
|
|
74
145
|
}
|
|
75
|
-
|
|
76
|
-
return connectInitialized(endpoint.href, {
|
|
77
|
-
...this.#connectOptions,
|
|
78
|
-
headers: { Authorization: `Bearer ${access.token}` },
|
|
79
|
-
...(combined !== undefined ? { signal: combined } : {}),
|
|
80
|
-
});
|
|
81
146
|
}
|
|
82
147
|
|
|
83
|
-
#verifyCapabilities(incoming: ServerCapabilities, session: InitializedSession): void {
|
|
84
|
-
if (!this.#referenceCapabilities) return;
|
|
85
|
-
const ref = this.#referenceCapabilities;
|
|
86
|
-
const mismatches: string[] = [];
|
|
87
|
-
|
|
88
|
-
if (ref.graphProfiles) {
|
|
89
|
-
const incomingProfiles = new Set<GraphProfile>(incoming.graphProfiles ?? []);
|
|
90
|
-
for (const profile of ref.graphProfiles) {
|
|
91
|
-
if (!incomingProfiles.has(profile)) mismatches.push(`missing graphProfile: ${profile}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (ref.logs && !incoming.logs) mismatches.push('missing capability: logs');
|
|
95
|
-
if (ref.agentAttach && !incoming.agentAttach)
|
|
96
|
-
mismatches.push('missing capability: agentAttach');
|
|
97
148
|
|
|
98
|
-
|
|
99
|
-
|
|
149
|
+
#verifyCapabilities(reference: ServerCapabilities, incoming: ServerCapabilities): void {
|
|
150
|
+
const referenceProfiles = new Set<GraphProfile>(reference.graphProfiles ?? []);
|
|
151
|
+
const incomingProfiles = new Set<GraphProfile>(incoming.graphProfiles ?? []);
|
|
152
|
+
if (
|
|
153
|
+
(reference.logs && !incoming.logs) ||
|
|
154
|
+
(reference.agentAttach && !incoming.agentAttach) ||
|
|
155
|
+
[...referenceProfiles].some((profile) => !incomingProfiles.has(profile))
|
|
156
|
+
) {
|
|
100
157
|
throw new ClusterConfigError(
|
|
101
|
-
|
|
102
|
-
'
|
|
158
|
+
'replacement connection removed required server capabilities',
|
|
159
|
+
'CAPABILITY_REGRESSION'
|
|
103
160
|
);
|
|
104
161
|
}
|
|
105
162
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class HostedAuthenticationError extends Error {
|
|
2
|
+
constructor() {
|
|
3
|
+
super('Hosted target authentication failed');
|
|
4
|
+
this.name = 'HostedAuthenticationError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class HostedAuthorizationError extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super('Hosted target authorization was revoked');
|
|
11
|
+
this.name = 'HostedAuthorizationError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class HostedTransportUncertainError extends Error {
|
|
16
|
+
readonly executionRetryAuthorized = false;
|
|
17
|
+
constructor() {
|
|
18
|
+
super('Hosted session transport closed with uncertain execution state');
|
|
19
|
+
this.name = 'HostedTransportUncertainError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
1
|
+
export {
|
|
2
|
+
HostedSessionCoordinator,
|
|
3
|
+
HostedAuthenticationError,
|
|
4
|
+
HostedAuthorizationError,
|
|
5
|
+
HostedTransportUncertainError,
|
|
6
|
+
} from './coordinator.js';
|
|
7
|
+
export type {
|
|
8
|
+
HostedAccess,
|
|
9
|
+
HostedAccessAdapter,
|
|
10
|
+
HostedSessionInit,
|
|
11
|
+
HostedWatch,
|
|
12
|
+
HostedWatchOptions,
|
|
13
|
+
InitializedSession,
|
|
14
|
+
} from './types.js';
|