@desplega.ai/agent-swarm 1.113.0 → 1.115.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.
Files changed (237) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-q4n7cz6e.js → actions-17ya5wde.js} +8 -9
  3. package/dist/{app-es4nzc71.js → app-4f718yk0.js} +6 -6
  4. package/dist/{assistant-0x8ey0vs.js → assistant-ah7csnjz.js} +19 -18
  5. package/dist/{boot-reembed-69agkhv6.js → boot-reembed-4jpxhb25.js} +6 -6
  6. package/dist/{boot-reembed-p0ny05t8.js → boot-reembed-qata34xa.js} +5 -5
  7. package/dist/{boot-scrub-logs-yybrkmvr.js → boot-scrub-logs-tv48nn3z.js} +4 -4
  8. package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-3csn5bks.js} +3 -3
  9. package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
  10. package/dist/cli-0pygq9r1.js +429 -0
  11. package/dist/{cli-hsetkkd3.js → cli-12vb0xg6.js} +33 -9
  12. package/dist/{cli-ncfgsqbd.js → cli-15y7qhzp.js} +262 -33
  13. package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
  14. package/dist/{cli-36ymmpmp.js → cli-3samkyap.js} +2 -2
  15. package/dist/cli-52fg7s7x.js +269 -0
  16. package/dist/{cli-hjhvekf4.js → cli-65ekje01.js} +11 -8
  17. package/dist/{cli-h3k622d0.js → cli-6aq8xhvm.js} +90 -3
  18. package/dist/{cli-f3qa069v.js → cli-7xje5amz.js} +1 -1
  19. package/dist/cli-86fdnerz.js +405 -0
  20. package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
  21. package/dist/{cli-c3frqf65.js → cli-b23axgz4.js} +3 -3
  22. package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
  23. package/dist/{cli-bnzbn8j8.js → cli-beea4a3y.js} +73 -24
  24. package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
  25. package/dist/{cli-pwc5e83c.js → cli-cchksf5q.js} +12 -7
  26. package/dist/{cli-30bbaveh.js → cli-cmw9rzy5.js} +2 -2
  27. package/dist/{cli-y6mrptcn.js → cli-cnwssmsr.js} +1 -1
  28. package/dist/{cli-r5g6ngtn.js → cli-dcca6j8m.js} +46 -5
  29. package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
  30. package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
  31. package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
  32. package/dist/{cli-4xyj9jtq.js → cli-hrhye2rm.js} +1062 -478
  33. package/dist/cli-jkhwmmgg.js +136 -0
  34. package/dist/{cli-y4ycrnjc.js → cli-k3y4z3h5.js} +1 -1
  35. package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
  36. package/dist/{cli-2fc97xm5.js → cli-mnbgv3w7.js} +4 -4
  37. package/dist/{cli-trmapn9k.js → cli-pet3aev6.js} +95 -10
  38. package/dist/{cli-z46pnksz.js → cli-q1rx7g0d.js} +175 -28
  39. package/dist/{cli-qwgtacd6.js → cli-r9f6ngrf.js} +1244 -336
  40. package/dist/{cli-gtkqc144.js → cli-shvaxw27.js} +13 -7
  41. package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
  42. package/dist/cli-t0vqevnm.js +393 -0
  43. package/dist/{cli-tbw13sx8.js → cli-tece6zgm.js} +1 -1
  44. package/dist/{cli-bgvskydy.js → cli-tffvrh6j.js} +1 -1
  45. package/dist/cli-wh91zby6.js +187222 -0
  46. package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
  47. package/dist/{cli-mq580e06.js → cli-zsrdty74.js} +18 -18
  48. package/dist/cli.js +32 -15
  49. package/dist/{codex-adapter-5cmy858w.js → codex-adapter-de3w0nch.js} +10 -10
  50. package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-bnw8cysk.js} +10 -10
  51. package/dist/{commands-z5dbwta3.js → commands-hch4e2k1.js} +4 -4
  52. package/dist/{db-bbgahh4z.js → db-p3h2j06x.js} +14 -4
  53. package/dist/{handlers-6b44317z.js → handlers-9er4zx9q.js} +17 -31
  54. package/dist/{hook-sbp5fmps.js → hook-4axs756z.js} +7 -7
  55. package/dist/{http-2xz43gz3.js → http-809fvtz2.js} +1934 -886
  56. package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
  57. package/dist/{index-nhat35em.js → index-47em3d2n.js} +14 -11
  58. package/dist/{index-5ghxn8s6.js → index-9fqaktjr.js} +12 -9
  59. package/dist/{index-0gzmqj4k.js → index-9ht8gr56.js} +13 -10
  60. package/dist/{index-vfedgdw6.js → index-rm85cfdx.js} +368 -40
  61. package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
  62. package/dist/{keepalive-62gfj91d.js → keepalive-3cps6e3e.js} +7 -6
  63. package/dist/{lead-ag0akn0v.js → lead-fkk95wgq.js} +36 -32
  64. package/dist/{maintenance-xxrrzk5x.js → maintenance-fweqh0yj.js} +6 -6
  65. package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
  66. package/dist/oauth-refresh-sweep-sycqtbph.js +114 -0
  67. package/dist/{onboard-64zyfcbs.js → onboard-cy0rkgvx.js} +2 -2
  68. package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
  69. package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
  70. package/dist/{otel-impl-b86qseaa.js → otel-impl-wbns8hf7.js} +1 -1
  71. package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-05sck1ds.js} +17 -109
  72. package/dist/{pricing-refresh-cgtkffpa.js → pricing-refresh-0hvazmkf.js} +6 -6
  73. package/dist/rbac-roles-kfesjy9y.js +28 -0
  74. package/dist/rbac-roles-mwcwhbxc.js +283 -0
  75. package/dist/{seed-pricing-1r1y1xkq.js → seed-pricing-h2kdq4cq.js} +5 -5
  76. package/dist/{setup-mkcgkjf7.js → setup-8506q97w.js} +2 -2
  77. package/dist/{worker-351sze63.js → worker-4r5c6zyb.js} +36 -32
  78. package/openapi.json +1327 -20
  79. package/package.json +3 -3
  80. package/src/agentmail/handlers.ts +16 -6
  81. package/src/agentmail/templates.ts +25 -5
  82. package/src/be/audit-user.ts +28 -4
  83. package/src/be/db-queries/oauth.ts +42 -0
  84. package/src/be/db.ts +314 -28
  85. package/src/be/identity.ts +79 -0
  86. package/src/be/mcp-proxy.ts +132 -0
  87. package/src/be/migrations/109_rbac_roles.sql +79 -0
  88. package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
  89. package/src/be/migrations/112_script_connections_graphql.sql +96 -0
  90. package/src/be/migrations/113_task_routing_affinity.sql +9 -0
  91. package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
  92. package/src/be/modelsdev-cache.json +135 -0
  93. package/src/be/oauth-credential-bindings.ts +35 -0
  94. package/src/be/oauth-refresh-sweep.ts +159 -0
  95. package/src/be/rbac-audit.ts +52 -13
  96. package/src/be/rbac-roles.ts +424 -0
  97. package/src/be/script-connections.ts +459 -40
  98. package/src/be/script-credential-broker.ts +29 -3
  99. package/src/be/scripts/typecheck.ts +51 -7
  100. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
  101. package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
  102. package/src/be/users.ts +24 -0
  103. package/src/cli.tsx +17 -0
  104. package/src/github/handlers.ts +10 -9
  105. package/src/github/templates.ts +45 -9
  106. package/src/gitlab/handlers.ts +20 -8
  107. package/src/gitlab/templates.ts +18 -6
  108. package/src/heartbeat/heartbeat.ts +143 -21
  109. package/src/http/all-routes.ts +3 -0
  110. package/src/http/approval-requests.ts +12 -0
  111. package/src/http/config.ts +44 -10
  112. package/src/http/core.ts +30 -3
  113. package/src/http/favorites.ts +1 -5
  114. package/src/http/index.ts +25 -1
  115. package/src/http/mcp-oauth.ts +2 -0
  116. package/src/http/mcp-servers.ts +44 -3
  117. package/src/http/oauth-generic.ts +105 -0
  118. package/src/http/poll.ts +20 -3
  119. package/src/http/script-connection-proxy.ts +116 -0
  120. package/src/http/script-connections.ts +1657 -0
  121. package/src/http/scripts.ts +27 -7
  122. package/src/http/skills.ts +11 -0
  123. package/src/http/tasks.ts +27 -13
  124. package/src/http/x.ts +6 -2
  125. package/src/integrations/kapso/inbound.ts +23 -6
  126. package/src/jira/sync.ts +111 -17
  127. package/src/jira/templates.ts +10 -2
  128. package/src/mcp-client/http-client.ts +194 -0
  129. package/src/oauth/app-validation.ts +16 -0
  130. package/src/oauth/ensure-token.ts +69 -14
  131. package/src/oauth/mcp-wrapper.ts +15 -0
  132. package/src/oauth/wrapper.ts +48 -20
  133. package/src/prompts/session-templates.ts +3 -3
  134. package/src/providers/codex-models.ts +100 -30
  135. package/src/providers/modelsdev-reasoning.json +51 -0
  136. package/src/providers/pi-mono-mcp-client.ts +2 -133
  137. package/src/providers/reasoning-effort.ts +11 -5
  138. package/src/rbac/admission.ts +68 -0
  139. package/src/rbac/index.ts +2 -0
  140. package/src/rbac/legacy-policy.ts +12 -0
  141. package/src/rbac/permissions.ts +48 -0
  142. package/src/scheduler/scheduler.ts +9 -1
  143. package/src/scripts-runtime/api-client.ts +151 -19
  144. package/src/scripts-runtime/api-types.ts +38 -6
  145. package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
  146. package/src/scripts-runtime/credential-broker/types.ts +8 -0
  147. package/src/scripts-runtime/ctx.ts +11 -1
  148. package/src/scripts-runtime/eval-harness.ts +5 -1
  149. package/src/scripts-runtime/executors/types.ts +2 -1
  150. package/src/scripts-runtime/loader.ts +3 -1
  151. package/src/scripts-runtime/mcp-client.ts +87 -0
  152. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  153. package/src/scripts-runtime/types/stdlib.d.ts +6 -0
  154. package/src/scripts-runtime/types/swarm-sdk.d.ts +19 -0
  155. package/src/server-user.ts +114 -59
  156. package/src/server.ts +12 -0
  157. package/src/slack/assistant.ts +14 -6
  158. package/src/slack/enrich.ts +17 -0
  159. package/src/slack/handlers.ts +8 -22
  160. package/src/slack/responses.ts +91 -1
  161. package/src/slack/thread-buffer.ts +6 -3
  162. package/src/slack/watcher.ts +9 -6
  163. package/src/tasks/worker-follow-up.ts +100 -3
  164. package/src/tests/agentmail-handlers.test.ts +32 -3
  165. package/src/tests/approval-requests.test.ts +61 -0
  166. package/src/tests/audit-user.test.ts +47 -1
  167. package/src/tests/codex-adapter.test.ts +46 -23
  168. package/src/tests/credential-broker.test.ts +5 -2
  169. package/src/tests/delete-page-tool.test.ts +197 -0
  170. package/src/tests/github-handlers.test.ts +28 -2
  171. package/src/tests/gitlab-handlers.test.ts +125 -0
  172. package/src/tests/heartbeat.test.ts +48 -3
  173. package/src/tests/identity.test.ts +117 -0
  174. package/src/tests/jira-sync.test.ts +99 -1
  175. package/src/tests/kapso-inbound.test.ts +7 -0
  176. package/src/tests/mcp-tools-user.test.ts +60 -6
  177. package/src/tests/model-control.test.ts +8 -2
  178. package/src/tests/oauth-credential-bindings.test.ts +490 -0
  179. package/src/tests/oauth-refresh-sweep.test.ts +160 -0
  180. package/src/tests/pool-affinity.test.ts +401 -0
  181. package/src/tests/prompt-template-remaining.test.ts +2 -2
  182. package/src/tests/rbac-admission-e2e.test.ts +386 -0
  183. package/src/tests/rbac-admission.test.ts +492 -0
  184. package/src/tests/rbac-e2e-helpers.ts +3 -0
  185. package/src/tests/rbac-engine.test.ts +50 -0
  186. package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
  187. package/src/tests/rbac-roles.test.ts +328 -0
  188. package/src/tests/reasoning-effort.test.ts +15 -2
  189. package/src/tests/schedule-target-type.test.ts +50 -0
  190. package/src/tests/scheduled-tasks.test.ts +40 -0
  191. package/src/tests/script-apis-mcp.test.ts +37 -13
  192. package/src/tests/script-connections-http.test.ts +1158 -0
  193. package/src/tests/script-connections-mcp.test.ts +894 -0
  194. package/src/tests/script-connections.test.ts +754 -6
  195. package/src/tests/scripts-external-api.test.ts +49 -1
  196. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
  197. package/src/tests/scripts-runtime.test.ts +291 -0
  198. package/src/tests/seed-scripts.test.ts +36 -0
  199. package/src/tests/slack-identity-resolution.test.ts +37 -3
  200. package/src/tests/slack-inline-output.test.ts +65 -0
  201. package/src/tests/slack-thread-buffer.test.ts +28 -0
  202. package/src/tests/tool-annotations.test.ts +1 -0
  203. package/src/tests/user-token-rest-auth.test.ts +140 -1
  204. package/src/tests/workflow-swarm-script.test.ts +44 -0
  205. package/src/tests/workflow-triggers-v2.test.ts +300 -1
  206. package/src/tools/credential-bindings/tool.ts +277 -18
  207. package/src/tools/delete-page.ts +145 -0
  208. package/src/tools/mcp-servers/mcp-server-delete.ts +7 -4
  209. package/src/tools/request-human-input.ts +2 -0
  210. package/src/tools/resolve-user.ts +77 -27
  211. package/src/tools/script-apis.ts +62 -3
  212. package/src/tools/script-connections/tool.ts +275 -31
  213. package/src/tools/send-task.ts +15 -1
  214. package/src/tools/task-action.ts +34 -2
  215. package/src/tools/templates.ts +53 -1
  216. package/src/tools/tool-config.ts +2 -1
  217. package/src/tools/utils.ts +2 -0
  218. package/src/tools/workflows/create-workflow.ts +8 -1
  219. package/src/tools/workflows/update-workflow.ts +11 -2
  220. package/src/types.ts +90 -11
  221. package/src/utils/scoped-resource.ts +25 -0
  222. package/src/workflows/executors/human-in-the-loop.ts +1 -0
  223. package/src/workflows/executors/swarm-script.ts +7 -1
  224. package/src/workflows/triggers.ts +146 -18
  225. package/templates/skills/swarm-scripts/content.md +33 -8
  226. package/dist/cli-bgef578c.js +0 -771
  227. package/dist/cli-c9mtm09b.js +0 -43
  228. package/dist/cli-ceewqajw.js +0 -1698
  229. package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
  230. package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
  231. package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
  232. package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
  233. package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
  234. package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
  235. package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
  236. package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
  237. package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
