@desplega.ai/agent-swarm 1.165.0 → 1.166.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/dist/{acp-adapter-w6zws6me.js → acp-adapter-yzfxn8vj.js} +4 -4
- package/dist/{actions-jna0b3wm.js → actions-qz3m692w.js} +20 -24
- package/dist/{amp-adapter-0eve81pz.js → amp-adapter-j1xbmsqz.js} +4 -4
- package/dist/{app-75hm5cfa.js → app-43vrdmv8.js} +6 -7
- package/dist/{assistant-yzd51j33.js → assistant-ertffmka.js} +21 -25
- package/dist/{boot-reembed-z158xq32.js → boot-reembed-998jtpdg.js} +9 -12
- package/dist/{boot-reembed-2ex2mcsh.js → boot-reembed-s7k7c6v2.js} +10 -12
- package/dist/boot-scrub-sweep-nepsk4t1.js +211 -0
- package/dist/{boot-seeds-2bmnh18p.js → boot-seeds-vvzs1zhk.js} +8 -8
- package/dist/{claude-adapter-jbj1mycz.js → claude-adapter-2zvmekrp.js} +9 -11
- package/dist/{claude-managed-adapter-17ggz09t.js → claude-managed-adapter-s49wbk8t.js} +3 -3
- package/dist/{claude-managed-setup-ptm1nzm2.js → claude-managed-setup-cvhqq8qn.js} +4 -4
- package/dist/{claude-sdk-session-9re1g7r2.js → claude-sdk-session-kkbxtw5q.js} +2618 -2600
- package/dist/{cli-k6xx3pve.js → cli-0nhdwxd5.js} +4 -4
- package/dist/{cli-n9ehc28t.js → cli-0qjcsxgz.js} +4 -4
- package/dist/{cli-zn2v3t8v.js → cli-3ddybbbx.js} +1 -1
- package/dist/{cli-5anb0ev3.js → cli-3qn4r334.js} +71 -14
- package/dist/{cli-1kzfvd1z.js → cli-4r1sjfc4.js} +9 -5
- package/dist/{cli-ba66wyhy.js → cli-66zh26sp.js} +6 -6
- package/dist/{cli-9xb89xca.js → cli-68r1j4sg.js} +6 -6
- package/dist/{cli-xnzrzets.js → cli-8kgvmkak.js} +2 -2
- package/dist/{cli-28smfvbn.js → cli-8t229cmr.js} +5 -5
- package/dist/{cli-9866bd07.js → cli-aqcey741.js} +1 -1
- package/dist/{cli-90v942q1.js → cli-cpfmqz3n.js} +8 -8
- package/dist/{cli-50eg13rj.js → cli-df56tqdw.js} +459 -282
- package/dist/{cli-8gpbwy09.js → cli-dw2q9f7g.js} +5 -5
- package/dist/{cli-0n4fasz0.js → cli-ecknp7p1.js} +15 -15
- package/dist/{cli-xb3c6aat.js → cli-f2n17zhp.js} +1 -1
- package/dist/{cli-ftry7975.js → cli-feh3dkah.js} +1 -1
- package/dist/{cli-amwhs8h2.js → cli-fn697bnt.js} +2 -2
- package/dist/{cli-prt9emct.js → cli-gt8azyet.js} +3 -3
- package/dist/{cli-59jn5twa.js → cli-h3x613ze.js} +2 -2
- package/dist/{cli-mmzwwptd.js → cli-hf5s9pgf.js} +1 -1
- package/dist/cli-j2jbr8af.js +516 -0
- package/dist/{cli-wfajtmf7.js → cli-jhm6hzjn.js} +593 -10
- package/dist/{cli-xtgtyafv.js → cli-jvj6a0cv.js} +190 -439
- package/dist/{cli-hpryr6em.js → cli-mb75wpxf.js} +1 -1
- package/dist/{cli-420bdgw0.js → cli-mv2520nm.js} +1 -1
- package/dist/{cli-pjxnr1jn.js → cli-mwegs4af.js} +3 -3
- package/dist/{cli-5b2fjjzh.js → cli-p4ztb80h.js} +2 -2
- package/dist/{cli-e7t4snpa.js → cli-rggdq8wq.js} +4 -4
- package/dist/{cli-bdv39kgj.js → cli-rsy933yz.js} +5 -5
- package/dist/{cli-gh5yqzpe.js → cli-v2a8x45d.js} +2 -2
- package/dist/{cli-bns5c8k9.js → cli-vzc73wet.js} +43 -47
- package/dist/cli-wt7ccy4r.js +2654 -0
- package/dist/{cli-j0pdrmwg.js → cli-x7kpr72a.js} +3 -3
- package/dist/{cli-x7afk5wm.js → cli-xvc3q9br.js} +1 -1
- package/dist/{cli-9s3h836g.js → cli-xvdgasgy.js} +1 -1
- package/dist/{cli-zvckv750.js → cli-y59h2pk9.js} +2 -2
- package/dist/{cli-qdv8kgz7.js → cli-yshaazs1.js} +13884 -3241
- package/dist/{cli-nfygw434.js → cli-ysnyhws9.js} +2 -2
- package/dist/{cli-fw6vdcq5.js → cli-zp67qg5x.js} +34 -1
- package/dist/{cli-ma3zvh39.js → cli-zy7vwsne.js} +6066 -5829
- package/dist/cli.js +24 -20
- package/dist/{codex-adapter-3qnxshje.js → codex-adapter-dw1wxqt8.js} +7 -7
- package/dist/{codex-login-brkxhhdg.js → codex-login-terbdsqq.js} +2 -2
- package/dist/{codex-session-runner-612wnapp.js → codex-session-runner-3cgb8y1g.js} +7 -7
- package/dist/{commands-2ybfcxkj.js → commands-mhxam6z2.js} +6 -6
- package/dist/{cursor-adapter-p3jgdehv.js → cursor-adapter-2qda3st7.js} +3 -3
- package/dist/{db-f4ans0jj.js → db-sjks418k.js} +8 -6
- package/dist/{devin-adapter-dhzt01ff.js → devin-adapter-bffjj5n4.js} +2 -2
- package/dist/{dispatcher-pk182apd.js → dispatcher-1es759rn.js} +18 -22
- package/dist/{dsh-adapter-7twaeps1.js → dsh-adapter-bek4cyw9.js} +3 -3
- package/dist/{e2b-y8t3jzyz.js → e2b-nd50eccg.js} +1 -1
- package/dist/{event-bus-w7ac4n3c.js → event-bus-vnfthafg.js} +2 -2
- package/dist/{grok-adapter-yt9pab3k.js → grok-adapter-ar9cw9jg.js} +5 -5
- package/dist/{handlers-g2wnr4t9.js → handlers-1gkbhktr.js} +21 -25
- package/dist/{hook-f7jt9vnm.js → hook-ds2zxq9v.js} +14 -16
- package/dist/{hook-bbdpnkb4.js → hook-vxa3tcsy.js} +8 -10
- package/dist/{http-w40q4w94.js → http-3h21z9md.js} +247 -164
- package/dist/{index-056j5kzn.js → index-9b65j1m5.js} +8 -8
- package/dist/{index-9bfssf54.js → index-bn6cy8ps.js} +18 -22
- package/dist/{index-cj1r9q83.js → index-dkfxpkmm.js} +19 -23
- package/dist/{index-7n70jwbb.js → index-f8xnqrye.js} +19 -21
- package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
- package/dist/{index-k8xc083e.js → index-n99fycq7.js} +18 -22
- package/dist/{keepalive-1tj10tf4.js → keepalive-3xspa9jw.js} +11 -8
- package/dist/{lead-st0bg7v4.js → lead-6qphc124.js} +34 -38
- package/dist/{maintenance-nz71zats.js → maintenance-0teem1bb.js} +7 -9
- package/dist/{node-f0ykebbv.js → node-9sg7ajby.js} +25 -7
- package/dist/{oauth-refresh-sweep-aefzwvvq.js → oauth-refresh-sweep-sh9q25xp.js} +10 -7
- package/dist/{onboard-kgpr9mbn.js → onboard-54qmnqxe.js} +2 -2
- package/dist/{opencode-adapter-0c8e70dk.js → opencode-adapter-wjfa2wvd.js} +2 -2
- package/dist/{otel-impl-x8zp4y5a.js → otel-impl-ycqzp2a1.js} +2 -2
- package/dist/{pi-mono-adapter-t280ah5c.js → pi-mono-adapter-e77e9zst.js} +4 -4
- package/dist/{pricing-refresh-9e0q7cwk.js → pricing-refresh-atnkngqs.js} +7 -7
- package/dist/{rbac-roles-kcp6zge2.js → rbac-roles-9pjphh9q.js} +6 -6
- package/dist/{rbac-roles-790j3ga8.js → rbac-roles-j78wdksm.js} +6 -6
- package/dist/{render-v2-tch4nefj.js → render-v2-pxjs49fx.js} +6 -7
- package/dist/{setup-rcm303ns.js → setup-ymej0xtx.js} +2 -2
- package/dist/{work-objects-ctg7t70w.js → work-objects-3nh4ymzb.js} +22 -26
- package/dist/{worker-5dp0xm55.js → worker-qa9fkz5s.js} +34 -38
- package/dist/{x-v3yw66zs.js → x-ma4gnfgy.js} +2 -2
- package/openapi.json +5 -2
- package/package.json +9 -5
- package/src/be/automation-preflight.ts +9 -4
- package/src/be/boot-scrub-sweep.ts +302 -0
- package/src/be/crypto/key-bootstrap.ts +1 -1
- package/src/be/db/approvals.ts +15 -1
- package/src/be/db/codex-oauth-device-flows.ts +40 -0
- package/src/be/db/config-secrets.ts +31 -0
- package/src/be/db/runtime.ts +4 -0
- package/src/be/db/script-runs.ts +15 -0
- package/src/be/db/tasks/write.ts +1 -1
- package/src/be/db-queries/mcp-oauth.ts +5 -0
- package/src/be/db-queries/oauth.ts +77 -0
- package/src/be/db.ts +162 -59
- package/src/be/events.ts +17 -1
- package/src/be/memory/index-content.ts +2 -2
- package/src/be/memory/providers/sqlite-store.ts +63 -11
- package/src/be/memory/types.ts +14 -0
- package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
- package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
- package/src/be/scripts/db.ts +28 -4
- package/src/be/scripts/source-secrets.ts +37 -0
- package/src/be/scrub-json.ts +32 -0
- package/src/be/sealed-json.ts +59 -0
- package/src/be/secret-registry.ts +131 -0
- package/src/be/workflow-replay.ts +77 -0
- package/src/http/codex-oauth-device.ts +8 -10
- package/src/http/db-query-bounded.ts +3 -0
- package/src/http/db-query-shared.ts +107 -15
- package/src/http/db-query.ts +10 -2
- package/src/http/index.ts +23 -6
- package/src/http/script-runs.ts +9 -1
- package/src/http/scripts.ts +15 -0
- package/src/http/workflows.ts +3 -2
- package/src/oauth/mcp-wrapper.ts +1 -1
- package/src/providers/acp-adapter.ts +25 -11
- package/src/providers/acp-target-catalog.ts +35 -1
- package/src/providers/acp-targets.ts +69 -3
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/script-workflows/supervisor.ts +11 -2
- package/src/scripts-runtime/eval-harness.ts +2 -12
- package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
- package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
- package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
- package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
- package/src/scripts-runtime/executors/quickjs.ts +196 -0
- package/src/scripts-runtime/executors/registry.ts +2 -0
- package/src/scripts-runtime/executors/sourcemap.ts +79 -0
- package/src/scripts-runtime/script-error-hints.ts +14 -0
- package/src/server.ts +3 -1
- package/src/tests/acp-adapter.test.ts +127 -2
- package/src/tests/boot-scrub-sweep.test.ts +390 -0
- package/src/tests/check-text-columns.test.ts +145 -0
- package/src/tests/claude-sdk-process.fixture.ts +13 -2
- package/src/tests/codex-oauth-device.test.ts +23 -37
- package/src/tests/db-query-denylist.test.ts +202 -0
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -0
- package/src/tests/entrypoint-acp-target-binary.test.ts +31 -1
- package/src/tests/events-scrub.test.ts +88 -0
- package/src/tests/fixtures/secret-corpus.ts +320 -0
- package/src/tests/script-connections.test.ts +5 -0
- package/src/tests/script-executor-conformance.test.ts +3 -0
- package/src/tests/script-executor-quickjs.test.ts +442 -0
- package/src/tests/script-executor-registry.test.ts +6 -1
- package/src/tests/script-runs-http.test.ts +88 -1
- package/src/tests/script-runs-scrub.test.ts +275 -0
- package/src/tests/scripts-http.test.ts +82 -1
- package/src/tests/scrubbed-text-12e.test.ts +289 -0
- package/src/tests/sealed-key-guard.test.ts +166 -0
- package/src/tests/secret-canary-sweep.test.ts +958 -0
- package/src/tests/secret-registry.test.ts +355 -0
- package/src/tests/secret-rules.test.ts +230 -0
- package/src/tests/secret-scrubber.test.ts +3 -2
- package/src/tests/workflow-replay.test.ts +518 -0
- package/src/tests/workflow-scrub.test.ts +242 -0
- package/src/tools/db-query.ts +1 -1
- package/src/tools/inject-learning.ts +1 -1
- package/src/tools/workflows/get-workflow-run.ts +3 -2
- package/src/types.ts +1 -1
- package/src/utils/secret-rules.generated.ts +2055 -0
- package/src/utils/secret-scrubber.ts +363 -29
- package/src/workflows/engine.ts +39 -4
- package/src/workflows/recovery.ts +10 -1
- package/src/workflows/resume.ts +62 -3
- package/src/workflows/retry-poller.ts +3 -0
- package/dist/boot-scrub-logs-246yn076.js +0 -99
- package/dist/cli-3a4m1aws.js +0 -572
- package/dist/cli-a87b04k8.js +0 -951
- package/dist/cli-cvk6yzw5.js +0 -40
- package/dist/cli-h1spv8v4.js +0 -427
- package/dist/cli-jqt9hrnz.js +0 -168
- package/dist/cli-yhmwmv0g.js +0 -9281
- package/src/be/boot-scrub-logs.ts +0 -132
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import {
|
|
2
|
+
acquireOAuthRefreshLock,
|
|
3
|
+
createOAuthPending,
|
|
4
|
+
getAuthorizationById,
|
|
5
|
+
getDefaultAuthorizationIdForProvider,
|
|
6
|
+
getOAuthAppById,
|
|
7
|
+
getOAuthAppIdByProvider,
|
|
8
|
+
init_oauth,
|
|
9
|
+
markAuthorizationRefreshFailed,
|
|
10
|
+
releaseOAuthRefreshLock,
|
|
11
|
+
updateAuthorizationTokens
|
|
12
|
+
} from "./cli-yshaazs1.js";
|
|
13
|
+
import {
|
|
14
|
+
init_secret_scrubber,
|
|
15
|
+
registerVolatileSecret,
|
|
16
|
+
scrubSecrets
|
|
17
|
+
} from "./cli-wt7ccy4r.js";
|
|
18
|
+
|
|
19
|
+
// src/oauth/ensure-token.ts
|
|
20
|
+
init_oauth();
|
|
21
|
+
init_secret_scrubber();
|
|
22
|
+
|
|
23
|
+
// node_modules/oauth4webapi/build/index.js
|
|
24
|
+
var USER_AGENT;
|
|
25
|
+
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) {
|
|
26
|
+
const NAME = "oauth4webapi";
|
|
27
|
+
const VERSION = "v3.8.5";
|
|
28
|
+
USER_AGENT = `${NAME}/${VERSION}`;
|
|
29
|
+
}
|
|
30
|
+
var ERR_INVALID_ARG_VALUE = "ERR_INVALID_ARG_VALUE";
|
|
31
|
+
var ERR_INVALID_ARG_TYPE = "ERR_INVALID_ARG_TYPE";
|
|
32
|
+
function CodedTypeError(message, code, cause) {
|
|
33
|
+
const err = new TypeError(message, { cause });
|
|
34
|
+
Object.assign(err, { code });
|
|
35
|
+
return err;
|
|
36
|
+
}
|
|
37
|
+
var allowInsecureRequests = Symbol();
|
|
38
|
+
var clockSkew = Symbol();
|
|
39
|
+
var clockTolerance = Symbol();
|
|
40
|
+
var customFetch = Symbol();
|
|
41
|
+
var modifyAssertion = Symbol();
|
|
42
|
+
var jweDecrypt = Symbol();
|
|
43
|
+
var jwksCache = Symbol();
|
|
44
|
+
var encoder = new TextEncoder;
|
|
45
|
+
var decoder = new TextDecoder;
|
|
46
|
+
function buf(input) {
|
|
47
|
+
if (typeof input === "string") {
|
|
48
|
+
return encoder.encode(input);
|
|
49
|
+
}
|
|
50
|
+
return decoder.decode(input);
|
|
51
|
+
}
|
|
52
|
+
var encodeBase64Url;
|
|
53
|
+
if (Uint8Array.prototype.toBase64) {
|
|
54
|
+
encodeBase64Url = (input) => {
|
|
55
|
+
if (input instanceof ArrayBuffer) {
|
|
56
|
+
input = new Uint8Array(input);
|
|
57
|
+
}
|
|
58
|
+
return input.toBase64({ alphabet: "base64url", omitPadding: true });
|
|
59
|
+
};
|
|
60
|
+
} else {
|
|
61
|
+
const CHUNK_SIZE = 32768;
|
|
62
|
+
encodeBase64Url = (input) => {
|
|
63
|
+
if (input instanceof ArrayBuffer) {
|
|
64
|
+
input = new Uint8Array(input);
|
|
65
|
+
}
|
|
66
|
+
const arr = [];
|
|
67
|
+
for (let i = 0;i < input.byteLength; i += CHUNK_SIZE) {
|
|
68
|
+
arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
69
|
+
}
|
|
70
|
+
return btoa(arr.join("")).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
var decodeBase64Url;
|
|
74
|
+
if (Uint8Array.fromBase64) {
|
|
75
|
+
decodeBase64Url = (input) => {
|
|
76
|
+
try {
|
|
77
|
+
return Uint8Array.fromBase64(input, { alphabet: "base64url" });
|
|
78
|
+
} catch (cause) {
|
|
79
|
+
throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
decodeBase64Url = (input) => {
|
|
84
|
+
try {
|
|
85
|
+
const binary = atob(input.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""));
|
|
86
|
+
const bytes = new Uint8Array(binary.length);
|
|
87
|
+
for (let i = 0;i < binary.length; i++) {
|
|
88
|
+
bytes[i] = binary.charCodeAt(i);
|
|
89
|
+
}
|
|
90
|
+
return bytes;
|
|
91
|
+
} catch (cause) {
|
|
92
|
+
throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function b64u(input) {
|
|
97
|
+
if (typeof input === "string") {
|
|
98
|
+
return decodeBase64Url(input);
|
|
99
|
+
}
|
|
100
|
+
return encodeBase64Url(input);
|
|
101
|
+
}
|
|
102
|
+
class OperationProcessingError extends Error {
|
|
103
|
+
code;
|
|
104
|
+
constructor(message, options) {
|
|
105
|
+
super(message, options);
|
|
106
|
+
this.name = this.constructor.name;
|
|
107
|
+
if (options?.code) {
|
|
108
|
+
this.code = options?.code;
|
|
109
|
+
}
|
|
110
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function OPE(message, code, cause) {
|
|
114
|
+
return new OperationProcessingError(message, { code, cause });
|
|
115
|
+
}
|
|
116
|
+
function assertString(input, it, code, cause) {
|
|
117
|
+
try {
|
|
118
|
+
if (typeof input !== "string") {
|
|
119
|
+
throw CodedTypeError(`${it} must be a string`, ERR_INVALID_ARG_TYPE, cause);
|
|
120
|
+
}
|
|
121
|
+
if (input.length === 0) {
|
|
122
|
+
throw CodedTypeError(`${it} must not be empty`, ERR_INVALID_ARG_VALUE, cause);
|
|
123
|
+
}
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (code) {
|
|
126
|
+
throw OPE(err.message, code, cause);
|
|
127
|
+
}
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function randomBytes() {
|
|
132
|
+
return b64u(crypto.getRandomValues(new Uint8Array(32)));
|
|
133
|
+
}
|
|
134
|
+
function generateRandomCodeVerifier() {
|
|
135
|
+
return randomBytes();
|
|
136
|
+
}
|
|
137
|
+
function generateRandomState() {
|
|
138
|
+
return randomBytes();
|
|
139
|
+
}
|
|
140
|
+
async function calculatePKCECodeChallenge(codeVerifier) {
|
|
141
|
+
assertString(codeVerifier, "codeVerifier");
|
|
142
|
+
return b64u(await crypto.subtle.digest("SHA-256", buf(codeVerifier)));
|
|
143
|
+
}
|
|
144
|
+
var URLParse = URL.parse ? (url, base) => URL.parse(url, base) : (url, base) => {
|
|
145
|
+
try {
|
|
146
|
+
return new URL(url, base);
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
var tokenMatch = "[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+";
|
|
152
|
+
var token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}";
|
|
153
|
+
var quotedMatch = '"((?:[^"\\\\]|\\\\[\\s\\S])*)"';
|
|
154
|
+
var quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*" + quotedMatch;
|
|
155
|
+
var paramMatcher = "(" + tokenMatch + ")\\s*=\\s*(" + tokenMatch + ")";
|
|
156
|
+
var schemeRE = new RegExp("^[,\\s]*(" + tokenMatch + ")");
|
|
157
|
+
var quotedParamRE = new RegExp("^[,\\s]*" + quotedParamMatcher + "[,\\s]*(.*)");
|
|
158
|
+
var unquotedParamRE = new RegExp("^[,\\s]*" + paramMatcher + "[,\\s]*(.*)");
|
|
159
|
+
var token68ParamRE = new RegExp("^(" + token68Match + ")(?:$|[,\\s])(.*)");
|
|
160
|
+
var skipSubjectCheck = Symbol();
|
|
161
|
+
var idTokenClaims = new WeakMap;
|
|
162
|
+
var jwtRefs = new WeakMap;
|
|
163
|
+
var branded = new WeakSet;
|
|
164
|
+
var nopkce = Symbol();
|
|
165
|
+
var expectNoNonce = Symbol();
|
|
166
|
+
var skipAuthTimeCheck = Symbol();
|
|
167
|
+
var skipStateCheck = Symbol();
|
|
168
|
+
var expectNoState = Symbol();
|
|
169
|
+
var _nodiscoverycheck = Symbol();
|
|
170
|
+
var _expectedIssuer = Symbol();
|
|
171
|
+
|
|
172
|
+
// src/oauth/wrapper.ts
|
|
173
|
+
init_oauth();
|
|
174
|
+
async function buildAuthorizationUrl(config, options = {}) {
|
|
175
|
+
const state = generateRandomState();
|
|
176
|
+
const codeVerifier = generateRandomCodeVerifier();
|
|
177
|
+
const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
|
|
178
|
+
const appId = options.appId ?? await getOAuthAppIdByProvider(config.provider);
|
|
179
|
+
if (!appId) {
|
|
180
|
+
throw new Error(`OAuth app ${config.provider} is not configured`);
|
|
181
|
+
}
|
|
182
|
+
await createOAuthPending({
|
|
183
|
+
state,
|
|
184
|
+
appId,
|
|
185
|
+
label: options.label ?? "default",
|
|
186
|
+
flow: options.flow ?? "generic",
|
|
187
|
+
codeVerifier,
|
|
188
|
+
nonce: options.nonce ?? null,
|
|
189
|
+
redirectUri: config.redirectUri,
|
|
190
|
+
finalRedirect: options.finalRedirect ?? null,
|
|
191
|
+
userId: options.userId ?? null
|
|
192
|
+
});
|
|
193
|
+
const url = new URL(config.authorizeUrl);
|
|
194
|
+
url.searchParams.set("client_id", config.clientId);
|
|
195
|
+
url.searchParams.set("redirect_uri", config.redirectUri);
|
|
196
|
+
url.searchParams.set("response_type", "code");
|
|
197
|
+
url.searchParams.set("scope", config.scopes.join(config.scopeSeparator ?? ","));
|
|
198
|
+
url.searchParams.set("state", state);
|
|
199
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
200
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
201
|
+
if (config.extraParams) {
|
|
202
|
+
for (const [key, value] of Object.entries(config.extraParams)) {
|
|
203
|
+
url.searchParams.set(key, value);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { url: url.toString(), state, codeVerifier };
|
|
207
|
+
}
|
|
208
|
+
function tokenRequestInit(config, params) {
|
|
209
|
+
const useBasic = config.tokenAuthStyle === "basic";
|
|
210
|
+
const bodyParams = useBasic ? params : { ...params, client_id: config.clientId, client_secret: config.clientSecret };
|
|
211
|
+
const headers = { Accept: "application/json" };
|
|
212
|
+
if (useBasic) {
|
|
213
|
+
headers.Authorization = `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`;
|
|
214
|
+
}
|
|
215
|
+
if (config.tokenBodyFormat === "json") {
|
|
216
|
+
headers["Content-Type"] = "application/json";
|
|
217
|
+
return { headers, body: JSON.stringify(bodyParams) };
|
|
218
|
+
}
|
|
219
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
220
|
+
return { headers, body: new URLSearchParams(bodyParams).toString() };
|
|
221
|
+
}
|
|
222
|
+
async function exchangeAuthorizationCode(config, params) {
|
|
223
|
+
const response = await fetch(config.tokenUrl, {
|
|
224
|
+
method: "POST",
|
|
225
|
+
...tokenRequestInit(config, {
|
|
226
|
+
grant_type: "authorization_code",
|
|
227
|
+
redirect_uri: params.redirectUri,
|
|
228
|
+
code: params.code,
|
|
229
|
+
code_verifier: params.codeVerifier
|
|
230
|
+
})
|
|
231
|
+
});
|
|
232
|
+
if (!response.ok) {
|
|
233
|
+
const errorText = await response.text();
|
|
234
|
+
throw new Error(`Token exchange failed (${response.status}): ${errorText}`);
|
|
235
|
+
}
|
|
236
|
+
const data = await response.json();
|
|
237
|
+
return {
|
|
238
|
+
accessToken: data.access_token,
|
|
239
|
+
refreshToken: data.refresh_token,
|
|
240
|
+
expiresIn: data.expires_in,
|
|
241
|
+
scope: data.scope,
|
|
242
|
+
tokenType: data.token_type,
|
|
243
|
+
idToken: data.id_token
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
async function performTokenRefreshRequest(config, refreshToken) {
|
|
247
|
+
const response = await fetch(config.tokenUrl, {
|
|
248
|
+
method: "POST",
|
|
249
|
+
...tokenRequestInit(config, {
|
|
250
|
+
grant_type: "refresh_token",
|
|
251
|
+
refresh_token: refreshToken
|
|
252
|
+
})
|
|
253
|
+
});
|
|
254
|
+
if (!response.ok) {
|
|
255
|
+
const errorText = await response.text();
|
|
256
|
+
throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
|
|
257
|
+
}
|
|
258
|
+
const data = await response.json();
|
|
259
|
+
if (typeof data.access_token !== "string" || data.access_token.length === 0) {
|
|
260
|
+
throw new Error(`Token refresh failed: ${config.provider} response missing access_token`);
|
|
261
|
+
}
|
|
262
|
+
if (config.requiresRefreshTokenRotation && (typeof data.refresh_token !== "string" || data.refresh_token.length === 0)) {
|
|
263
|
+
throw new Error(`Token refresh failed: ${config.provider} response did not include a rotated refresh_token`);
|
|
264
|
+
}
|
|
265
|
+
const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : null;
|
|
266
|
+
return {
|
|
267
|
+
accessToken: data.access_token,
|
|
268
|
+
refreshToken: data.refresh_token,
|
|
269
|
+
expiresIn: data.expires_in,
|
|
270
|
+
scope: data.scope,
|
|
271
|
+
expiresAt
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/oauth/ensure-token.ts
|
|
276
|
+
function parseMetadata(metadataJson) {
|
|
277
|
+
try {
|
|
278
|
+
const parsed = JSON.parse(metadataJson || "{}");
|
|
279
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
280
|
+
} catch {
|
|
281
|
+
return {};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function stringRecord(value) {
|
|
285
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
286
|
+
return;
|
|
287
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, String(item)]));
|
|
288
|
+
}
|
|
289
|
+
function oauthAppRowToProviderConfig(app) {
|
|
290
|
+
const metadata = parseMetadata(app.metadata);
|
|
291
|
+
const liftedExtraParams = stringRecord(parseMetadata(app.extraParamsJson));
|
|
292
|
+
const extraParams = {
|
|
293
|
+
...typeof metadata.actor === "string" ? { actor: metadata.actor } : {},
|
|
294
|
+
...liftedExtraParams
|
|
295
|
+
};
|
|
296
|
+
return {
|
|
297
|
+
provider: app.provider,
|
|
298
|
+
clientId: app.clientId,
|
|
299
|
+
clientSecret: app.clientSecret,
|
|
300
|
+
authorizeUrl: app.authorizeUrl,
|
|
301
|
+
tokenUrl: app.tokenUrl,
|
|
302
|
+
redirectUri: app.redirectUri,
|
|
303
|
+
scopes: app.scopes.split(",").map((scope) => scope.trim()).filter(Boolean),
|
|
304
|
+
extraParams: Object.keys(extraParams).length > 0 ? extraParams : undefined,
|
|
305
|
+
scopeSeparator: app.scopeSeparator,
|
|
306
|
+
tokenAuthStyle: app.tokenAuthStyle,
|
|
307
|
+
tokenBodyFormat: app.tokenBodyFormat,
|
|
308
|
+
requiresRefreshTokenRotation: app.requiresRefreshTokenRotation
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
class OAuthRefreshError extends Error {
|
|
313
|
+
authorizationId;
|
|
314
|
+
appId;
|
|
315
|
+
reason;
|
|
316
|
+
authorizationLabel;
|
|
317
|
+
constructor(authorizationId, appId, reason, authorizationLabel, message) {
|
|
318
|
+
super(message ?? `OAuth authorization '${authorizationLabel}' refresh failed (${reason})`);
|
|
319
|
+
this.authorizationId = authorizationId;
|
|
320
|
+
this.appId = appId;
|
|
321
|
+
this.reason = reason;
|
|
322
|
+
this.authorizationLabel = authorizationLabel;
|
|
323
|
+
this.name = "OAuthRefreshError";
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function authorizationLabelFor(app, authorization) {
|
|
327
|
+
const base = app.displayName?.trim() || app.provider;
|
|
328
|
+
return authorization.label && authorization.label !== "default" ? `${base} (${authorization.label})` : base;
|
|
329
|
+
}
|
|
330
|
+
var refreshLocks = new Map;
|
|
331
|
+
var REFRESH_LOCK_TTL_MS = 2 * 60 * 1000;
|
|
332
|
+
var REFRESH_LOCK_WAIT_MS = 30 * 1000;
|
|
333
|
+
var REFRESH_LOCK_POLL_MS = 250;
|
|
334
|
+
var DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
335
|
+
async function withAuthorizationRefreshLock(authorizationId, fn) {
|
|
336
|
+
const previous = refreshLocks.get(authorizationId) ?? Promise.resolve();
|
|
337
|
+
let release;
|
|
338
|
+
const current = new Promise((resolve) => {
|
|
339
|
+
release = resolve;
|
|
340
|
+
});
|
|
341
|
+
const next = previous.catch(() => {
|
|
342
|
+
return;
|
|
343
|
+
}).then(() => current);
|
|
344
|
+
refreshLocks.set(authorizationId, next);
|
|
345
|
+
await previous.catch(() => {
|
|
346
|
+
return;
|
|
347
|
+
});
|
|
348
|
+
try {
|
|
349
|
+
return await fn();
|
|
350
|
+
} finally {
|
|
351
|
+
release();
|
|
352
|
+
if (refreshLocks.get(authorizationId) === next) {
|
|
353
|
+
refreshLocks.delete(authorizationId);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function sleep(ms) {
|
|
358
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
359
|
+
}
|
|
360
|
+
function authorizationNeedsRefresh(authorization, bufferMs = DEFAULT_REFRESH_BUFFER_MS, force = false) {
|
|
361
|
+
if (authorization.status === "refresh-failed" || authorization.status === "expired")
|
|
362
|
+
return true;
|
|
363
|
+
if (force)
|
|
364
|
+
return true;
|
|
365
|
+
if (!authorization.expiresAt)
|
|
366
|
+
return false;
|
|
367
|
+
const expiresAt = new Date(authorization.expiresAt).getTime();
|
|
368
|
+
if (Number.isNaN(expiresAt))
|
|
369
|
+
return true;
|
|
370
|
+
return expiresAt - Date.now() < bufferMs;
|
|
371
|
+
}
|
|
372
|
+
var authorizationRefreshedListeners = new Set;
|
|
373
|
+
function onAuthorizationRefreshed(listener) {
|
|
374
|
+
authorizationRefreshedListeners.add(listener);
|
|
375
|
+
return () => {
|
|
376
|
+
authorizationRefreshedListeners.delete(listener);
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function notifyAuthorizationRefreshed(event) {
|
|
380
|
+
for (const listener of authorizationRefreshedListeners) {
|
|
381
|
+
try {
|
|
382
|
+
listener(event);
|
|
383
|
+
} catch (err) {
|
|
384
|
+
console.error(scrubSecrets(`[OAuth] authorization-refreshed listener failed for ${event.provider}: ${err instanceof Error ? err.message : String(err)}`));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async function ensureAuthorizationTokenOrThrow(authorizationId, bufferMs, force = false) {
|
|
389
|
+
const initial = await getAuthorizationById(authorizationId);
|
|
390
|
+
if (!initial || initial.status === "revoked")
|
|
391
|
+
return;
|
|
392
|
+
if (!authorizationNeedsRefresh(initial, bufferMs, force))
|
|
393
|
+
return;
|
|
394
|
+
await withAuthorizationRefreshLock(authorizationId, async () => {
|
|
395
|
+
const waitStartedAt = Date.now();
|
|
396
|
+
while (true) {
|
|
397
|
+
const current = await getAuthorizationById(authorizationId);
|
|
398
|
+
if (!current || current.status === "revoked")
|
|
399
|
+
return;
|
|
400
|
+
if (current.tokenVersion !== initial.tokenVersion)
|
|
401
|
+
return;
|
|
402
|
+
if (!authorizationNeedsRefresh(current, bufferMs, force))
|
|
403
|
+
return;
|
|
404
|
+
const app = await getOAuthAppById(current.appId);
|
|
405
|
+
if (!app || app.mcpServerId !== null)
|
|
406
|
+
return;
|
|
407
|
+
if (!current.refreshToken) {
|
|
408
|
+
const label = authorizationLabelFor(app, current);
|
|
409
|
+
const message = `OAuth authorization '${label}' cannot refresh: no refresh token stored`;
|
|
410
|
+
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
411
|
+
throw new OAuthRefreshError(authorizationId, app.id, "no_refresh_token", label, message);
|
|
412
|
+
}
|
|
413
|
+
const lockOwner = await acquireOAuthRefreshLock(`authz:${authorizationId}`, REFRESH_LOCK_TTL_MS);
|
|
414
|
+
if (!lockOwner) {
|
|
415
|
+
if (Date.now() - waitStartedAt > REFRESH_LOCK_WAIT_MS) {
|
|
416
|
+
const label = authorizationLabelFor(app, current);
|
|
417
|
+
const message = `Timed out waiting for OAuth refresh lock for '${label}'`;
|
|
418
|
+
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
419
|
+
throw new OAuthRefreshError(authorizationId, app.id, "lock_timeout", label, message);
|
|
420
|
+
}
|
|
421
|
+
await sleep(REFRESH_LOCK_POLL_MS);
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
const locked = await getAuthorizationById(authorizationId);
|
|
426
|
+
if (!locked || locked.status === "revoked")
|
|
427
|
+
return;
|
|
428
|
+
if (locked.tokenVersion !== initial.tokenVersion)
|
|
429
|
+
return;
|
|
430
|
+
if (!authorizationNeedsRefresh(locked, bufferMs, force))
|
|
431
|
+
return;
|
|
432
|
+
const lockedApp = await getOAuthAppById(locked.appId);
|
|
433
|
+
if (!lockedApp || lockedApp.mcpServerId !== null)
|
|
434
|
+
return;
|
|
435
|
+
if (!locked.refreshToken) {
|
|
436
|
+
const label = authorizationLabelFor(lockedApp, locked);
|
|
437
|
+
const message = `OAuth authorization '${label}' cannot refresh: no refresh token stored`;
|
|
438
|
+
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
439
|
+
throw new OAuthRefreshError(authorizationId, lockedApp.id, "no_refresh_token", label, message);
|
|
440
|
+
}
|
|
441
|
+
const config = oauthAppRowToProviderConfig(lockedApp);
|
|
442
|
+
try {
|
|
443
|
+
const refreshed = await performTokenRefreshRequest(config, locked.refreshToken);
|
|
444
|
+
const persisted = await updateAuthorizationTokens(authorizationId, {
|
|
445
|
+
accessToken: refreshed.accessToken,
|
|
446
|
+
refreshToken: refreshed.refreshToken ?? locked.refreshToken,
|
|
447
|
+
expiresAt: refreshed.expiresAt,
|
|
448
|
+
scope: refreshed.scope ?? null,
|
|
449
|
+
expectedTokenVersion: locked.tokenVersion
|
|
450
|
+
});
|
|
451
|
+
if (!persisted) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
notifyAuthorizationRefreshed({
|
|
455
|
+
authorizationId,
|
|
456
|
+
appId: lockedApp.id,
|
|
457
|
+
provider: lockedApp.provider
|
|
458
|
+
});
|
|
459
|
+
return;
|
|
460
|
+
} catch (err) {
|
|
461
|
+
const label = authorizationLabelFor(lockedApp, locked);
|
|
462
|
+
if (locked.refreshToken)
|
|
463
|
+
registerVolatileSecret(locked.refreshToken, "oauth-refresh-token");
|
|
464
|
+
if (locked.accessToken)
|
|
465
|
+
registerVolatileSecret(locked.accessToken, "oauth-access-token");
|
|
466
|
+
if (lockedApp.clientSecret)
|
|
467
|
+
registerVolatileSecret(lockedApp.clientSecret, "oauth-client-secret");
|
|
468
|
+
const message = scrubSecrets(err instanceof Error ? err.message : String(err));
|
|
469
|
+
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
470
|
+
if (err instanceof OAuthRefreshError)
|
|
471
|
+
throw err;
|
|
472
|
+
throw new OAuthRefreshError(authorizationId, lockedApp.id, "refresh_rejected", label, message);
|
|
473
|
+
}
|
|
474
|
+
} finally {
|
|
475
|
+
await releaseOAuthRefreshLock(`authz:${authorizationId}`, lockOwner);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
async function forceRefreshAuthorizationOrThrow(authorizationId) {
|
|
481
|
+
await ensureAuthorizationTokenOrThrow(authorizationId, undefined, true);
|
|
482
|
+
}
|
|
483
|
+
async function ensureToken(provider, bufferMs) {
|
|
484
|
+
try {
|
|
485
|
+
await ensureTokenOrThrow(provider, bufferMs);
|
|
486
|
+
} catch (err) {
|
|
487
|
+
console.error(`[OAuth] Failed to refresh ${provider} token:`, err instanceof Error ? err.message : err);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function ensureTokenOrThrow(provider, bufferMs) {
|
|
491
|
+
const authorizationId = await getDefaultAuthorizationIdForProvider(provider);
|
|
492
|
+
if (!authorizationId)
|
|
493
|
+
return;
|
|
494
|
+
try {
|
|
495
|
+
await ensureAuthorizationTokenOrThrow(authorizationId, bufferMs);
|
|
496
|
+
} catch (err) {
|
|
497
|
+
if (err instanceof OAuthRefreshError && err.reason === "no_refresh_token") {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
throw err;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async function forceRefreshTokenOrThrow(provider) {
|
|
504
|
+
const authorizationId = await getDefaultAuthorizationIdForProvider(provider);
|
|
505
|
+
if (!authorizationId)
|
|
506
|
+
return;
|
|
507
|
+
try {
|
|
508
|
+
await forceRefreshAuthorizationOrThrow(authorizationId);
|
|
509
|
+
} catch (err) {
|
|
510
|
+
if (err instanceof OAuthRefreshError && err.reason === "no_refresh_token")
|
|
511
|
+
return;
|
|
512
|
+
throw err;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export { generateRandomCodeVerifier, generateRandomState, calculatePKCECodeChallenge, buildAuthorizationUrl, exchangeAuthorizationCode, oauthAppRowToProviderConfig, onAuthorizationRefreshed, ensureAuthorizationTokenOrThrow, forceRefreshAuthorizationOrThrow, ensureToken, ensureTokenOrThrow, forceRefreshTokenOrThrow };
|