@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
package/dist/cli-a87b04k8.js
DELETED
|
@@ -1,951 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
decryptSecret,
|
|
3
|
-
encryptSecret,
|
|
4
|
-
getDbClient,
|
|
5
|
-
getEncryptionKey,
|
|
6
|
-
init_crypto,
|
|
7
|
-
init_date_utils,
|
|
8
|
-
init_db,
|
|
9
|
-
normalizeDateRequired
|
|
10
|
-
} from "./cli-qdv8kgz7.js";
|
|
11
|
-
import {
|
|
12
|
-
init_secret_scrubber,
|
|
13
|
-
registerVolatileSecret,
|
|
14
|
-
scrubSecrets
|
|
15
|
-
} from "./cli-h1spv8v4.js";
|
|
16
|
-
|
|
17
|
-
// src/be/db-queries/oauth.ts
|
|
18
|
-
init_crypto();
|
|
19
|
-
init_date_utils();
|
|
20
|
-
init_db();
|
|
21
|
-
function parseScopeList(value) {
|
|
22
|
-
try {
|
|
23
|
-
const parsed = JSON.parse(value);
|
|
24
|
-
if (Array.isArray(parsed)) {
|
|
25
|
-
return parsed.filter((item) => typeof item === "string");
|
|
26
|
-
}
|
|
27
|
-
} catch {}
|
|
28
|
-
return value.split(",").map((scope) => scope.trim()).filter(Boolean);
|
|
29
|
-
}
|
|
30
|
-
function storeScopeList(value) {
|
|
31
|
-
return JSON.stringify(Array.isArray(value) ? value : parseScopeList(value));
|
|
32
|
-
}
|
|
33
|
-
function parseObject(value) {
|
|
34
|
-
try {
|
|
35
|
-
const parsed = JSON.parse(value || "{}");
|
|
36
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
37
|
-
} catch {
|
|
38
|
-
return {};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function storageMetadata(metadata) {
|
|
42
|
-
const parsed = parseObject(metadata);
|
|
43
|
-
const extraParams = parsed.extraParams && typeof parsed.extraParams === "object" && !Array.isArray(parsed.extraParams) ? parsed.extraParams : null;
|
|
44
|
-
const tokenAuthStyle = parsed.tokenAuthStyle === "basic" ? "basic" : "body";
|
|
45
|
-
const tokenBodyFormat = parsed.tokenBodyFormat === "json" ? "json" : "form";
|
|
46
|
-
const revocationUrl = typeof parsed.revocationUrl === "string" ? parsed.revocationUrl : null;
|
|
47
|
-
const hasLiftedFields = [
|
|
48
|
-
"extraParams",
|
|
49
|
-
"tokenAuthStyle",
|
|
50
|
-
"tokenBodyFormat",
|
|
51
|
-
"revocationUrl"
|
|
52
|
-
].some((key) => Object.hasOwn(parsed, key));
|
|
53
|
-
if (hasLiftedFields) {
|
|
54
|
-
delete parsed.extraParams;
|
|
55
|
-
delete parsed.tokenAuthStyle;
|
|
56
|
-
delete parsed.tokenBodyFormat;
|
|
57
|
-
delete parsed.revocationUrl;
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
metadata: hasLiftedFields ? JSON.stringify(parsed) : metadata,
|
|
61
|
-
extraParamsJson: extraParams ? JSON.stringify(extraParams) : null,
|
|
62
|
-
tokenAuthStyle,
|
|
63
|
-
tokenBodyFormat,
|
|
64
|
-
revocationUrl
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function normalizeOAuthApp(row) {
|
|
68
|
-
const encrypted = row.clientSecretEncrypted === 1;
|
|
69
|
-
return {
|
|
70
|
-
...row,
|
|
71
|
-
clientSecret: row.clientSecret == null ? "" : encrypted ? decryptSecret(row.clientSecret, getEncryptionKey()) : row.clientSecret,
|
|
72
|
-
clientSecretEncrypted: encrypted,
|
|
73
|
-
scopes: parseScopeList(row.scopes).join(","),
|
|
74
|
-
requiresRefreshTokenRotation: row.requiresRefreshTokenRotation === 1,
|
|
75
|
-
createdAt: normalizeDateRequired(row.createdAt),
|
|
76
|
-
updatedAt: normalizeDateRequired(row.updatedAt)
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function normalizeAuthorization(row) {
|
|
80
|
-
const encrypted = row.tokensEncrypted === 1;
|
|
81
|
-
const key = encrypted ? getEncryptionKey() : null;
|
|
82
|
-
return {
|
|
83
|
-
...row,
|
|
84
|
-
accessToken: key ? decryptSecret(row.accessToken, key) : row.accessToken,
|
|
85
|
-
refreshToken: row.refreshToken == null ? null : key ? decryptSecret(row.refreshToken, key) : row.refreshToken,
|
|
86
|
-
tokensEncrypted: encrypted,
|
|
87
|
-
createdAt: normalizeDateRequired(row.createdAt),
|
|
88
|
-
updatedAt: normalizeDateRequired(row.updatedAt)
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
async function rawOAuthAppByProvider(provider) {
|
|
92
|
-
return await getDbClient().get(`SELECT * FROM oauth_apps
|
|
93
|
-
WHERE provider = ? AND mcpServerId IS NULL
|
|
94
|
-
ORDER BY createdAt ASC, id ASC
|
|
95
|
-
LIMIT 1`, [provider]);
|
|
96
|
-
}
|
|
97
|
-
async function rawOAuthAppById(id) {
|
|
98
|
-
return await getDbClient().get("SELECT * FROM oauth_apps WHERE id = ? AND mcpServerId IS NULL", [id]);
|
|
99
|
-
}
|
|
100
|
-
async function rawDefaultAuthorizationForApp(appId) {
|
|
101
|
-
return await getDbClient().get("SELECT * FROM oauth_authorizations WHERE appId = ? AND label = 'default'", [appId]);
|
|
102
|
-
}
|
|
103
|
-
async function rawDefaultAuthorizationForProvider(provider) {
|
|
104
|
-
return await getDbClient().get(`SELECT z.*
|
|
105
|
-
FROM oauth_authorizations z
|
|
106
|
-
JOIN oauth_apps a ON a.id = z.appId
|
|
107
|
-
WHERE a.provider = ? AND a.mcpServerId IS NULL AND z.label = 'default'
|
|
108
|
-
ORDER BY a.createdAt ASC, a.id ASC
|
|
109
|
-
LIMIT 1`, [provider]);
|
|
110
|
-
}
|
|
111
|
-
async function getDefaultAuthorizationIdForProvider(provider) {
|
|
112
|
-
return (await rawDefaultAuthorizationForProvider(provider))?.id ?? null;
|
|
113
|
-
}
|
|
114
|
-
async function getOAuthApp(provider) {
|
|
115
|
-
const row = await rawOAuthAppByProvider(provider);
|
|
116
|
-
return row ? normalizeOAuthApp(row) : null;
|
|
117
|
-
}
|
|
118
|
-
async function getOAuthAppById(id) {
|
|
119
|
-
const row = await getDbClient().get("SELECT * FROM oauth_apps WHERE id = ?", [id]);
|
|
120
|
-
return row ? normalizeOAuthApp(row) : null;
|
|
121
|
-
}
|
|
122
|
-
async function getOAuthAppIdByProvider(provider) {
|
|
123
|
-
return (await rawOAuthAppByProvider(provider))?.id ?? null;
|
|
124
|
-
}
|
|
125
|
-
async function writeOAuthApp(existing, provider, data) {
|
|
126
|
-
const metadataProvided = data.metadata !== undefined;
|
|
127
|
-
const lifted = metadataProvided ? storageMetadata(data.metadata) : null;
|
|
128
|
-
const encryptedSecret = encryptSecret(data.clientSecret, getEncryptionKey());
|
|
129
|
-
const scopeSeparator = data.scopeSeparator ?? existing?.scopeSeparator ?? (provider === "linear" ? "," : " ");
|
|
130
|
-
const rotation = data.requiresRefreshTokenRotation ?? (existing ? existing.requiresRefreshTokenRotation === 1 : provider === "jira");
|
|
131
|
-
const tokenAuthStyle = data.tokenAuthStyle ?? lifted?.tokenAuthStyle ?? existing?.tokenAuthStyle ?? "body";
|
|
132
|
-
const tokenBodyFormat = data.tokenBodyFormat ?? lifted?.tokenBodyFormat ?? existing?.tokenBodyFormat ?? "form";
|
|
133
|
-
const extraParamsJson = data.extraParams !== undefined ? data.extraParams == null ? null : JSON.stringify(data.extraParams) : lifted ? lifted.extraParamsJson : existing?.extraParamsJson ?? null;
|
|
134
|
-
const revocationUrl = data.revocationUrl !== undefined ? data.revocationUrl : lifted ? lifted.revocationUrl : existing?.revocationUrl ?? null;
|
|
135
|
-
if (existing) {
|
|
136
|
-
await getDbClient().run(`UPDATE oauth_apps SET
|
|
137
|
-
displayName = ?, clientId = ?, clientSecret = ?, clientSecretEncrypted = 1,
|
|
138
|
-
authorizeUrl = ?, tokenUrl = ?, revocationUrl = ?, userinfoUrl = ?,
|
|
139
|
-
redirectUri = ?, scopes = ?, scopeSeparator = ?, tokenAuthStyle = ?,
|
|
140
|
-
tokenBodyFormat = ?, requiresRefreshTokenRotation = ?, extraParamsJson = ?,
|
|
141
|
-
source = ?, metadata = ?, updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
142
|
-
WHERE id = ?`, [
|
|
143
|
-
data.displayName !== undefined ? data.displayName : existing.displayName,
|
|
144
|
-
data.clientId,
|
|
145
|
-
encryptedSecret,
|
|
146
|
-
data.authorizeUrl,
|
|
147
|
-
data.tokenUrl,
|
|
148
|
-
revocationUrl,
|
|
149
|
-
data.userinfoUrl !== undefined ? data.userinfoUrl : existing.userinfoUrl,
|
|
150
|
-
data.redirectUri,
|
|
151
|
-
storeScopeList(data.scopes),
|
|
152
|
-
scopeSeparator,
|
|
153
|
-
tokenAuthStyle,
|
|
154
|
-
tokenBodyFormat,
|
|
155
|
-
rotation ? 1 : 0,
|
|
156
|
-
extraParamsJson,
|
|
157
|
-
data.source ?? existing.source,
|
|
158
|
-
lifted?.metadata ?? existing.metadata,
|
|
159
|
-
existing.id
|
|
160
|
-
]);
|
|
161
|
-
return existing.id;
|
|
162
|
-
}
|
|
163
|
-
const inserted = await getDbClient().get(`INSERT INTO oauth_apps (
|
|
164
|
-
provider, displayName, clientId, clientSecret, clientSecretEncrypted,
|
|
165
|
-
authorizeUrl, tokenUrl, revocationUrl, userinfoUrl, redirectUri, scopes,
|
|
166
|
-
scopeSeparator, tokenAuthStyle, tokenBodyFormat,
|
|
167
|
-
requiresRefreshTokenRotation, extraParamsJson, source, metadata
|
|
168
|
-
) VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
169
|
-
RETURNING id`, [
|
|
170
|
-
provider,
|
|
171
|
-
data.displayName ?? null,
|
|
172
|
-
data.clientId,
|
|
173
|
-
encryptedSecret,
|
|
174
|
-
data.authorizeUrl,
|
|
175
|
-
data.tokenUrl,
|
|
176
|
-
revocationUrl,
|
|
177
|
-
data.userinfoUrl ?? null,
|
|
178
|
-
data.redirectUri,
|
|
179
|
-
storeScopeList(data.scopes),
|
|
180
|
-
scopeSeparator,
|
|
181
|
-
tokenAuthStyle,
|
|
182
|
-
tokenBodyFormat,
|
|
183
|
-
rotation ? 1 : 0,
|
|
184
|
-
extraParamsJson,
|
|
185
|
-
data.source ?? "manual",
|
|
186
|
-
lifted?.metadata ?? "{}"
|
|
187
|
-
]);
|
|
188
|
-
return inserted.id;
|
|
189
|
-
}
|
|
190
|
-
async function createOAuthApp(provider, data) {
|
|
191
|
-
return await writeOAuthApp(null, provider, data);
|
|
192
|
-
}
|
|
193
|
-
async function updateOAuthAppById(id, data) {
|
|
194
|
-
const existing = await rawOAuthAppById(id);
|
|
195
|
-
if (!existing) {
|
|
196
|
-
throw new Error(`OAuth app ${id} not found.`);
|
|
197
|
-
}
|
|
198
|
-
await writeOAuthApp(existing, existing.provider, data);
|
|
199
|
-
}
|
|
200
|
-
async function upsertOAuthApp(provider, data) {
|
|
201
|
-
await writeOAuthApp(await rawOAuthAppByProvider(provider), provider, data);
|
|
202
|
-
}
|
|
203
|
-
async function listAuthorizationsForApp(appId) {
|
|
204
|
-
const rows = await getDbClient().query("SELECT * FROM oauth_authorizations WHERE appId = ? ORDER BY createdAt ASC, id ASC", [appId]);
|
|
205
|
-
return rows.map(normalizeAuthorization);
|
|
206
|
-
}
|
|
207
|
-
async function getAuthorizationById(id) {
|
|
208
|
-
const row = await getDbClient().get("SELECT * FROM oauth_authorizations WHERE id = ?", [id]);
|
|
209
|
-
return row ? normalizeAuthorization(row) : null;
|
|
210
|
-
}
|
|
211
|
-
async function upsertAuthorization(data) {
|
|
212
|
-
const label = data.label ?? "default";
|
|
213
|
-
const existing = data.id ? await getAuthorizationById(data.id) : (await listAuthorizationsForApp(data.appId)).find((row) => row.label === label);
|
|
214
|
-
const key = getEncryptionKey();
|
|
215
|
-
const accessToken = encryptSecret(data.accessToken, key);
|
|
216
|
-
const refreshToken = data.refreshToken === undefined ? undefined : data.refreshToken == null ? null : encryptSecret(data.refreshToken, key);
|
|
217
|
-
if (existing) {
|
|
218
|
-
await getDbClient().run(`UPDATE oauth_authorizations SET
|
|
219
|
-
userId = ?, accountEmail = ?, identityJson = ?, accessToken = ?,
|
|
220
|
-
refreshToken = ?, tokenType = ?, expiresAt = ?, scope = ?,
|
|
221
|
-
tokensEncrypted = 1, tokenVersion = tokenVersion + 1, status = ?,
|
|
222
|
-
lastErrorMessage = ?, lastRefreshedAt = ?, connectedByUserId = ?,
|
|
223
|
-
updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
224
|
-
WHERE id = ?`, [
|
|
225
|
-
data.userId !== undefined ? data.userId : existing.userId,
|
|
226
|
-
data.accountEmail !== undefined ? data.accountEmail : existing.accountEmail,
|
|
227
|
-
data.identityJson !== undefined ? data.identityJson : existing.identityJson,
|
|
228
|
-
accessToken,
|
|
229
|
-
refreshToken === undefined ? existing.refreshToken == null ? null : encryptSecret(existing.refreshToken, key) : refreshToken,
|
|
230
|
-
data.tokenType ?? existing.tokenType,
|
|
231
|
-
data.expiresAt !== undefined ? data.expiresAt : existing.expiresAt,
|
|
232
|
-
data.scope !== undefined ? data.scope : existing.scope,
|
|
233
|
-
data.status ?? existing.status,
|
|
234
|
-
data.lastErrorMessage !== undefined ? data.lastErrorMessage : existing.lastErrorMessage,
|
|
235
|
-
data.lastRefreshedAt !== undefined ? data.lastRefreshedAt : existing.lastRefreshedAt,
|
|
236
|
-
data.connectedByUserId !== undefined ? data.connectedByUserId : existing.connectedByUserId,
|
|
237
|
-
existing.id
|
|
238
|
-
]);
|
|
239
|
-
return await getAuthorizationById(existing.id);
|
|
240
|
-
}
|
|
241
|
-
const id = data.id ?? crypto.randomUUID();
|
|
242
|
-
await getDbClient().run(`INSERT INTO oauth_authorizations (
|
|
243
|
-
id, appId, label, userId, accountEmail, identityJson,
|
|
244
|
-
accessToken, refreshToken, tokenType, expiresAt, scope,
|
|
245
|
-
tokensEncrypted, tokenVersion, status, lastErrorMessage,
|
|
246
|
-
lastRefreshedAt, connectedByUserId
|
|
247
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?, ?, ?)`, [
|
|
248
|
-
id,
|
|
249
|
-
data.appId,
|
|
250
|
-
label,
|
|
251
|
-
data.userId ?? null,
|
|
252
|
-
data.accountEmail ?? null,
|
|
253
|
-
data.identityJson ?? null,
|
|
254
|
-
accessToken,
|
|
255
|
-
refreshToken ?? null,
|
|
256
|
-
data.tokenType ?? "Bearer",
|
|
257
|
-
data.expiresAt ?? null,
|
|
258
|
-
data.scope ?? null,
|
|
259
|
-
data.status ?? "active",
|
|
260
|
-
data.lastErrorMessage ?? null,
|
|
261
|
-
data.lastRefreshedAt ?? null,
|
|
262
|
-
data.connectedByUserId ?? null
|
|
263
|
-
]);
|
|
264
|
-
return await getAuthorizationById(id);
|
|
265
|
-
}
|
|
266
|
-
async function updateAuthorizationTokens(id, data) {
|
|
267
|
-
const existing = await getAuthorizationById(id);
|
|
268
|
-
if (!existing)
|
|
269
|
-
return null;
|
|
270
|
-
const expectedVersion = data.expectedTokenVersion ?? existing.tokenVersion;
|
|
271
|
-
const key = getEncryptionKey();
|
|
272
|
-
const encryptedRefresh = data.refreshToken === undefined ? existing.refreshToken == null ? null : encryptSecret(existing.refreshToken, key) : data.refreshToken == null ? null : encryptSecret(data.refreshToken, key);
|
|
273
|
-
const result = await getDbClient().run(`UPDATE oauth_authorizations SET
|
|
274
|
-
accessToken = ?, refreshToken = ?, expiresAt = ?, scope = ?,
|
|
275
|
-
tokensEncrypted = 1, tokenVersion = tokenVersion + 1,
|
|
276
|
-
status = 'active', lastErrorMessage = NULL,
|
|
277
|
-
lastRefreshedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
|
|
278
|
-
updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
279
|
-
WHERE id = ? AND tokenVersion = ?`, [
|
|
280
|
-
encryptSecret(data.accessToken, key),
|
|
281
|
-
encryptedRefresh,
|
|
282
|
-
data.expiresAt !== undefined ? data.expiresAt : existing.expiresAt,
|
|
283
|
-
data.scope !== undefined ? data.scope : existing.scope,
|
|
284
|
-
id,
|
|
285
|
-
expectedVersion
|
|
286
|
-
]);
|
|
287
|
-
return result.changes === 1 ? await getAuthorizationById(id) : null;
|
|
288
|
-
}
|
|
289
|
-
async function updateAuthorizationIdentity(id, data) {
|
|
290
|
-
await getDbClient().run(`UPDATE oauth_authorizations SET
|
|
291
|
-
accountEmail = ?, identityJson = ?,
|
|
292
|
-
updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
293
|
-
WHERE id = ?`, [data.accountEmail ?? null, data.identityJson ?? null, id]);
|
|
294
|
-
}
|
|
295
|
-
async function deleteAuthorizationById(id) {
|
|
296
|
-
const result = await getDbClient().run("DELETE FROM oauth_authorizations WHERE id = ?", [id]);
|
|
297
|
-
return result.changes > 0;
|
|
298
|
-
}
|
|
299
|
-
async function deleteAuthorizationsForApp(appId) {
|
|
300
|
-
return (await getDbClient().run("DELETE FROM oauth_authorizations WHERE appId = ?", [appId])).changes;
|
|
301
|
-
}
|
|
302
|
-
var OAUTH_PENDING_TTL_MS = 10 * 60 * 1000;
|
|
303
|
-
async function createOAuthPending(input) {
|
|
304
|
-
await getDbClient().run(`INSERT INTO oauth_pending (
|
|
305
|
-
state, appId, label, flow, codeVerifier, nonce,
|
|
306
|
-
redirectUri, finalRedirect, userId, contextJson
|
|
307
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
308
|
-
input.state,
|
|
309
|
-
input.appId,
|
|
310
|
-
input.label ?? "default",
|
|
311
|
-
input.flow ?? "generic",
|
|
312
|
-
encryptSecret(input.codeVerifier, getEncryptionKey()),
|
|
313
|
-
input.nonce ?? null,
|
|
314
|
-
input.redirectUri,
|
|
315
|
-
input.finalRedirect ?? null,
|
|
316
|
-
input.userId ?? null,
|
|
317
|
-
input.contextJson ?? "{}"
|
|
318
|
-
]);
|
|
319
|
-
}
|
|
320
|
-
async function consumeOAuthPending(state) {
|
|
321
|
-
return await getDbClient().transaction(async (tx) => {
|
|
322
|
-
const row = await tx.get(`SELECT state, appId, label, flow, codeVerifier, nonce, redirectUri,
|
|
323
|
-
finalRedirect, userId, contextJson, createdAt
|
|
324
|
-
FROM oauth_pending
|
|
325
|
-
WHERE state = ? AND flow IN ('generic', 'tracker')`, [state]);
|
|
326
|
-
if (!row)
|
|
327
|
-
return null;
|
|
328
|
-
await tx.run("DELETE FROM oauth_pending WHERE state = ?", [state]);
|
|
329
|
-
const createdAt = normalizeDateRequired(row.createdAt);
|
|
330
|
-
const createdMs = new Date(createdAt).getTime();
|
|
331
|
-
if (Number.isNaN(createdMs) || Date.now() - createdMs > OAUTH_PENDING_TTL_MS) {
|
|
332
|
-
return null;
|
|
333
|
-
}
|
|
334
|
-
return {
|
|
335
|
-
...row,
|
|
336
|
-
codeVerifier: decryptSecret(row.codeVerifier, getEncryptionKey()),
|
|
337
|
-
createdAt
|
|
338
|
-
};
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
async function gcOAuthPending(olderThanMs = 10 * 60 * 1000) {
|
|
342
|
-
const cutoff = new Date(Date.now() - olderThanMs).toISOString();
|
|
343
|
-
const result = await getDbClient().run("DELETE FROM oauth_pending WHERE flow IN ('generic', 'tracker') AND createdAt < ?", [cutoff]);
|
|
344
|
-
return result.changes;
|
|
345
|
-
}
|
|
346
|
-
async function markAuthorizationRefreshFailed(id, message) {
|
|
347
|
-
const result = await getDbClient().run(`UPDATE oauth_authorizations SET
|
|
348
|
-
status = 'refresh-failed', lastErrorMessage = ?,
|
|
349
|
-
updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
350
|
-
WHERE id = ? AND status != 'revoked'`, [message, id]);
|
|
351
|
-
return result.changes === 1 ? await getAuthorizationById(id) : null;
|
|
352
|
-
}
|
|
353
|
-
async function getOAuthTokens(provider) {
|
|
354
|
-
const row = await rawDefaultAuthorizationForProvider(provider);
|
|
355
|
-
if (!row)
|
|
356
|
-
return null;
|
|
357
|
-
const authorization = normalizeAuthorization(row);
|
|
358
|
-
if (authorization.status === "revoked")
|
|
359
|
-
return null;
|
|
360
|
-
return {
|
|
361
|
-
id: authorization.id,
|
|
362
|
-
provider,
|
|
363
|
-
accessToken: authorization.accessToken,
|
|
364
|
-
refreshToken: authorization.refreshToken,
|
|
365
|
-
expiresAt: authorization.expiresAt ?? "",
|
|
366
|
-
scope: authorization.scope,
|
|
367
|
-
tokenVersion: authorization.tokenVersion,
|
|
368
|
-
createdAt: authorization.createdAt,
|
|
369
|
-
updatedAt: authorization.updatedAt
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
async function listAuthorizationSweepRows() {
|
|
373
|
-
const rows = await getDbClient().query(`SELECT z.id AS authorizationId,
|
|
374
|
-
z.appId AS appId,
|
|
375
|
-
a.provider AS provider,
|
|
376
|
-
z.label AS label,
|
|
377
|
-
z.status AS status,
|
|
378
|
-
CASE WHEN z.refreshToken IS NOT NULL AND z.refreshToken != '' THEN 1 ELSE 0 END AS hasRefreshToken,
|
|
379
|
-
COALESCE(z.expiresAt, '') AS expiresAt,
|
|
380
|
-
z.updatedAt AS updatedAt
|
|
381
|
-
FROM oauth_authorizations z
|
|
382
|
-
JOIN oauth_apps a ON a.id = z.appId
|
|
383
|
-
WHERE a.mcpServerId IS NULL
|
|
384
|
-
ORDER BY a.provider ASC, z.label ASC`);
|
|
385
|
-
return rows.map((row) => ({
|
|
386
|
-
authorizationId: row.authorizationId,
|
|
387
|
-
appId: row.appId,
|
|
388
|
-
provider: row.provider,
|
|
389
|
-
label: row.label,
|
|
390
|
-
status: row.status,
|
|
391
|
-
hasRefreshToken: row.hasRefreshToken === 1,
|
|
392
|
-
expiresAt: normalizeDateRequired(row.expiresAt),
|
|
393
|
-
updatedAt: normalizeDateRequired(row.updatedAt)
|
|
394
|
-
}));
|
|
395
|
-
}
|
|
396
|
-
async function listKeepAliveAuthorizations() {
|
|
397
|
-
const rows = await getDbClient().query(`SELECT z.id AS authorizationId,
|
|
398
|
-
z.appId AS appId,
|
|
399
|
-
a.provider AS provider,
|
|
400
|
-
z.label AS label,
|
|
401
|
-
a.displayName AS displayName
|
|
402
|
-
FROM oauth_authorizations z
|
|
403
|
-
JOIN oauth_apps a ON a.id = z.appId
|
|
404
|
-
WHERE a.mcpServerId IS NULL
|
|
405
|
-
AND z.status = 'active'
|
|
406
|
-
AND z.refreshToken IS NOT NULL AND z.refreshToken != ''
|
|
407
|
-
AND (
|
|
408
|
-
a.requiresRefreshTokenRotation = 1
|
|
409
|
-
OR (json_valid(a.metadata) = 1 AND json_extract(a.metadata, '$.keepAlive') IN (1, 'true'))
|
|
410
|
-
)
|
|
411
|
-
ORDER BY a.provider ASC, z.label ASC`);
|
|
412
|
-
return rows.map((row) => ({
|
|
413
|
-
authorizationId: row.authorizationId,
|
|
414
|
-
appId: row.appId,
|
|
415
|
-
provider: row.provider,
|
|
416
|
-
label: row.label,
|
|
417
|
-
displayName: row.displayName
|
|
418
|
-
}));
|
|
419
|
-
}
|
|
420
|
-
async function deleteOAuthTokens(provider) {
|
|
421
|
-
const app = await rawOAuthAppByProvider(provider);
|
|
422
|
-
if (!app)
|
|
423
|
-
return;
|
|
424
|
-
const existing = await rawDefaultAuthorizationForApp(app.id);
|
|
425
|
-
if (!existing)
|
|
426
|
-
return;
|
|
427
|
-
await getDbClient().run(`UPDATE oauth_authorizations SET
|
|
428
|
-
accessToken = ?, refreshToken = NULL, expiresAt = NULL, scope = NULL,
|
|
429
|
-
tokensEncrypted = 1, tokenVersion = tokenVersion + 1,
|
|
430
|
-
status = 'revoked', lastErrorMessage = NULL, lastRefreshedAt = NULL,
|
|
431
|
-
updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
432
|
-
WHERE id = ?`, [encryptSecret("", getEncryptionKey()), existing.id]);
|
|
433
|
-
}
|
|
434
|
-
async function acquireOAuthRefreshLock(lockKey, ttlMs) {
|
|
435
|
-
const owner = crypto.randomUUID();
|
|
436
|
-
const now = Date.now();
|
|
437
|
-
const expiresAt = new Date(now + ttlMs).toISOString();
|
|
438
|
-
const nowIso = new Date(now).toISOString();
|
|
439
|
-
await getDbClient().run(`INSERT INTO oauth_refresh_locks (lockKey, owner, expiresAt, createdAt, updatedAt)
|
|
440
|
-
VALUES (?, ?, ?, ?, ?)
|
|
441
|
-
ON CONFLICT(lockKey) DO UPDATE SET
|
|
442
|
-
owner = excluded.owner,
|
|
443
|
-
expiresAt = excluded.expiresAt,
|
|
444
|
-
updatedAt = excluded.updatedAt
|
|
445
|
-
WHERE oauth_refresh_locks.expiresAt <= ?`, [lockKey, owner, expiresAt, nowIso, nowIso, nowIso]);
|
|
446
|
-
const row = await getDbClient().get("SELECT owner FROM oauth_refresh_locks WHERE lockKey = ?", [lockKey]);
|
|
447
|
-
return row?.owner === owner ? owner : null;
|
|
448
|
-
}
|
|
449
|
-
async function releaseOAuthRefreshLock(lockKey, owner) {
|
|
450
|
-
await getDbClient().run("DELETE FROM oauth_refresh_locks WHERE lockKey = ? AND owner = ?", [
|
|
451
|
-
lockKey,
|
|
452
|
-
owner
|
|
453
|
-
]);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// src/oauth/ensure-token.ts
|
|
457
|
-
init_secret_scrubber();
|
|
458
|
-
|
|
459
|
-
// node_modules/oauth4webapi/build/index.js
|
|
460
|
-
var USER_AGENT;
|
|
461
|
-
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) {
|
|
462
|
-
const NAME = "oauth4webapi";
|
|
463
|
-
const VERSION = "v3.8.5";
|
|
464
|
-
USER_AGENT = `${NAME}/${VERSION}`;
|
|
465
|
-
}
|
|
466
|
-
var ERR_INVALID_ARG_VALUE = "ERR_INVALID_ARG_VALUE";
|
|
467
|
-
var ERR_INVALID_ARG_TYPE = "ERR_INVALID_ARG_TYPE";
|
|
468
|
-
function CodedTypeError(message, code, cause) {
|
|
469
|
-
const err = new TypeError(message, { cause });
|
|
470
|
-
Object.assign(err, { code });
|
|
471
|
-
return err;
|
|
472
|
-
}
|
|
473
|
-
var allowInsecureRequests = Symbol();
|
|
474
|
-
var clockSkew = Symbol();
|
|
475
|
-
var clockTolerance = Symbol();
|
|
476
|
-
var customFetch = Symbol();
|
|
477
|
-
var modifyAssertion = Symbol();
|
|
478
|
-
var jweDecrypt = Symbol();
|
|
479
|
-
var jwksCache = Symbol();
|
|
480
|
-
var encoder = new TextEncoder;
|
|
481
|
-
var decoder = new TextDecoder;
|
|
482
|
-
function buf(input) {
|
|
483
|
-
if (typeof input === "string") {
|
|
484
|
-
return encoder.encode(input);
|
|
485
|
-
}
|
|
486
|
-
return decoder.decode(input);
|
|
487
|
-
}
|
|
488
|
-
var encodeBase64Url;
|
|
489
|
-
if (Uint8Array.prototype.toBase64) {
|
|
490
|
-
encodeBase64Url = (input) => {
|
|
491
|
-
if (input instanceof ArrayBuffer) {
|
|
492
|
-
input = new Uint8Array(input);
|
|
493
|
-
}
|
|
494
|
-
return input.toBase64({ alphabet: "base64url", omitPadding: true });
|
|
495
|
-
};
|
|
496
|
-
} else {
|
|
497
|
-
const CHUNK_SIZE = 32768;
|
|
498
|
-
encodeBase64Url = (input) => {
|
|
499
|
-
if (input instanceof ArrayBuffer) {
|
|
500
|
-
input = new Uint8Array(input);
|
|
501
|
-
}
|
|
502
|
-
const arr = [];
|
|
503
|
-
for (let i = 0;i < input.byteLength; i += CHUNK_SIZE) {
|
|
504
|
-
arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
505
|
-
}
|
|
506
|
-
return btoa(arr.join("")).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
var decodeBase64Url;
|
|
510
|
-
if (Uint8Array.fromBase64) {
|
|
511
|
-
decodeBase64Url = (input) => {
|
|
512
|
-
try {
|
|
513
|
-
return Uint8Array.fromBase64(input, { alphabet: "base64url" });
|
|
514
|
-
} catch (cause) {
|
|
515
|
-
throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
} else {
|
|
519
|
-
decodeBase64Url = (input) => {
|
|
520
|
-
try {
|
|
521
|
-
const binary = atob(input.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""));
|
|
522
|
-
const bytes = new Uint8Array(binary.length);
|
|
523
|
-
for (let i = 0;i < binary.length; i++) {
|
|
524
|
-
bytes[i] = binary.charCodeAt(i);
|
|
525
|
-
}
|
|
526
|
-
return bytes;
|
|
527
|
-
} catch (cause) {
|
|
528
|
-
throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
function b64u(input) {
|
|
533
|
-
if (typeof input === "string") {
|
|
534
|
-
return decodeBase64Url(input);
|
|
535
|
-
}
|
|
536
|
-
return encodeBase64Url(input);
|
|
537
|
-
}
|
|
538
|
-
class OperationProcessingError extends Error {
|
|
539
|
-
code;
|
|
540
|
-
constructor(message, options) {
|
|
541
|
-
super(message, options);
|
|
542
|
-
this.name = this.constructor.name;
|
|
543
|
-
if (options?.code) {
|
|
544
|
-
this.code = options?.code;
|
|
545
|
-
}
|
|
546
|
-
Error.captureStackTrace?.(this, this.constructor);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
function OPE(message, code, cause) {
|
|
550
|
-
return new OperationProcessingError(message, { code, cause });
|
|
551
|
-
}
|
|
552
|
-
function assertString(input, it, code, cause) {
|
|
553
|
-
try {
|
|
554
|
-
if (typeof input !== "string") {
|
|
555
|
-
throw CodedTypeError(`${it} must be a string`, ERR_INVALID_ARG_TYPE, cause);
|
|
556
|
-
}
|
|
557
|
-
if (input.length === 0) {
|
|
558
|
-
throw CodedTypeError(`${it} must not be empty`, ERR_INVALID_ARG_VALUE, cause);
|
|
559
|
-
}
|
|
560
|
-
} catch (err) {
|
|
561
|
-
if (code) {
|
|
562
|
-
throw OPE(err.message, code, cause);
|
|
563
|
-
}
|
|
564
|
-
throw err;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
function randomBytes() {
|
|
568
|
-
return b64u(crypto.getRandomValues(new Uint8Array(32)));
|
|
569
|
-
}
|
|
570
|
-
function generateRandomCodeVerifier() {
|
|
571
|
-
return randomBytes();
|
|
572
|
-
}
|
|
573
|
-
function generateRandomState() {
|
|
574
|
-
return randomBytes();
|
|
575
|
-
}
|
|
576
|
-
async function calculatePKCECodeChallenge(codeVerifier) {
|
|
577
|
-
assertString(codeVerifier, "codeVerifier");
|
|
578
|
-
return b64u(await crypto.subtle.digest("SHA-256", buf(codeVerifier)));
|
|
579
|
-
}
|
|
580
|
-
var URLParse = URL.parse ? (url, base) => URL.parse(url, base) : (url, base) => {
|
|
581
|
-
try {
|
|
582
|
-
return new URL(url, base);
|
|
583
|
-
} catch {
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
};
|
|
587
|
-
var tokenMatch = "[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+";
|
|
588
|
-
var token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}";
|
|
589
|
-
var quotedMatch = '"((?:[^"\\\\]|\\\\[\\s\\S])*)"';
|
|
590
|
-
var quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*" + quotedMatch;
|
|
591
|
-
var paramMatcher = "(" + tokenMatch + ")\\s*=\\s*(" + tokenMatch + ")";
|
|
592
|
-
var schemeRE = new RegExp("^[,\\s]*(" + tokenMatch + ")");
|
|
593
|
-
var quotedParamRE = new RegExp("^[,\\s]*" + quotedParamMatcher + "[,\\s]*(.*)");
|
|
594
|
-
var unquotedParamRE = new RegExp("^[,\\s]*" + paramMatcher + "[,\\s]*(.*)");
|
|
595
|
-
var token68ParamRE = new RegExp("^(" + token68Match + ")(?:$|[,\\s])(.*)");
|
|
596
|
-
var skipSubjectCheck = Symbol();
|
|
597
|
-
var idTokenClaims = new WeakMap;
|
|
598
|
-
var jwtRefs = new WeakMap;
|
|
599
|
-
var branded = new WeakSet;
|
|
600
|
-
var nopkce = Symbol();
|
|
601
|
-
var expectNoNonce = Symbol();
|
|
602
|
-
var skipAuthTimeCheck = Symbol();
|
|
603
|
-
var skipStateCheck = Symbol();
|
|
604
|
-
var expectNoState = Symbol();
|
|
605
|
-
var _nodiscoverycheck = Symbol();
|
|
606
|
-
var _expectedIssuer = Symbol();
|
|
607
|
-
|
|
608
|
-
// src/oauth/wrapper.ts
|
|
609
|
-
async function buildAuthorizationUrl(config, options = {}) {
|
|
610
|
-
const state = generateRandomState();
|
|
611
|
-
const codeVerifier = generateRandomCodeVerifier();
|
|
612
|
-
const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
|
|
613
|
-
const appId = options.appId ?? await getOAuthAppIdByProvider(config.provider);
|
|
614
|
-
if (!appId) {
|
|
615
|
-
throw new Error(`OAuth app ${config.provider} is not configured`);
|
|
616
|
-
}
|
|
617
|
-
await createOAuthPending({
|
|
618
|
-
state,
|
|
619
|
-
appId,
|
|
620
|
-
label: options.label ?? "default",
|
|
621
|
-
flow: options.flow ?? "generic",
|
|
622
|
-
codeVerifier,
|
|
623
|
-
nonce: options.nonce ?? null,
|
|
624
|
-
redirectUri: config.redirectUri,
|
|
625
|
-
finalRedirect: options.finalRedirect ?? null,
|
|
626
|
-
userId: options.userId ?? null
|
|
627
|
-
});
|
|
628
|
-
const url = new URL(config.authorizeUrl);
|
|
629
|
-
url.searchParams.set("client_id", config.clientId);
|
|
630
|
-
url.searchParams.set("redirect_uri", config.redirectUri);
|
|
631
|
-
url.searchParams.set("response_type", "code");
|
|
632
|
-
url.searchParams.set("scope", config.scopes.join(config.scopeSeparator ?? ","));
|
|
633
|
-
url.searchParams.set("state", state);
|
|
634
|
-
url.searchParams.set("code_challenge", codeChallenge);
|
|
635
|
-
url.searchParams.set("code_challenge_method", "S256");
|
|
636
|
-
if (config.extraParams) {
|
|
637
|
-
for (const [key, value] of Object.entries(config.extraParams)) {
|
|
638
|
-
url.searchParams.set(key, value);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
return { url: url.toString(), state, codeVerifier };
|
|
642
|
-
}
|
|
643
|
-
function tokenRequestInit(config, params) {
|
|
644
|
-
const useBasic = config.tokenAuthStyle === "basic";
|
|
645
|
-
const bodyParams = useBasic ? params : { ...params, client_id: config.clientId, client_secret: config.clientSecret };
|
|
646
|
-
const headers = { Accept: "application/json" };
|
|
647
|
-
if (useBasic) {
|
|
648
|
-
headers.Authorization = `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`;
|
|
649
|
-
}
|
|
650
|
-
if (config.tokenBodyFormat === "json") {
|
|
651
|
-
headers["Content-Type"] = "application/json";
|
|
652
|
-
return { headers, body: JSON.stringify(bodyParams) };
|
|
653
|
-
}
|
|
654
|
-
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
655
|
-
return { headers, body: new URLSearchParams(bodyParams).toString() };
|
|
656
|
-
}
|
|
657
|
-
async function exchangeAuthorizationCode(config, params) {
|
|
658
|
-
const response = await fetch(config.tokenUrl, {
|
|
659
|
-
method: "POST",
|
|
660
|
-
...tokenRequestInit(config, {
|
|
661
|
-
grant_type: "authorization_code",
|
|
662
|
-
redirect_uri: params.redirectUri,
|
|
663
|
-
code: params.code,
|
|
664
|
-
code_verifier: params.codeVerifier
|
|
665
|
-
})
|
|
666
|
-
});
|
|
667
|
-
if (!response.ok) {
|
|
668
|
-
const errorText = await response.text();
|
|
669
|
-
throw new Error(`Token exchange failed (${response.status}): ${errorText}`);
|
|
670
|
-
}
|
|
671
|
-
const data = await response.json();
|
|
672
|
-
return {
|
|
673
|
-
accessToken: data.access_token,
|
|
674
|
-
refreshToken: data.refresh_token,
|
|
675
|
-
expiresIn: data.expires_in,
|
|
676
|
-
scope: data.scope,
|
|
677
|
-
tokenType: data.token_type,
|
|
678
|
-
idToken: data.id_token
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
async function performTokenRefreshRequest(config, refreshToken) {
|
|
682
|
-
const response = await fetch(config.tokenUrl, {
|
|
683
|
-
method: "POST",
|
|
684
|
-
...tokenRequestInit(config, {
|
|
685
|
-
grant_type: "refresh_token",
|
|
686
|
-
refresh_token: refreshToken
|
|
687
|
-
})
|
|
688
|
-
});
|
|
689
|
-
if (!response.ok) {
|
|
690
|
-
const errorText = await response.text();
|
|
691
|
-
throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
|
|
692
|
-
}
|
|
693
|
-
const data = await response.json();
|
|
694
|
-
if (typeof data.access_token !== "string" || data.access_token.length === 0) {
|
|
695
|
-
throw new Error(`Token refresh failed: ${config.provider} response missing access_token`);
|
|
696
|
-
}
|
|
697
|
-
if (config.requiresRefreshTokenRotation && (typeof data.refresh_token !== "string" || data.refresh_token.length === 0)) {
|
|
698
|
-
throw new Error(`Token refresh failed: ${config.provider} response did not include a rotated refresh_token`);
|
|
699
|
-
}
|
|
700
|
-
const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : null;
|
|
701
|
-
return {
|
|
702
|
-
accessToken: data.access_token,
|
|
703
|
-
refreshToken: data.refresh_token,
|
|
704
|
-
expiresIn: data.expires_in,
|
|
705
|
-
scope: data.scope,
|
|
706
|
-
expiresAt
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// src/oauth/ensure-token.ts
|
|
711
|
-
function parseMetadata(metadataJson) {
|
|
712
|
-
try {
|
|
713
|
-
const parsed = JSON.parse(metadataJson || "{}");
|
|
714
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
715
|
-
} catch {
|
|
716
|
-
return {};
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
function stringRecord(value) {
|
|
720
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
721
|
-
return;
|
|
722
|
-
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, String(item)]));
|
|
723
|
-
}
|
|
724
|
-
function oauthAppRowToProviderConfig(app) {
|
|
725
|
-
const metadata = parseMetadata(app.metadata);
|
|
726
|
-
const liftedExtraParams = stringRecord(parseMetadata(app.extraParamsJson));
|
|
727
|
-
const extraParams = {
|
|
728
|
-
...typeof metadata.actor === "string" ? { actor: metadata.actor } : {},
|
|
729
|
-
...liftedExtraParams
|
|
730
|
-
};
|
|
731
|
-
return {
|
|
732
|
-
provider: app.provider,
|
|
733
|
-
clientId: app.clientId,
|
|
734
|
-
clientSecret: app.clientSecret,
|
|
735
|
-
authorizeUrl: app.authorizeUrl,
|
|
736
|
-
tokenUrl: app.tokenUrl,
|
|
737
|
-
redirectUri: app.redirectUri,
|
|
738
|
-
scopes: app.scopes.split(",").map((scope) => scope.trim()).filter(Boolean),
|
|
739
|
-
extraParams: Object.keys(extraParams).length > 0 ? extraParams : undefined,
|
|
740
|
-
scopeSeparator: app.scopeSeparator,
|
|
741
|
-
tokenAuthStyle: app.tokenAuthStyle,
|
|
742
|
-
tokenBodyFormat: app.tokenBodyFormat,
|
|
743
|
-
requiresRefreshTokenRotation: app.requiresRefreshTokenRotation
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
class OAuthRefreshError extends Error {
|
|
748
|
-
authorizationId;
|
|
749
|
-
appId;
|
|
750
|
-
reason;
|
|
751
|
-
authorizationLabel;
|
|
752
|
-
constructor(authorizationId, appId, reason, authorizationLabel, message) {
|
|
753
|
-
super(message ?? `OAuth authorization '${authorizationLabel}' refresh failed (${reason})`);
|
|
754
|
-
this.authorizationId = authorizationId;
|
|
755
|
-
this.appId = appId;
|
|
756
|
-
this.reason = reason;
|
|
757
|
-
this.authorizationLabel = authorizationLabel;
|
|
758
|
-
this.name = "OAuthRefreshError";
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
function authorizationLabelFor(app, authorization) {
|
|
762
|
-
const base = app.displayName?.trim() || app.provider;
|
|
763
|
-
return authorization.label && authorization.label !== "default" ? `${base} (${authorization.label})` : base;
|
|
764
|
-
}
|
|
765
|
-
var refreshLocks = new Map;
|
|
766
|
-
var REFRESH_LOCK_TTL_MS = 2 * 60 * 1000;
|
|
767
|
-
var REFRESH_LOCK_WAIT_MS = 30 * 1000;
|
|
768
|
-
var REFRESH_LOCK_POLL_MS = 250;
|
|
769
|
-
var DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
770
|
-
async function withAuthorizationRefreshLock(authorizationId, fn) {
|
|
771
|
-
const previous = refreshLocks.get(authorizationId) ?? Promise.resolve();
|
|
772
|
-
let release;
|
|
773
|
-
const current = new Promise((resolve) => {
|
|
774
|
-
release = resolve;
|
|
775
|
-
});
|
|
776
|
-
const next = previous.catch(() => {
|
|
777
|
-
return;
|
|
778
|
-
}).then(() => current);
|
|
779
|
-
refreshLocks.set(authorizationId, next);
|
|
780
|
-
await previous.catch(() => {
|
|
781
|
-
return;
|
|
782
|
-
});
|
|
783
|
-
try {
|
|
784
|
-
return await fn();
|
|
785
|
-
} finally {
|
|
786
|
-
release();
|
|
787
|
-
if (refreshLocks.get(authorizationId) === next) {
|
|
788
|
-
refreshLocks.delete(authorizationId);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
function sleep(ms) {
|
|
793
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
794
|
-
}
|
|
795
|
-
function authorizationNeedsRefresh(authorization, bufferMs = DEFAULT_REFRESH_BUFFER_MS, force = false) {
|
|
796
|
-
if (authorization.status === "refresh-failed" || authorization.status === "expired")
|
|
797
|
-
return true;
|
|
798
|
-
if (force)
|
|
799
|
-
return true;
|
|
800
|
-
if (!authorization.expiresAt)
|
|
801
|
-
return false;
|
|
802
|
-
const expiresAt = new Date(authorization.expiresAt).getTime();
|
|
803
|
-
if (Number.isNaN(expiresAt))
|
|
804
|
-
return true;
|
|
805
|
-
return expiresAt - Date.now() < bufferMs;
|
|
806
|
-
}
|
|
807
|
-
var authorizationRefreshedListeners = new Set;
|
|
808
|
-
function onAuthorizationRefreshed(listener) {
|
|
809
|
-
authorizationRefreshedListeners.add(listener);
|
|
810
|
-
return () => {
|
|
811
|
-
authorizationRefreshedListeners.delete(listener);
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
function notifyAuthorizationRefreshed(event) {
|
|
815
|
-
for (const listener of authorizationRefreshedListeners) {
|
|
816
|
-
try {
|
|
817
|
-
listener(event);
|
|
818
|
-
} catch (err) {
|
|
819
|
-
console.error(scrubSecrets(`[OAuth] authorization-refreshed listener failed for ${event.provider}: ${err instanceof Error ? err.message : String(err)}`));
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
async function ensureAuthorizationTokenOrThrow(authorizationId, bufferMs, force = false) {
|
|
824
|
-
const initial = await getAuthorizationById(authorizationId);
|
|
825
|
-
if (!initial || initial.status === "revoked")
|
|
826
|
-
return;
|
|
827
|
-
if (!authorizationNeedsRefresh(initial, bufferMs, force))
|
|
828
|
-
return;
|
|
829
|
-
await withAuthorizationRefreshLock(authorizationId, async () => {
|
|
830
|
-
const waitStartedAt = Date.now();
|
|
831
|
-
while (true) {
|
|
832
|
-
const current = await getAuthorizationById(authorizationId);
|
|
833
|
-
if (!current || current.status === "revoked")
|
|
834
|
-
return;
|
|
835
|
-
if (current.tokenVersion !== initial.tokenVersion)
|
|
836
|
-
return;
|
|
837
|
-
if (!authorizationNeedsRefresh(current, bufferMs, force))
|
|
838
|
-
return;
|
|
839
|
-
const app = await getOAuthAppById(current.appId);
|
|
840
|
-
if (!app || app.mcpServerId !== null)
|
|
841
|
-
return;
|
|
842
|
-
if (!current.refreshToken) {
|
|
843
|
-
const label = authorizationLabelFor(app, current);
|
|
844
|
-
const message = `OAuth authorization '${label}' cannot refresh: no refresh token stored`;
|
|
845
|
-
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
846
|
-
throw new OAuthRefreshError(authorizationId, app.id, "no_refresh_token", label, message);
|
|
847
|
-
}
|
|
848
|
-
const lockOwner = await acquireOAuthRefreshLock(`authz:${authorizationId}`, REFRESH_LOCK_TTL_MS);
|
|
849
|
-
if (!lockOwner) {
|
|
850
|
-
if (Date.now() - waitStartedAt > REFRESH_LOCK_WAIT_MS) {
|
|
851
|
-
const label = authorizationLabelFor(app, current);
|
|
852
|
-
const message = `Timed out waiting for OAuth refresh lock for '${label}'`;
|
|
853
|
-
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
854
|
-
throw new OAuthRefreshError(authorizationId, app.id, "lock_timeout", label, message);
|
|
855
|
-
}
|
|
856
|
-
await sleep(REFRESH_LOCK_POLL_MS);
|
|
857
|
-
continue;
|
|
858
|
-
}
|
|
859
|
-
try {
|
|
860
|
-
const locked = await getAuthorizationById(authorizationId);
|
|
861
|
-
if (!locked || locked.status === "revoked")
|
|
862
|
-
return;
|
|
863
|
-
if (locked.tokenVersion !== initial.tokenVersion)
|
|
864
|
-
return;
|
|
865
|
-
if (!authorizationNeedsRefresh(locked, bufferMs, force))
|
|
866
|
-
return;
|
|
867
|
-
const lockedApp = await getOAuthAppById(locked.appId);
|
|
868
|
-
if (!lockedApp || lockedApp.mcpServerId !== null)
|
|
869
|
-
return;
|
|
870
|
-
if (!locked.refreshToken) {
|
|
871
|
-
const label = authorizationLabelFor(lockedApp, locked);
|
|
872
|
-
const message = `OAuth authorization '${label}' cannot refresh: no refresh token stored`;
|
|
873
|
-
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
874
|
-
throw new OAuthRefreshError(authorizationId, lockedApp.id, "no_refresh_token", label, message);
|
|
875
|
-
}
|
|
876
|
-
const config = oauthAppRowToProviderConfig(lockedApp);
|
|
877
|
-
try {
|
|
878
|
-
const refreshed = await performTokenRefreshRequest(config, locked.refreshToken);
|
|
879
|
-
const persisted = await updateAuthorizationTokens(authorizationId, {
|
|
880
|
-
accessToken: refreshed.accessToken,
|
|
881
|
-
refreshToken: refreshed.refreshToken ?? locked.refreshToken,
|
|
882
|
-
expiresAt: refreshed.expiresAt,
|
|
883
|
-
scope: refreshed.scope ?? null,
|
|
884
|
-
expectedTokenVersion: locked.tokenVersion
|
|
885
|
-
});
|
|
886
|
-
if (!persisted) {
|
|
887
|
-
continue;
|
|
888
|
-
}
|
|
889
|
-
notifyAuthorizationRefreshed({
|
|
890
|
-
authorizationId,
|
|
891
|
-
appId: lockedApp.id,
|
|
892
|
-
provider: lockedApp.provider
|
|
893
|
-
});
|
|
894
|
-
return;
|
|
895
|
-
} catch (err) {
|
|
896
|
-
const label = authorizationLabelFor(lockedApp, locked);
|
|
897
|
-
if (locked.refreshToken)
|
|
898
|
-
registerVolatileSecret(locked.refreshToken, "oauth-refresh-token");
|
|
899
|
-
if (locked.accessToken)
|
|
900
|
-
registerVolatileSecret(locked.accessToken, "oauth-access-token");
|
|
901
|
-
if (lockedApp.clientSecret)
|
|
902
|
-
registerVolatileSecret(lockedApp.clientSecret, "oauth-client-secret");
|
|
903
|
-
const message = scrubSecrets(err instanceof Error ? err.message : String(err));
|
|
904
|
-
await markAuthorizationRefreshFailed(authorizationId, message);
|
|
905
|
-
if (err instanceof OAuthRefreshError)
|
|
906
|
-
throw err;
|
|
907
|
-
throw new OAuthRefreshError(authorizationId, lockedApp.id, "refresh_rejected", label, message);
|
|
908
|
-
}
|
|
909
|
-
} finally {
|
|
910
|
-
await releaseOAuthRefreshLock(`authz:${authorizationId}`, lockOwner);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
async function forceRefreshAuthorizationOrThrow(authorizationId) {
|
|
916
|
-
await ensureAuthorizationTokenOrThrow(authorizationId, undefined, true);
|
|
917
|
-
}
|
|
918
|
-
async function ensureToken(provider, bufferMs) {
|
|
919
|
-
try {
|
|
920
|
-
await ensureTokenOrThrow(provider, bufferMs);
|
|
921
|
-
} catch (err) {
|
|
922
|
-
console.error(`[OAuth] Failed to refresh ${provider} token:`, err instanceof Error ? err.message : err);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
async function ensureTokenOrThrow(provider, bufferMs) {
|
|
926
|
-
const authorizationId = await getDefaultAuthorizationIdForProvider(provider);
|
|
927
|
-
if (!authorizationId)
|
|
928
|
-
return;
|
|
929
|
-
try {
|
|
930
|
-
await ensureAuthorizationTokenOrThrow(authorizationId, bufferMs);
|
|
931
|
-
} catch (err) {
|
|
932
|
-
if (err instanceof OAuthRefreshError && err.reason === "no_refresh_token") {
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
throw err;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
async function forceRefreshTokenOrThrow(provider) {
|
|
939
|
-
const authorizationId = await getDefaultAuthorizationIdForProvider(provider);
|
|
940
|
-
if (!authorizationId)
|
|
941
|
-
return;
|
|
942
|
-
try {
|
|
943
|
-
await forceRefreshAuthorizationOrThrow(authorizationId);
|
|
944
|
-
} catch (err) {
|
|
945
|
-
if (err instanceof OAuthRefreshError && err.reason === "no_refresh_token")
|
|
946
|
-
return;
|
|
947
|
-
throw err;
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
export { getDefaultAuthorizationIdForProvider, getOAuthApp, getOAuthAppById, getOAuthAppIdByProvider, createOAuthApp, updateOAuthAppById, upsertOAuthApp, listAuthorizationsForApp, getAuthorizationById, upsertAuthorization, updateAuthorizationTokens, updateAuthorizationIdentity, deleteAuthorizationById, deleteAuthorizationsForApp, consumeOAuthPending, gcOAuthPending, getOAuthTokens, listAuthorizationSweepRows, listKeepAliveAuthorizations, deleteOAuthTokens, acquireOAuthRefreshLock, releaseOAuthRefreshLock, generateRandomCodeVerifier, generateRandomState, calculatePKCECodeChallenge, buildAuthorizationUrl, exchangeAuthorizationCode, oauthAppRowToProviderConfig, onAuthorizationRefreshed, ensureAuthorizationTokenOrThrow, forceRefreshAuthorizationOrThrow, ensureToken, ensureTokenOrThrow, forceRefreshTokenOrThrow };
|