@@ -1,771 +0,0 @@
1
- import {
2
- getDb,
3
- init_date_utils,
4
- init_db,
5
- normalizeDateRequired
6
- } from "./cli-ncfgsqbd.js";
7
-
8
- // src/be/db-queries/oauth.ts
9
- init_date_utils();
10
- init_db();
11
- function normalizeOAuthApp(row) {
12
- return {
13
- ...row,
14
- createdAt: normalizeDateRequired(row.createdAt),
15
- updatedAt: normalizeDateRequired(row.updatedAt)
16
- };
17
- }
18
- function normalizeOAuthTokens(row) {
19
- return {
20
- ...row,
21
- createdAt: normalizeDateRequired(row.createdAt),
22
- updatedAt: normalizeDateRequired(row.updatedAt)
23
- };
24
- }
25
- function getOAuthApp(provider) {
26
- const row = getDb().query("SELECT * FROM oauth_apps WHERE provider = ?").get(provider);
27
- return row ? normalizeOAuthApp(row) : null;
28
- }
29
- function upsertOAuthApp(provider, data) {
30
- const metadataProvided = data.metadata !== undefined;
31
- const sql = metadataProvided ? `INSERT INTO oauth_apps (provider, clientId, clientSecret, authorizeUrl, tokenUrl, redirectUri, scopes, metadata)
32
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
33
- ON CONFLICT(provider) DO UPDATE SET
34
- clientId = excluded.clientId,
35
- clientSecret = excluded.clientSecret,
36
- authorizeUrl = excluded.authorizeUrl,
37
- tokenUrl = excluded.tokenUrl,
38
- redirectUri = excluded.redirectUri,
39
- scopes = excluded.scopes,
40
- metadata = excluded.metadata,
41
- updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')` : `INSERT INTO oauth_apps (provider, clientId, clientSecret, authorizeUrl, tokenUrl, redirectUri, scopes, metadata)
42
- VALUES (?, ?, ?, ?, ?, ?, ?, '{}')
43
- ON CONFLICT(provider) DO UPDATE SET
44
- clientId = excluded.clientId,
45
- clientSecret = excluded.clientSecret,
46
- authorizeUrl = excluded.authorizeUrl,
47
- tokenUrl = excluded.tokenUrl,
48
- redirectUri = excluded.redirectUri,
49
- scopes = excluded.scopes,
50
- updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
51
- if (metadataProvided) {
52
- getDb().query(sql).run(provider, data.clientId, data.clientSecret, data.authorizeUrl, data.tokenUrl, data.redirectUri, data.scopes, data.metadata);
53
- } else {
54
- getDb().query(sql).run(provider, data.clientId, data.clientSecret, data.authorizeUrl, data.tokenUrl, data.redirectUri, data.scopes);
55
- }
56
- }
57
- function getOAuthTokens(provider) {
58
- const row = getDb().query("SELECT * FROM oauth_tokens WHERE provider = ?").get(provider);
59
- return row ? normalizeOAuthTokens(row) : null;
60
- }
61
- function storeOAuthTokens(provider, data) {
62
- getDb().query(`INSERT INTO oauth_tokens (provider, accessToken, refreshToken, expiresAt, scope)
63
- VALUES (?, ?, ?, ?, ?)
64
- ON CONFLICT(provider) DO UPDATE SET
65
- accessToken = excluded.accessToken,
66
- refreshToken = COALESCE(excluded.refreshToken, oauth_tokens.refreshToken),
67
- expiresAt = excluded.expiresAt,
68
- scope = COALESCE(excluded.scope, oauth_tokens.scope),
69
- updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`).run(provider, data.accessToken, data.refreshToken ?? null, data.expiresAt, data.scope ?? null);
70
- }
71
- function updateOAuthTokensAfterRefresh(provider, expectedRefreshToken, data) {
72
- const result = getDb().query(`UPDATE oauth_tokens
73
- SET accessToken = ?,
74
- refreshToken = ?,
75
- expiresAt = ?,
76
- scope = COALESCE(?, scope),
77
- updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
78
- WHERE provider = ? AND refreshToken = ?`).run(data.accessToken, data.refreshToken, data.expiresAt, data.scope ?? null, provider, expectedRefreshToken);
79
- if (result.changes === 1)
80
- return;
81
- const current = getOAuthTokens(provider);
82
- if (!current) {
83
- throw new Error(`OAuth token refresh persistence failed for ${provider}: token row missing`);
84
- }
85
- if (current.refreshToken !== expectedRefreshToken) {
86
- throw new Error(`OAuth token refresh persistence failed for ${provider}: stored refresh token changed during refresh`);
87
- }
88
- throw new Error(`OAuth token refresh persistence failed for ${provider}: no rows updated`);
89
- }
90
- function deleteOAuthTokens(provider) {
91
- getDb().query("DELETE FROM oauth_tokens WHERE provider = ?").run(provider);
92
- }
93
- function isTokenExpiringSoon(provider, bufferMs = 5 * 60 * 1000) {
94
- const tokens = getOAuthTokens(provider);
95
- if (!tokens)
96
- return true;
97
- const expiresAt = new Date(tokens.expiresAt).getTime();
98
- return expiresAt - Date.now() < bufferMs;
99
- }
100
- function acquireOAuthRefreshLock(provider, ttlMs) {
101
- const owner = crypto.randomUUID();
102
- const now = Date.now();
103
- const expiresAt = new Date(now + ttlMs).toISOString();
104
- const nowIso = new Date(now).toISOString();
105
- getDb().query(`INSERT INTO oauth_refresh_locks (provider, owner, expiresAt, createdAt, updatedAt)
106
- VALUES (?, ?, ?, ?, ?)
107
- ON CONFLICT(provider) DO UPDATE SET
108
- owner = excluded.owner,
109
- expiresAt = excluded.expiresAt,
110
- updatedAt = excluded.updatedAt
111
- WHERE oauth_refresh_locks.expiresAt <= ?`).run(provider, owner, expiresAt, nowIso, nowIso, nowIso);
112
- const row = getDb().query("SELECT owner FROM oauth_refresh_locks WHERE provider = ?").get(provider);
113
- return row?.owner === owner ? owner : null;
114
- }
115
- function releaseOAuthRefreshLock(provider, owner) {
116
- getDb().query("DELETE FROM oauth_refresh_locks WHERE provider = ? AND owner = ?").run(provider, owner);
117
- }
118
-
119
- // node_modules/oauth4webapi/build/index.js
120
- var USER_AGENT;
121
- if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) {
122
- const NAME = "oauth4webapi";
123
- const VERSION = "v3.8.5";
124
- USER_AGENT = `${NAME}/${VERSION}`;
125
- }
126
- var ERR_INVALID_ARG_VALUE = "ERR_INVALID_ARG_VALUE";
127
- var ERR_INVALID_ARG_TYPE = "ERR_INVALID_ARG_TYPE";
128
- function CodedTypeError(message, code, cause) {
129
- const err = new TypeError(message, { cause });
130
- Object.assign(err, { code });
131
- return err;
132
- }
133
- var allowInsecureRequests = Symbol();
134
- var clockSkew = Symbol();
135
- var clockTolerance = Symbol();
136
- var customFetch = Symbol();
137
- var modifyAssertion = Symbol();
138
- var jweDecrypt = Symbol();
139
- var jwksCache = Symbol();
140
- var encoder = new TextEncoder;
141
- var decoder = new TextDecoder;
142
- function buf(input) {
143
- if (typeof input === "string") {
144
- return encoder.encode(input);
145
- }
146
- return decoder.decode(input);
147
- }
148
- var encodeBase64Url;
149
- if (Uint8Array.prototype.toBase64) {
150
- encodeBase64Url = (input) => {
151
- if (input instanceof ArrayBuffer) {
152
- input = new Uint8Array(input);
153
- }
154
- return input.toBase64({ alphabet: "base64url", omitPadding: true });
155
- };
156
- } else {
157
- const CHUNK_SIZE = 32768;
158
- encodeBase64Url = (input) => {
159
- if (input instanceof ArrayBuffer) {
160
- input = new Uint8Array(input);
161
- }
162
- const arr = [];
163
- for (let i = 0;i < input.byteLength; i += CHUNK_SIZE) {
164
- arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
165
- }
166
- return btoa(arr.join("")).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
167
- };
168
- }
169
- var decodeBase64Url;
170
- if (Uint8Array.fromBase64) {
171
- decodeBase64Url = (input) => {
172
- try {
173
- return Uint8Array.fromBase64(input, { alphabet: "base64url" });
174
- } catch (cause) {
175
- throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
176
- }
177
- };
178
- } else {
179
- decodeBase64Url = (input) => {
180
- try {
181
- const binary = atob(input.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""));
182
- const bytes = new Uint8Array(binary.length);
183
- for (let i = 0;i < binary.length; i++) {
184
- bytes[i] = binary.charCodeAt(i);
185
- }
186
- return bytes;
187
- } catch (cause) {
188
- throw CodedTypeError("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE, cause);
189
- }
190
- };
191
- }
192
- function b64u(input) {
193
- if (typeof input === "string") {
194
- return decodeBase64Url(input);
195
- }
196
- return encodeBase64Url(input);
197
- }
198
-
199
- class UnsupportedOperationError extends Error {
200
- code;
201
- constructor(message, options) {
202
- super(message, options);
203
- this.name = this.constructor.name;
204
- this.code = UNSUPPORTED_OPERATION;
205
- Error.captureStackTrace?.(this, this.constructor);
206
- }
207
- }
208
-
209
- class OperationProcessingError extends Error {
210
- code;
211
- constructor(message, options) {
212
- super(message, options);
213
- this.name = this.constructor.name;
214
- if (options?.code) {
215
- this.code = options?.code;
216
- }
217
- Error.captureStackTrace?.(this, this.constructor);
218
- }
219
- }
220
- function OPE(message, code, cause) {
221
- return new OperationProcessingError(message, { code, cause });
222
- }
223
- async function calculateJwkThumbprint(jwk) {
224
- let components;
225
- switch (jwk.kty) {
226
- case "EC":
227
- components = {
228
- crv: jwk.crv,
229
- kty: jwk.kty,
230
- x: jwk.x,
231
- y: jwk.y
232
- };
233
- break;
234
- case "OKP":
235
- components = {
236
- crv: jwk.crv,
237
- kty: jwk.kty,
238
- x: jwk.x
239
- };
240
- break;
241
- case "AKP":
242
- components = {
243
- alg: jwk.alg,
244
- kty: jwk.kty,
245
- pub: jwk.pub
246
- };
247
- break;
248
- case "RSA":
249
- components = {
250
- e: jwk.e,
251
- kty: jwk.kty,
252
- n: jwk.n
253
- };
254
- break;
255
- default:
256
- throw new UnsupportedOperationError("unsupported JWK key type", { cause: jwk });
257
- }
258
- return b64u(await crypto.subtle.digest("SHA-256", buf(JSON.stringify(components))));
259
- }
260
- function assertCryptoKey(key, it) {
261
- if (!(key instanceof CryptoKey)) {
262
- throw CodedTypeError(`${it} must be a CryptoKey`, ERR_INVALID_ARG_TYPE);
263
- }
264
- }
265
- function assertPrivateKey(key, it) {
266
- assertCryptoKey(key, it);
267
- if (key.type !== "private") {
268
- throw CodedTypeError(`${it} must be a private CryptoKey`, ERR_INVALID_ARG_VALUE);
269
- }
270
- }
271
- function assertPublicKey(key, it) {
272
- assertCryptoKey(key, it);
273
- if (key.type !== "public") {
274
- throw CodedTypeError(`${it} must be a public CryptoKey`, ERR_INVALID_ARG_VALUE);
275
- }
276
- }
277
- function assertString(input, it, code, cause) {
278
- try {
279
- if (typeof input !== "string") {
280
- throw CodedTypeError(`${it} must be a string`, ERR_INVALID_ARG_TYPE, cause);
281
- }
282
- if (input.length === 0) {
283
- throw CodedTypeError(`${it} must not be empty`, ERR_INVALID_ARG_VALUE, cause);
284
- }
285
- } catch (err) {
286
- if (code) {
287
- throw OPE(err.message, code, cause);
288
- }
289
- throw err;
290
- }
291
- }
292
- function randomBytes() {
293
- return b64u(crypto.getRandomValues(new Uint8Array(32)));
294
- }
295
- function generateRandomCodeVerifier() {
296
- return randomBytes();
297
- }
298
- function generateRandomState() {
299
- return randomBytes();
300
- }
301
- async function calculatePKCECodeChallenge(codeVerifier) {
302
- assertString(codeVerifier, "codeVerifier");
303
- return b64u(await crypto.subtle.digest("SHA-256", buf(codeVerifier)));
304
- }
305
- function psAlg(key) {
306
- switch (key.algorithm.hash.name) {
307
- case "SHA-256":
308
- return "PS256";
309
- case "SHA-384":
310
- return "PS384";
311
- case "SHA-512":
312
- return "PS512";
313
- default:
314
- throw new UnsupportedOperationError("unsupported RsaHashedKeyAlgorithm hash name", {
315
- cause: key
316
- });
317
- }
318
- }
319
- function rsAlg(key) {
320
- switch (key.algorithm.hash.name) {
321
- case "SHA-256":
322
- return "RS256";
323
- case "SHA-384":
324
- return "RS384";
325
- case "SHA-512":
326
- return "RS512";
327
- default:
328
- throw new UnsupportedOperationError("unsupported RsaHashedKeyAlgorithm hash name", {
329
- cause: key
330
- });
331
- }
332
- }
333
- function esAlg(key) {
334
- switch (key.algorithm.namedCurve) {
335
- case "P-256":
336
- return "ES256";
337
- case "P-384":
338
- return "ES384";
339
- case "P-521":
340
- return "ES512";
341
- default:
342
- throw new UnsupportedOperationError("unsupported EcKeyAlgorithm namedCurve", { cause: key });
343
- }
344
- }
345
- function keyToJws(key) {
346
- switch (key.algorithm.name) {
347
- case "RSA-PSS":
348
- return psAlg(key);
349
- case "RSASSA-PKCS1-v1_5":
350
- return rsAlg(key);
351
- case "ECDSA":
352
- return esAlg(key);
353
- case "Ed25519":
354
- case "ML-DSA-44":
355
- case "ML-DSA-65":
356
- case "ML-DSA-87":
357
- return key.algorithm.name;
358
- case "EdDSA":
359
- return "Ed25519";
360
- default:
361
- throw new UnsupportedOperationError("unsupported CryptoKey algorithm name", { cause: key });
362
- }
363
- }
364
- function getClockSkew(client) {
365
- const skew = client?.[clockSkew];
366
- return typeof skew === "number" && Number.isFinite(skew) ? skew : 0;
367
- }
368
- function epochTime() {
369
- return Math.floor(Date.now() / 1000);
370
- }
371
- async function signJwt(header, payload, key) {
372
- if (!key.usages.includes("sign")) {
373
- throw CodedTypeError('CryptoKey instances used for signing assertions must include "sign" in their "usages"', ERR_INVALID_ARG_VALUE);
374
- }
375
- const input = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(payload)))}`;
376
- const signature = b64u(await crypto.subtle.sign(keyToSubtle(key), key, buf(input)));
377
- return `${input}.${signature}`;
378
- }
379
- var jwkCache;
380
- async function getSetPublicJwkCache(key, alg) {
381
- const { kty, e, n, x, y, crv, pub } = await crypto.subtle.exportKey("jwk", key);
382
- const jwk = { kty, e, n, x, y, crv, pub };
383
- if (kty === "AKP")
384
- jwk.alg = alg;
385
- jwkCache.set(key, jwk);
386
- return jwk;
387
- }
388
- async function publicJwk(key, alg) {
389
- jwkCache ||= new WeakMap;
390
- return jwkCache.get(key) || getSetPublicJwkCache(key, alg);
391
- }
392
- var URLParse = URL.parse ? (url, base) => URL.parse(url, base) : (url, base) => {
393
- try {
394
- return new URL(url, base);
395
- } catch {
396
- return null;
397
- }
398
- };
399
- class DPoPHandler {
400
- #header;
401
- #privateKey;
402
- #publicKey;
403
- #clockSkew;
404
- #modifyAssertion;
405
- #map;
406
- #jkt;
407
- constructor(client, keyPair, options) {
408
- assertPrivateKey(keyPair?.privateKey, '"DPoP.privateKey"');
409
- assertPublicKey(keyPair?.publicKey, '"DPoP.publicKey"');
410
- if (!keyPair.publicKey.extractable) {
411
- throw CodedTypeError('"DPoP.publicKey.extractable" must be true', ERR_INVALID_ARG_VALUE);
412
- }
413
- this.#modifyAssertion = options?.[modifyAssertion];
414
- this.#clockSkew = getClockSkew(client);
415
- this.#privateKey = keyPair.privateKey;
416
- this.#publicKey = keyPair.publicKey;
417
- branded.add(this);
418
- }
419
- #get(key) {
420
- this.#map ||= new Map;
421
- let item = this.#map.get(key);
422
- if (item) {
423
- this.#map.delete(key);
424
- this.#map.set(key, item);
425
- }
426
- return item;
427
- }
428
- #set(key, val) {
429
- this.#map ||= new Map;
430
- this.#map.delete(key);
431
- if (this.#map.size === 100) {
432
- this.#map.delete(this.#map.keys().next().value);
433
- }
434
- this.#map.set(key, val);
435
- }
436
- async calculateThumbprint() {
437
- if (!this.#jkt) {
438
- const jwk = await crypto.subtle.exportKey("jwk", this.#publicKey);
439
- this.#jkt ||= await calculateJwkThumbprint(jwk);
440
- }
441
- return this.#jkt;
442
- }
443
- async addProof(url, headers, htm, accessToken) {
444
- const alg = keyToJws(this.#privateKey);
445
- this.#header ||= {
446
- alg,
447
- typ: "dpop+jwt",
448
- jwk: await publicJwk(this.#publicKey, alg)
449
- };
450
- const nonce = this.#get(url.origin);
451
- const now = epochTime() + this.#clockSkew;
452
- const payload = {
453
- iat: now,
454
- jti: randomBytes(),
455
- htm,
456
- nonce,
457
- htu: `${url.origin}${url.pathname}`,
458
- ath: accessToken ? b64u(await crypto.subtle.digest("SHA-256", buf(accessToken))) : undefined
459
- };
460
- this.#modifyAssertion?.(this.#header, payload);
461
- headers.set("dpop", await signJwt(this.#header, payload, this.#privateKey));
462
- }
463
- cacheNonce(response, url) {
464
- try {
465
- const nonce = response.headers.get("dpop-nonce");
466
- if (nonce) {
467
- this.#set(url.origin, nonce);
468
- }
469
- } catch {}
470
- }
471
- }
472
- var tokenMatch = "[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+";
473
- var token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}";
474
- var quotedMatch = '"((?:[^"\\\\]|\\\\[\\s\\S])*)"';
475
- var quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*" + quotedMatch;
476
- var paramMatcher = "(" + tokenMatch + ")\\s*=\\s*(" + tokenMatch + ")";
477
- var schemeRE = new RegExp("^[,\\s]*(" + tokenMatch + ")");
478
- var quotedParamRE = new RegExp("^[,\\s]*" + quotedParamMatcher + "[,\\s]*(.*)");
479
- var unquotedParamRE = new RegExp("^[,\\s]*" + paramMatcher + "[,\\s]*(.*)");
480
- var token68ParamRE = new RegExp("^(" + token68Match + ")(?:$|[,\\s])(.*)");
481
- var skipSubjectCheck = Symbol();
482
- var idTokenClaims = new WeakMap;
483
- var jwtRefs = new WeakMap;
484
- var branded = new WeakSet;
485
- var nopkce = Symbol();
486
- var expectNoNonce = Symbol();
487
- var skipAuthTimeCheck = Symbol();
488
- var UNSUPPORTED_OPERATION = "OAUTH_UNSUPPORTED_OPERATION";
489
- function checkRsaKeyAlgorithm(key) {
490
- const { algorithm } = key;
491
- if (typeof algorithm.modulusLength !== "number" || algorithm.modulusLength < 2048) {
492
- throw new UnsupportedOperationError(`unsupported ${algorithm.name} modulusLength`, {
493
- cause: key
494
- });
495
- }
496
- }
497
- function ecdsaHashName(key) {
498
- const { algorithm } = key;
499
- switch (algorithm.namedCurve) {
500
- case "P-256":
501
- return "SHA-256";
502
- case "P-384":
503
- return "SHA-384";
504
- case "P-521":
505
- return "SHA-512";
506
- default:
507
- throw new UnsupportedOperationError("unsupported ECDSA namedCurve", { cause: key });
508
- }
509
- }
510
- function keyToSubtle(key) {
511
- switch (key.algorithm.name) {
512
- case "ECDSA":
513
- return {
514
- name: key.algorithm.name,
515
- hash: ecdsaHashName(key)
516
- };
517
- case "RSA-PSS": {
518
- checkRsaKeyAlgorithm(key);
519
- switch (key.algorithm.hash.name) {
520
- case "SHA-256":
521
- case "SHA-384":
522
- case "SHA-512":
523
- return {
524
- name: key.algorithm.name,
525
- saltLength: parseInt(key.algorithm.hash.name.slice(-3), 10) >> 3
526
- };
527
- default:
528
- throw new UnsupportedOperationError("unsupported RSA-PSS hash name", { cause: key });
529
- }
530
- }
531
- case "RSASSA-PKCS1-v1_5":
532
- checkRsaKeyAlgorithm(key);
533
- return key.algorithm.name;
534
- case "ML-DSA-44":
535
- case "ML-DSA-65":
536
- case "ML-DSA-87":
537
- case "Ed25519":
538
- return key.algorithm.name;
539
- }
540
- throw new UnsupportedOperationError("unsupported CryptoKey algorithm name", { cause: key });
541
- }
542
- var skipStateCheck = Symbol();
543
- var expectNoState = Symbol();
544
- var _nodiscoverycheck = Symbol();
545
- var _expectedIssuer = Symbol();
546
-
547
- // src/oauth/wrapper.ts
548
- var STATE_TTL_MS = 10 * 60 * 1000;
549
- var pendingStates = new Map;
550
- function cleanupExpiredStates() {
551
- const now = Date.now();
552
- for (const [key, entry] of pendingStates) {
553
- if (now - entry.createdAt > STATE_TTL_MS) {
554
- pendingStates.delete(key);
555
- }
556
- }
557
- }
558
- async function buildAuthorizationUrl(config) {
559
- cleanupExpiredStates();
560
- const state = generateRandomState();
561
- const codeVerifier = generateRandomCodeVerifier();
562
- const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
563
- pendingStates.set(state, {
564
- codeVerifier,
565
- config,
566
- createdAt: Date.now()
567
- });
568
- const url = new URL(config.authorizeUrl);
569
- url.searchParams.set("client_id", config.clientId);
570
- url.searchParams.set("redirect_uri", config.redirectUri);
571
- url.searchParams.set("response_type", "code");
572
- url.searchParams.set("scope", config.scopes.join(config.scopeSeparator ?? ","));
573
- url.searchParams.set("state", state);
574
- url.searchParams.set("code_challenge", codeChallenge);
575
- url.searchParams.set("code_challenge_method", "S256");
576
- if (config.extraParams) {
577
- for (const [key, value] of Object.entries(config.extraParams)) {
578
- url.searchParams.set(key, value);
579
- }
580
- }
581
- return { url: url.toString(), state, codeVerifier };
582
- }
583
- async function exchangeCode(config, code, state) {
584
- const pending = pendingStates.get(state);
585
- if (!pending) {
586
- throw new Error("Invalid or expired OAuth state");
587
- }
588
- pendingStates.delete(state);
589
- const { codeVerifier } = pending;
590
- const body = new URLSearchParams({
591
- grant_type: "authorization_code",
592
- client_id: config.clientId,
593
- client_secret: config.clientSecret,
594
- redirect_uri: config.redirectUri,
595
- code,
596
- code_verifier: codeVerifier
597
- });
598
- const response = await fetch(config.tokenUrl, {
599
- method: "POST",
600
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
601
- body: body.toString()
602
- });
603
- if (!response.ok) {
604
- const errorText = await response.text();
605
- throw new Error(`Token exchange failed (${response.status}): ${errorText}`);
606
- }
607
- const data = await response.json();
608
- const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
609
- storeOAuthTokens(config.provider, {
610
- accessToken: data.access_token,
611
- refreshToken: data.refresh_token ?? null,
612
- expiresAt,
613
- scope: data.scope ?? null
614
- });
615
- return {
616
- accessToken: data.access_token,
617
- refreshToken: data.refresh_token,
618
- expiresIn: data.expires_in,
619
- scope: data.scope
620
- };
621
- }
622
- async function refreshAccessToken(config, refreshToken) {
623
- const body = new URLSearchParams({
624
- grant_type: "refresh_token",
625
- client_id: config.clientId,
626
- client_secret: config.clientSecret,
627
- refresh_token: refreshToken
628
- });
629
- const response = await fetch(config.tokenUrl, {
630
- method: "POST",
631
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
632
- body: body.toString()
633
- });
634
- if (!response.ok) {
635
- const errorText = await response.text();
636
- throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
637
- }
638
- const data = await response.json();
639
- if (typeof data.access_token !== "string" || data.access_token.length === 0) {
640
- throw new Error(`Token refresh failed: ${config.provider} response missing access_token`);
641
- }
642
- if (config.requiresRefreshTokenRotation && (typeof data.refresh_token !== "string" || data.refresh_token.length === 0)) {
643
- throw new Error(`Token refresh failed: ${config.provider} response did not include a rotated refresh_token`);
644
- }
645
- const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
646
- const nextRefreshToken = data.refresh_token ?? refreshToken;
647
- try {
648
- updateOAuthTokensAfterRefresh(config.provider, refreshToken, {
649
- accessToken: data.access_token,
650
- refreshToken: nextRefreshToken,
651
- expiresAt,
652
- scope: data.scope ?? null
653
- });
654
- } catch (err) {
655
- const message = err instanceof Error ? err.message : String(err);
656
- console.warn(`[OAuth] Refusing to use refreshed ${config.provider} access token because persistence failed: ${message}`);
657
- throw err;
658
- }
659
- return {
660
- accessToken: data.access_token,
661
- refreshToken: data.refresh_token,
662
- expiresIn: data.expires_in,
663
- scope: data.scope
664
- };
665
- }
666
-
667
- // src/oauth/ensure-token.ts
668
- var refreshLocks = new Map;
669
- var REFRESH_LOCK_TTL_MS = 2 * 60 * 1000;
670
- var REFRESH_LOCK_WAIT_MS = 30 * 1000;
671
- var REFRESH_LOCK_POLL_MS = 250;
672
- function getOAuthConfig(provider) {
673
- const app = getOAuthApp(provider);
674
- if (!app)
675
- return null;
676
- const metadata = JSON.parse(app.metadata || "{}");
677
- return {
678
- provider,
679
- clientId: app.clientId,
680
- clientSecret: app.clientSecret,
681
- authorizeUrl: app.authorizeUrl,
682
- tokenUrl: app.tokenUrl,
683
- redirectUri: app.redirectUri,
684
- scopes: app.scopes.split(","),
685
- extraParams: metadata.extraParams ?? (metadata.actor ? { actor: metadata.actor } : undefined),
686
- requiresRefreshTokenRotation: provider === "jira"
687
- };
688
- }
689
- async function withProviderRefreshLock(provider, fn) {
690
- const previous = refreshLocks.get(provider) ?? Promise.resolve();
691
- let release;
692
- const current = new Promise((resolve) => {
693
- release = resolve;
694
- });
695
- const next = previous.catch(() => {
696
- return;
697
- }).then(() => current);
698
- refreshLocks.set(provider, next);
699
- await previous.catch(() => {
700
- return;
701
- });
702
- try {
703
- return await fn();
704
- } finally {
705
- release();
706
- if (refreshLocks.get(provider) === next) {
707
- refreshLocks.delete(provider);
708
- }
709
- }
710
- }
711
- function sleep(ms) {
712
- return new Promise((resolve) => setTimeout(resolve, ms));
713
- }
714
- function tokenRowChanged(current, observed) {
715
- if (!observed)
716
- return current !== null;
717
- if (!current)
718
- return true;
719
- return current.accessToken !== observed.accessToken || current.refreshToken !== observed.refreshToken || current.expiresAt !== observed.expiresAt;
720
- }
721
- async function ensureToken(provider, bufferMs) {
722
- try {
723
- await ensureTokenOrThrow(provider, bufferMs);
724
- } catch (err) {
725
- console.error(`[OAuth] Failed to refresh ${provider} token:`, err instanceof Error ? err.message : err);
726
- }
727
- }
728
- async function ensureTokenOrThrow(provider, bufferMs) {
729
- if (!isTokenExpiringSoon(provider, bufferMs))
730
- return;
731
- const observedTokens = getOAuthTokens(provider);
732
- await withProviderRefreshLock(provider, async () => {
733
- const waitStartedAt = Date.now();
734
- while (isTokenExpiringSoon(provider, bufferMs)) {
735
- const tokens = getOAuthTokens(provider);
736
- if (tokenRowChanged(tokens, observedTokens))
737
- return;
738
- const config = getOAuthConfig(provider);
739
- if (!config || !tokens?.refreshToken) {
740
- console.warn(`[OAuth] ${provider} token expiring but cannot refresh (missing config or refresh token)`);
741
- return;
742
- }
743
- const lockOwner = acquireOAuthRefreshLock(provider, REFRESH_LOCK_TTL_MS);
744
- if (!lockOwner) {
745
- if (Date.now() - waitStartedAt > REFRESH_LOCK_WAIT_MS) {
746
- throw new Error(`Timed out waiting for ${provider} OAuth token refresh lock`);
747
- }
748
- await sleep(REFRESH_LOCK_POLL_MS);
749
- continue;
750
- }
751
- try {
752
- const lockedTokens = getOAuthTokens(provider);
753
- if (!isTokenExpiringSoon(provider, bufferMs) || tokenRowChanged(lockedTokens, observedTokens)) {
754
- return;
755
- }
756
- const lockedConfig = getOAuthConfig(provider);
757
- if (!lockedConfig || !lockedTokens?.refreshToken) {
758
- console.warn(`[OAuth] ${provider} token expiring but cannot refresh (missing config or refresh token)`);
759
- return;
760
- }
761
- await refreshAccessToken(lockedConfig, lockedTokens.refreshToken);
762
- console.log(`[OAuth] ${provider} token refreshed successfully`);
763
- return;
764
- } finally {
765
- releaseOAuthRefreshLock(provider, lockOwner);
766
- }
767
- }
768
- });
769
- }
770
-
771
- export { getOAuthApp, upsertOAuthApp, getOAuthTokens, deleteOAuthTokens, acquireOAuthRefreshLock, releaseOAuthRefreshLock, generateRandomCodeVerifier, generateRandomState, calculatePKCECodeChallenge, buildAuthorizationUrl, exchangeCode, ensureToken, ensureTokenOrThrow };