@the-open-engine/zeroshot 6.28.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/README.md +3 -3
- package/cli/index.js +20 -224
- package/docker/zeroshot-cluster/Dockerfile +2 -3
- 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/cluster/connection-types.cjs +2 -0
- 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 +1 -11
- package/lib/cluster-worker/engine-input.js +14 -0
- 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/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 -10
- package/lib/target/device-flow.js +162 -53
- 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 +68 -5
- package/lib/target/discovery.js +93 -101
- 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 -31
- package/lib/target/target-session.js +63 -150
- 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 +16 -6
- package/scripts/audit-production-dependencies.js +150 -0
- package/scripts/build-cluster.js +23 -3
- package/scripts/opcore-agent-gate.js +159 -0
- package/scripts/opcore-agent-tool-overlays.js +154 -0
- package/scripts/opcore-introduced-check.js +288 -0
- 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/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 +206 -71
- 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 -115
- 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 -222
- package/src/target/token-response.ts +62 -0
|
@@ -1,249 +1,132 @@
|
|
|
1
|
-
import type { TargetCredentialStore } from './credential-store.
|
|
2
|
-
import type {
|
|
1
|
+
import type { TargetCredentialStore } from './credential-store.js';
|
|
2
|
+
import type { Clock } from './device-flow.js';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
TargetSessionManager,
|
|
5
|
+
type TargetSessionDeps,
|
|
6
|
+
} from './target-session-manager.js';
|
|
7
|
+
import type { SettingsPort, TargetRecord } from './target-registry.js';
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
LoginRequiredError,
|
|
11
|
+
TargetSessionManager,
|
|
12
|
+
type BrowserOpener,
|
|
13
|
+
type TargetSessionDeps,
|
|
14
|
+
type TargetSessionManagerInit,
|
|
15
|
+
} from './target-session-manager.js';
|
|
13
16
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
constructor(targetName: string) {
|
|
17
|
-
super(`Login required. Run: zeroshot target login ${targetName}`);
|
|
18
|
-
this.name = 'LoginRequiredError';
|
|
19
|
-
this.targetName = targetName;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface BrowserOpener {
|
|
24
|
-
open(url: string): Promise<void>;
|
|
17
|
+
export interface TargetAccessTokenProvider {
|
|
18
|
+
getAccessToken(signal?: AbortSignal): Promise<string>;
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
readonly
|
|
29
|
-
readonly
|
|
30
|
-
readonly
|
|
31
|
-
|
|
32
|
-
readonly discoveryEndpoints: {
|
|
33
|
-
readonly deviceAuthorizationEndpoint: string;
|
|
34
|
-
readonly tokenEndpoint: string;
|
|
35
|
-
readonly revocationEndpoint?: string;
|
|
36
|
-
readonly clientId: string;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
21
|
+
type LegacySessionDeps = Pick<TargetSessionDeps, 'http' | 'discoveryEndpoints'> & {
|
|
22
|
+
readonly settings?: SettingsPort;
|
|
23
|
+
readonly targetName?: string;
|
|
24
|
+
readonly clock?: Clock;
|
|
25
|
+
};
|
|
39
26
|
|
|
40
|
-
|
|
27
|
+
type TargetLoginArgs = readonly [
|
|
41
28
|
targetName: string,
|
|
42
29
|
target: TargetRecord,
|
|
43
30
|
credentialStore: TargetCredentialStore,
|
|
44
31
|
acquireLock: () => Promise<() => Promise<void>>,
|
|
45
32
|
settings: SettingsPort,
|
|
46
|
-
deps: TargetSessionDeps
|
|
47
|
-
|
|
48
|
-
const { http, clock, browserOpener, stderr, discoveryEndpoints } = deps;
|
|
49
|
-
const { deviceAuthorizationEndpoint, tokenEndpoint, clientId } = discoveryEndpoints;
|
|
50
|
-
|
|
51
|
-
const codeResponse = await requestDeviceCode(deviceAuthorizationEndpoint, clientId, http);
|
|
52
|
-
|
|
53
|
-
stderr.write(
|
|
54
|
-
`\nOpen this URL to authorize:\n ${codeResponse.verification_uri}\n\nEnter code: ${codeResponse.user_code}\n\n`
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
if (codeResponse.verification_uri_complete) {
|
|
58
|
-
try {
|
|
59
|
-
await browserOpener.open(codeResponse.verification_uri_complete);
|
|
60
|
-
} catch {
|
|
61
|
-
// Browser open is best-effort
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const tokenResponse = await pollForToken(
|
|
66
|
-
tokenEndpoint,
|
|
67
|
-
clientId,
|
|
68
|
-
codeResponse.device_code,
|
|
69
|
-
codeResponse.interval,
|
|
70
|
-
codeResponse.expires_in,
|
|
71
|
-
http,
|
|
72
|
-
clock
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
if (!tokenResponse.organization) {
|
|
76
|
-
throw new UnboundSessionError(codeResponse.verification_uri);
|
|
77
|
-
}
|
|
33
|
+
deps: TargetSessionDeps,
|
|
34
|
+
];
|
|
78
35
|
|
|
79
|
-
|
|
80
|
-
const release = await acquireLock();
|
|
81
|
-
try {
|
|
82
|
-
await credentialStore.set(serviceKey, TARGET_ACCOUNT, tokenResponse.refresh_token);
|
|
83
|
-
} finally {
|
|
84
|
-
await release();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
updateTargetOrganization(targetName, tokenResponse.organization, settings);
|
|
88
|
-
|
|
89
|
-
return { organization: tokenResponse.organization };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function refreshAccessToken(
|
|
36
|
+
type RefreshAccessArgs = readonly [
|
|
93
37
|
targetName: string,
|
|
94
38
|
target: TargetRecord,
|
|
95
39
|
credentialStore: TargetCredentialStore,
|
|
96
40
|
acquireLock: () => Promise<() => Promise<void>>,
|
|
97
|
-
deps:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const { tokenEndpoint, revocationEndpoint, clientId } = discoveryEndpoints;
|
|
101
|
-
const serviceKey = targetServiceKey(target.id);
|
|
41
|
+
deps: LegacySessionDeps,
|
|
42
|
+
clock?: Clock,
|
|
43
|
+
];
|
|
102
44
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const body = new URLSearchParams({
|
|
111
|
-
grant_type: 'refresh_token',
|
|
112
|
-
refresh_token: currentRefreshToken,
|
|
113
|
-
client_id: clientId,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
let tokenResponse: TokenResponse;
|
|
117
|
-
const response = await http.fetch(tokenEndpoint, {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
120
|
-
body: body.toString(),
|
|
121
|
-
redirect: 'error',
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!response.ok) {
|
|
125
|
-
const errorBody = (await response.json().catch(() => ({ error: 'unknown' }))) as {
|
|
126
|
-
error: string;
|
|
127
|
-
};
|
|
128
|
-
if (errorBody.error === 'invalid_grant') {
|
|
129
|
-
await credentialStore.delete(serviceKey, TARGET_ACCOUNT);
|
|
130
|
-
throw new LoginRequiredError(targetName);
|
|
131
|
-
}
|
|
132
|
-
throw new Error(`Token refresh failed (${response.status}): ${errorBody.error}`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
tokenResponse = (await response.json()) as TokenResponse;
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
await credentialStore.set(serviceKey, TARGET_ACCOUNT, tokenResponse.refresh_token);
|
|
139
|
-
} catch {
|
|
140
|
-
await bestEffortRevoke(tokenResponse.refresh_token, revocationEndpoint, clientId, http);
|
|
141
|
-
await credentialStore.delete(serviceKey, TARGET_ACCOUNT);
|
|
142
|
-
throw new LoginRequiredError(targetName);
|
|
143
|
-
}
|
|
45
|
+
type RevokeArgs = readonly [
|
|
46
|
+
target: TargetRecord,
|
|
47
|
+
credentialStore: TargetCredentialStore,
|
|
48
|
+
acquireLock: () => Promise<() => Promise<void>>,
|
|
49
|
+
deps: LegacySessionDeps,
|
|
50
|
+
force: boolean,
|
|
51
|
+
];
|
|
144
52
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
53
|
+
type LegacyManagerInit = {
|
|
54
|
+
readonly targetName: string;
|
|
55
|
+
readonly target: TargetRecord;
|
|
56
|
+
readonly credentialStore: TargetCredentialStore;
|
|
57
|
+
readonly acquireLock: () => Promise<() => Promise<void>>;
|
|
58
|
+
readonly deps: LegacySessionDeps;
|
|
59
|
+
readonly clock?: Clock;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function transientSettings(targetName: string, target: TargetRecord): SettingsPort {
|
|
63
|
+
const state: { _targets: Record<string, TargetRecord> } = {
|
|
64
|
+
_targets: { [targetName]: target },
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
load: () => state,
|
|
68
|
+
mutate: (mutator) => mutator(state),
|
|
69
|
+
};
|
|
149
70
|
}
|
|
150
71
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
body: body.toString(),
|
|
168
|
-
redirect: 'error',
|
|
169
|
-
});
|
|
170
|
-
} catch {
|
|
171
|
-
// Best-effort
|
|
172
|
-
}
|
|
72
|
+
function legacyManager(init: LegacyManagerInit): TargetSessionManager {
|
|
73
|
+
const clock = init.clock ?? init.deps.clock ?? { now: () => Date.now() };
|
|
74
|
+
return new TargetSessionManager({
|
|
75
|
+
targetName: init.targetName,
|
|
76
|
+
target: init.target,
|
|
77
|
+
credentialStore: init.credentialStore,
|
|
78
|
+
acquireLock: init.acquireLock,
|
|
79
|
+
settings: init.deps.settings ?? transientSettings(init.targetName, init.target),
|
|
80
|
+
deps: {
|
|
81
|
+
http: init.deps.http,
|
|
82
|
+
clock,
|
|
83
|
+
browserOpener: { open: () => Promise.resolve() },
|
|
84
|
+
stderr: { write: () => undefined },
|
|
85
|
+
discoveryEndpoints: init.deps.discoveryEndpoints,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
173
88
|
}
|
|
174
89
|
|
|
175
|
-
export
|
|
176
|
-
|
|
90
|
+
export function targetLogin(...args: TargetLoginArgs): Promise<{ organization: { id: string } }> {
|
|
91
|
+
const [targetName, target, credentialStore, acquireLock, settings, deps] = args;
|
|
92
|
+
return new TargetSessionManager({
|
|
93
|
+
targetName,
|
|
94
|
+
target,
|
|
95
|
+
credentialStore,
|
|
96
|
+
acquireLock,
|
|
97
|
+
settings,
|
|
98
|
+
deps,
|
|
99
|
+
}).login();
|
|
177
100
|
}
|
|
178
101
|
|
|
179
|
-
export function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
credentialStore
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
async getAccessToken(_signal?: AbortSignal): Promise<string> {
|
|
192
|
-
if (cachedToken && clock.now() < expiresAt - 30_000) {
|
|
193
|
-
return cachedToken;
|
|
194
|
-
}
|
|
195
|
-
const result = await refreshAccessToken(
|
|
196
|
-
targetName,
|
|
197
|
-
target,
|
|
198
|
-
credentialStore,
|
|
199
|
-
acquireLock,
|
|
200
|
-
deps
|
|
201
|
-
);
|
|
202
|
-
cachedToken = result.accessToken;
|
|
203
|
-
expiresAt = clock.now() + result.expiresIn * 1000;
|
|
204
|
-
return result.accessToken;
|
|
205
|
-
},
|
|
206
|
-
};
|
|
102
|
+
export async function refreshAccessToken(
|
|
103
|
+
...args: RefreshAccessArgs
|
|
104
|
+
): Promise<{ accessToken: string; expiresIn: number }> {
|
|
105
|
+
const [targetName, target, credentialStore, acquireLock, deps, clock] = args;
|
|
106
|
+
return legacyManager({
|
|
107
|
+
targetName,
|
|
108
|
+
target,
|
|
109
|
+
credentialStore,
|
|
110
|
+
acquireLock,
|
|
111
|
+
deps,
|
|
112
|
+
...(clock === undefined ? {} : { clock }),
|
|
113
|
+
}).getAccessTokenWithLifetime('capsule');
|
|
207
114
|
}
|
|
208
115
|
|
|
209
|
-
export
|
|
210
|
-
target
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
116
|
+
export function getAccessTokenProvider(...args: RefreshAccessArgs): TargetAccessTokenProvider {
|
|
117
|
+
const [targetName, target, credentialStore, acquireLock, deps, clock] = args;
|
|
118
|
+
return legacyManager({
|
|
119
|
+
targetName,
|
|
120
|
+
target,
|
|
121
|
+
credentialStore,
|
|
122
|
+
acquireLock,
|
|
123
|
+
deps,
|
|
124
|
+
...(clock === undefined ? {} : { clock }),
|
|
125
|
+
}).tokenProvider('capsule');
|
|
126
|
+
}
|
|
219
127
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const body = new URLSearchParams({
|
|
225
|
-
token: refreshToken,
|
|
226
|
-
client_id: clientId,
|
|
227
|
-
token_type_hint: 'refresh_token',
|
|
228
|
-
});
|
|
229
|
-
try {
|
|
230
|
-
const response = await http.fetch(revocationEndpoint, {
|
|
231
|
-
method: 'POST',
|
|
232
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
233
|
-
body: body.toString(),
|
|
234
|
-
redirect: 'error',
|
|
235
|
-
});
|
|
236
|
-
if (!response.ok && !force) {
|
|
237
|
-
throw new Error(
|
|
238
|
-
`Remote revocation failed (${response.status}). Use --force to remove anyway.`
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
} catch (err) {
|
|
242
|
-
if (!force) throw err;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
await credentialStore.delete(serviceKey, TARGET_ACCOUNT);
|
|
246
|
-
} finally {
|
|
247
|
-
await release();
|
|
248
|
-
}
|
|
128
|
+
export function revokeAndCleanup(...args: RevokeArgs): Promise<void> {
|
|
129
|
+
const [target, credentialStore, acquireLock, deps, force] = args;
|
|
130
|
+
const targetName = deps.targetName ?? target.id;
|
|
131
|
+
return legacyManager({ targetName, target, credentialStore, acquireLock, deps }).revoke(force);
|
|
249
132
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const MAX_TOKEN_BYTES = 16 * 1024;
|
|
2
|
+
const TOKEN_RESPONSE_FIELDS = [
|
|
3
|
+
'access_token',
|
|
4
|
+
'refresh_token',
|
|
5
|
+
'token_type',
|
|
6
|
+
'expires_in',
|
|
7
|
+
'refresh_expires_in',
|
|
8
|
+
'scope',
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
export interface TokenResponse {
|
|
12
|
+
readonly access_token: string;
|
|
13
|
+
readonly refresh_token: string;
|
|
14
|
+
readonly token_type: 'Bearer';
|
|
15
|
+
readonly expires_in: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function boundedString(value: unknown, maxBytes: number): value is string {
|
|
19
|
+
return typeof value === 'string' && value.length > 0 &&
|
|
20
|
+
new TextEncoder().encode(value).byteLength <= maxBytes;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function tokenFieldsValid(token: Record<string, unknown>): boolean {
|
|
24
|
+
const fields = Object.keys(token);
|
|
25
|
+
return fields.length === TOKEN_RESPONSE_FIELDS.length &&
|
|
26
|
+
fields.every((key) => TOKEN_RESPONSE_FIELDS.includes(
|
|
27
|
+
key as (typeof TOKEN_RESPONSE_FIELDS)[number],
|
|
28
|
+
));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function tokenLifetimesValid(token: Record<string, unknown>): boolean {
|
|
32
|
+
return Number.isSafeInteger(token.expires_in) &&
|
|
33
|
+
(token.expires_in as number) > 0 &&
|
|
34
|
+
(token.expires_in as number) <= 86_400 &&
|
|
35
|
+
Number.isSafeInteger(token.refresh_expires_in) &&
|
|
36
|
+
(token.refresh_expires_in as number) > 0 &&
|
|
37
|
+
(token.refresh_expires_in as number) <= 31_536_000;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function tokenStringsValid(token: Record<string, unknown>): boolean {
|
|
41
|
+
return boundedString(token.access_token, MAX_TOKEN_BYTES) &&
|
|
42
|
+
boundedString(token.refresh_token, MAX_TOKEN_BYTES) &&
|
|
43
|
+
token.token_type === 'Bearer' &&
|
|
44
|
+
boundedString(token.scope, 512) &&
|
|
45
|
+
!/[\u0000-\u001f\u007f]/.test(token.scope);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function parseTokenResponse(value: unknown): TokenResponse {
|
|
49
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
50
|
+
throw new Error('Token response is malformed');
|
|
51
|
+
}
|
|
52
|
+
const token = value as Record<string, unknown>;
|
|
53
|
+
if (!tokenFieldsValid(token) || !tokenLifetimesValid(token) || !tokenStringsValid(token)) {
|
|
54
|
+
throw new Error('Token response is malformed');
|
|
55
|
+
}
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
access_token: token.access_token,
|
|
58
|
+
refresh_token: token.refresh_token,
|
|
59
|
+
token_type: 'Bearer',
|
|
60
|
+
expires_in: token.expires_in,
|
|
61
|
+
}) as TokenResponse;
|
|
62
|
+
}
|