@astrale-os/cli 1.0.0-beta.9 → 1.0.0-npm-deprecated.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 (617) hide show
  1. package/README.md +14 -166
  2. package/package.json +10 -102
  3. package/.check-workspace.cjs +0 -40
  4. package/LICENSE +0 -202
  5. package/THIRD-PARTY-NOTICES.md +0 -27
  6. package/dist/astrale.js +0 -93344
  7. package/dist/public/connect-core.js +0 -29187
  8. package/dist/public/keys/index.js +0 -5651
  9. package/dist/public/paths/index.js +0 -4282
  10. package/dist/types/admin/binding.d.ts +0 -19
  11. package/dist/types/admin/instance/client.d.ts +0 -22
  12. package/dist/types/admin/instance/index.d.ts +0 -2
  13. package/dist/types/admin/instance/model.d.ts +0 -33
  14. package/dist/types/connect-core.d.ts +0 -22
  15. package/dist/types/connection/auth.d.ts +0 -39
  16. package/dist/types/connection/call.d.ts +0 -3
  17. package/dist/types/connection/command.d.ts +0 -27
  18. package/dist/types/connection/credential.d.ts +0 -14
  19. package/dist/types/connection/errors.d.ts +0 -1
  20. package/dist/types/connection/exchange.d.ts +0 -9
  21. package/dist/types/connection/failure/classify.d.ts +0 -2
  22. package/dist/types/connection/failure/index.d.ts +0 -5
  23. package/dist/types/connection/failure/model.d.ts +0 -25
  24. package/dist/types/connection/failure/render.d.ts +0 -3
  25. package/dist/types/connection/index.d.ts +0 -8
  26. package/dist/types/connection/reasons.d.ts +0 -37
  27. package/dist/types/connection/self.d.ts +0 -37
  28. package/dist/types/connection/session.d.ts +0 -31
  29. package/dist/types/connection/target.d.ts +0 -38
  30. package/dist/types/errors.d.ts +0 -23
  31. package/dist/types/identity/registry.d.ts +0 -25
  32. package/dist/types/keys/algorithm.d.ts +0 -6
  33. package/dist/types/keys/credential.d.ts +0 -21
  34. package/dist/types/keys/index.d.ts +0 -4
  35. package/dist/types/keys/pair.d.ts +0 -34
  36. package/dist/types/lib/admin-instance.d.ts +0 -17
  37. package/dist/types/lib/admin-target.d.ts +0 -78
  38. package/dist/types/lib/ca-fetch.d.ts +0 -2
  39. package/dist/types/lib/config.d.ts +0 -71
  40. package/dist/types/lib/failure-debug.d.ts +0 -1
  41. package/dist/types/lib/format.d.ts +0 -1
  42. package/dist/types/lib/idp-session.d.ts +0 -33
  43. package/dist/types/lib/idp.d.ts +0 -404
  44. package/dist/types/lib/instance-target.d.ts +0 -38
  45. package/dist/types/lib/instance.d.ts +0 -202
  46. package/dist/types/lib/invocation.d.ts +0 -3
  47. package/dist/types/lib/log.d.ts +0 -33
  48. package/dist/types/lib/login-flow.d.ts +0 -49
  49. package/dist/types/lib/meta.d.ts +0 -36
  50. package/dist/types/lib/output.d.ts +0 -87
  51. package/dist/types/lib/proc.d.ts +0 -43
  52. package/dist/types/lib/self.d.ts +0 -9
  53. package/dist/types/lib/table.d.ts +0 -18
  54. package/dist/types/lib/update.d.ts +0 -131
  55. package/dist/types/lib/validation.d.ts +0 -11
  56. package/dist/types/paths/index.d.ts +0 -2
  57. package/dist/types/state/exchange-credentials.d.ts +0 -25
  58. package/dist/types/state/files.d.ts +0 -9
  59. package/dist/types/state/identities.d.ts +0 -42
  60. package/dist/types/state/index.d.ts +0 -8
  61. package/dist/types/state/paths.d.ts +0 -32
  62. package/src/__tests__/fixtures/publication.ts +0 -20
  63. package/src/admin/.spec/api.d.ts +0 -3
  64. package/src/admin/.spec/architecture.md +0 -15
  65. package/src/admin/.spec/icon.svg +0 -3
  66. package/src/admin/.spec/layout.ts +0 -6
  67. package/src/admin/__tests__/binding.test.ts +0 -31
  68. package/src/admin/__tests__/fixture.ts +0 -101
  69. package/src/admin/binding.ts +0 -98
  70. package/src/admin/catalog/.spec/api.d.ts +0 -65
  71. package/src/admin/catalog/.spec/architecture.md +0 -6
  72. package/src/admin/catalog/.spec/icon.svg +0 -3
  73. package/src/admin/catalog/.spec/layout.ts +0 -6
  74. package/src/admin/catalog/__tests__/client.test.ts +0 -142
  75. package/src/admin/catalog/client.ts +0 -218
  76. package/src/admin/catalog/index.ts +0 -13
  77. package/src/admin/catalog/model.ts +0 -41
  78. package/src/admin/catalog/tsconfig.json +0 -8
  79. package/src/admin/graph/.spec/api.d.ts +0 -22
  80. package/src/admin/graph/.spec/architecture.md +0 -5
  81. package/src/admin/graph/.spec/icon.svg +0 -3
  82. package/src/admin/graph/.spec/layout.ts +0 -3
  83. package/src/admin/graph/index.ts +0 -6
  84. package/src/admin/graph/nodes.ts +0 -56
  85. package/src/admin/index.ts +0 -2
  86. package/src/admin/instance/.spec/api.d.ts +0 -66
  87. package/src/admin/instance/.spec/architecture.md +0 -10
  88. package/src/admin/instance/.spec/icon.svg +0 -3
  89. package/src/admin/instance/.spec/layout.ts +0 -6
  90. package/src/admin/instance/__tests__/client.test.ts +0 -166
  91. package/src/admin/instance/client.ts +0 -196
  92. package/src/admin/instance/index.ts +0 -15
  93. package/src/admin/instance/model.ts +0 -56
  94. package/src/admin/instance/tsconfig.json +0 -8
  95. package/src/commands/__tests__/admin-instance.test.ts +0 -91
  96. package/src/commands/__tests__/auth-login.test.ts +0 -231
  97. package/src/commands/__tests__/auth-token.test.ts +0 -223
  98. package/src/commands/__tests__/call-describe.test.ts +0 -80
  99. package/src/commands/__tests__/call.test.ts +0 -29
  100. package/src/commands/__tests__/domain-install-operation.test.ts +0 -126
  101. package/src/commands/__tests__/domain-install-owned.test.ts +0 -191
  102. package/src/commands/__tests__/domain-list.test.ts +0 -133
  103. package/src/commands/__tests__/domain-uninstall.test.ts +0 -53
  104. package/src/commands/__tests__/install-direct.test.ts +0 -21
  105. package/src/commands/__tests__/install-identity-override.test.ts +0 -76
  106. package/src/commands/__tests__/instance-bookmark.test.ts +0 -166
  107. package/src/commands/__tests__/instance-list-admin.test.ts +0 -26
  108. package/src/commands/__tests__/instance-list-rows.test.ts +0 -64
  109. package/src/commands/__tests__/instance-use.test.ts +0 -67
  110. package/src/commands/__tests__/introspect-parse.test.ts +0 -21
  111. package/src/commands/__tests__/logs.test.ts +0 -97
  112. package/src/commands/__tests__/read-commands.test.ts +0 -294
  113. package/src/commands/__tests__/setup-plan.test.ts +0 -61
  114. package/src/commands/__tests__/studio-descriptor.test.ts +0 -22
  115. package/src/commands/__tests__/token-ttl.test.ts +0 -21
  116. package/src/commands/__tests__/update.test.ts +0 -95
  117. package/src/commands/__tests__/view-build.test.ts +0 -58
  118. package/src/commands/__tests__/view.test.ts +0 -149
  119. package/src/commands/admin/status.ts +0 -61
  120. package/src/commands/admin/use.ts +0 -100
  121. package/src/commands/auth/login.ts +0 -82
  122. package/src/commands/auth/logout.ts +0 -52
  123. package/src/commands/auth/status.ts +0 -86
  124. package/src/commands/auth/token.ts +0 -174
  125. package/src/commands/browser.ts +0 -207
  126. package/src/commands/call-describe.ts +0 -123
  127. package/src/commands/call.ts +0 -205
  128. package/src/commands/domain/install.ts +0 -548
  129. package/src/commands/domain/list.ts +0 -155
  130. package/src/commands/domain/publish.ts +0 -136
  131. package/src/commands/domain/uninstall.ts +0 -128
  132. package/src/commands/get.ts +0 -69
  133. package/src/commands/identity/__tests__/register.test.ts +0 -93
  134. package/src/commands/identity/create.ts +0 -35
  135. package/src/commands/identity/delete.ts +0 -24
  136. package/src/commands/identity/export.ts +0 -46
  137. package/src/commands/identity/import.ts +0 -61
  138. package/src/commands/identity/list.ts +0 -56
  139. package/src/commands/identity/register.ts +0 -196
  140. package/src/commands/identity/sync.ts +0 -38
  141. package/src/commands/identity/unsync.ts +0 -34
  142. package/src/commands/identity/use.ts +0 -24
  143. package/src/commands/identity/whoami.ts +0 -34
  144. package/src/commands/idp/add.ts +0 -150
  145. package/src/commands/idp/list.ts +0 -57
  146. package/src/commands/idp/refresh.ts +0 -38
  147. package/src/commands/idp/remove.ts +0 -36
  148. package/src/commands/idp/show.ts +0 -29
  149. package/src/commands/instance/active.ts +0 -73
  150. package/src/commands/instance/bookmark.ts +0 -101
  151. package/src/commands/instance/create.ts +0 -61
  152. package/src/commands/instance/delete.ts +0 -69
  153. package/src/commands/instance/forget.ts +0 -26
  154. package/src/commands/instance/list.ts +0 -197
  155. package/src/commands/instance/status.ts +0 -38
  156. package/src/commands/instance/use.ts +0 -263
  157. package/src/commands/introspect.ts +0 -110
  158. package/src/commands/logs.ts +0 -283
  159. package/src/commands/mutate.ts +0 -122
  160. package/src/commands/query.ts +0 -136
  161. package/src/commands/session/analyze.ts +0 -50
  162. package/src/commands/session/list.ts +0 -36
  163. package/src/commands/setup.ts +0 -54
  164. package/src/commands/status.ts +0 -60
  165. package/src/commands/studio.ts +0 -434
  166. package/src/commands/token.ts +0 -107
  167. package/src/commands/update.ts +0 -334
  168. package/src/commands/use.ts +0 -86
  169. package/src/commands/view-serve.ts +0 -26
  170. package/src/commands/view.ts +0 -614
  171. package/src/connect-core.test.ts +0 -38
  172. package/src/connect-core.ts +0 -42
  173. package/src/connection/.spec/api.d.ts +0 -110
  174. package/src/connection/.spec/architecture.md +0 -47
  175. package/src/connection/.spec/capabilities/connection.ts +0 -13
  176. package/src/connection/.spec/examples/call.ts +0 -7
  177. package/src/connection/.spec/flows/command.ts +0 -20
  178. package/src/connection/.spec/flows/session.ts +0 -61
  179. package/src/connection/.spec/laws/connection.ts +0 -205
  180. package/src/connection/.spec/layout.ts +0 -21
  181. package/src/connection/__tests__/auth.test.ts +0 -128
  182. package/src/connection/__tests__/ca-fetch.test.ts +0 -60
  183. package/src/connection/__tests__/call.test.ts +0 -17
  184. package/src/connection/__tests__/credential.test.ts +0 -138
  185. package/src/connection/__tests__/errors.test.ts +0 -577
  186. package/src/connection/__tests__/exchange.test.ts +0 -295
  187. package/src/connection/__tests__/failure-fixtures.ts +0 -39
  188. package/src/connection/__tests__/failure-safety.test.ts +0 -75
  189. package/src/connection/__tests__/fixtures/localhost-cert.pem +0 -19
  190. package/src/connection/__tests__/fixtures/localhost-key.base64 +0 -1
  191. package/src/connection/__tests__/managed.test.ts +0 -39
  192. package/src/connection/__tests__/reasons.test.ts +0 -78
  193. package/src/connection/__tests__/self.test.ts +0 -71
  194. package/src/connection/__tests__/session.test.ts +0 -140
  195. package/src/connection/__tests__/target.test.ts +0 -94
  196. package/src/connection/auth.ts +0 -249
  197. package/src/connection/call.ts +0 -7
  198. package/src/connection/command.ts +0 -67
  199. package/src/connection/credential.ts +0 -117
  200. package/src/connection/errors.ts +0 -1
  201. package/src/connection/exchange.ts +0 -311
  202. package/src/connection/failure/classify.ts +0 -110
  203. package/src/connection/failure/index.ts +0 -18
  204. package/src/connection/failure/model.ts +0 -28
  205. package/src/connection/failure/render.ts +0 -116
  206. package/src/connection/index.ts +0 -8
  207. package/src/connection/reasons.ts +0 -209
  208. package/src/connection/self.ts +0 -138
  209. package/src/connection/session.ts +0 -196
  210. package/src/connection/target.ts +0 -112
  211. package/src/connection/tsconfig.json +0 -6
  212. package/src/errors.ts +0 -66
  213. package/src/graph/.spec/api.d.ts +0 -41
  214. package/src/graph/.spec/laws/documents.ts +0 -24
  215. package/src/graph/.spec/laws/projection.ts +0 -13
  216. package/src/graph/.spec/layout.ts +0 -14
  217. package/src/graph/__tests__/mutation.test.ts +0 -51
  218. package/src/graph/__tests__/projection.test.ts +0 -22
  219. package/src/graph/__tests__/query.test.ts +0 -173
  220. package/src/graph/class.ts +0 -30
  221. package/src/graph/index.ts +0 -4
  222. package/src/graph/mutation.ts +0 -46
  223. package/src/graph/projection.ts +0 -21
  224. package/src/graph/query.ts +0 -97
  225. package/src/graph/tsconfig.json +0 -6
  226. package/src/identity/.history/ard/bootstrap-root-transfer.md +0 -57
  227. package/src/identity/.history/ard/domain-mediated-registration.md +0 -36
  228. package/src/identity/.spec/api.d.ts +0 -124
  229. package/src/identity/.spec/architecture.md +0 -33
  230. package/src/identity/.spec/capabilities/identity.ts +0 -7
  231. package/src/identity/.spec/flows/bootstrap-root.ts +0 -79
  232. package/src/identity/.spec/flows/domain-mediated-registration.ts +0 -51
  233. package/src/identity/.spec/flows/import.ts +0 -29
  234. package/src/identity/.spec/laws/identity.ts +0 -56
  235. package/src/identity/.spec/layout.ts +0 -13
  236. package/src/identity/.spec/schemas/identity-export-v1.schema.json +0 -25
  237. package/src/identity/__tests__/fixtures/registry-journey.ts +0 -53
  238. package/src/identity/__tests__/registration.test.ts +0 -64
  239. package/src/identity/__tests__/registry.test.ts +0 -70
  240. package/src/identity/__tests__/transfer.test.ts +0 -198
  241. package/src/identity/index.ts +0 -23
  242. package/src/identity/registration.ts +0 -72
  243. package/src/identity/registry.ts +0 -179
  244. package/src/identity/transfer.ts +0 -187
  245. package/src/identity/tsconfig.json +0 -6
  246. package/src/index.ts +0 -1
  247. package/src/keys/.spec/api.d.ts +0 -74
  248. package/src/keys/.spec/architecture.md +0 -13
  249. package/src/keys/.spec/laws/keys.ts +0 -43
  250. package/src/keys/.spec/layout.ts +0 -6
  251. package/src/keys/__tests__/algorithm.test.ts +0 -39
  252. package/src/keys/__tests__/keys.test.ts +0 -168
  253. package/src/keys/algorithm.ts +0 -33
  254. package/src/keys/credential.ts +0 -112
  255. package/src/keys/index.ts +0 -14
  256. package/src/keys/pair.ts +0 -219
  257. package/src/keys/tsconfig.json +0 -6
  258. package/src/lib/__tests__/admin-target.test.ts +0 -184
  259. package/src/lib/__tests__/binary.test.ts +0 -55
  260. package/src/lib/__tests__/command-dx.test.ts +0 -102
  261. package/src/lib/__tests__/concurrency.test.ts +0 -62
  262. package/src/lib/__tests__/config.test.ts +0 -54
  263. package/src/lib/__tests__/design.test.ts +0 -99
  264. package/src/lib/__tests__/domain-publication.test.ts +0 -138
  265. package/src/lib/__tests__/format.test.ts +0 -22
  266. package/src/lib/__tests__/idp-session.driver.ts +0 -53
  267. package/src/lib/__tests__/idp-session.test.ts +0 -379
  268. package/src/lib/__tests__/idp.test.ts +0 -415
  269. package/src/lib/__tests__/instance-candidates.test.ts +0 -146
  270. package/src/lib/__tests__/instance-target.test.ts +0 -213
  271. package/src/lib/__tests__/instance.test.ts +0 -192
  272. package/src/lib/__tests__/local-status.test.ts +0 -202
  273. package/src/lib/__tests__/log-errors.test.ts +0 -64
  274. package/src/lib/__tests__/log.test.ts +0 -31
  275. package/src/lib/__tests__/meta.test.ts +0 -55
  276. package/src/lib/__tests__/output.test.ts +0 -162
  277. package/src/lib/__tests__/panel.test.ts +0 -40
  278. package/src/lib/__tests__/port.test.ts +0 -44
  279. package/src/lib/__tests__/prompt.test.ts +0 -25
  280. package/src/lib/__tests__/sdk-deps.test.ts +0 -68
  281. package/src/lib/__tests__/self.test.ts +0 -50
  282. package/src/lib/__tests__/studio-server-deps.test.ts +0 -111
  283. package/src/lib/__tests__/table.test.ts +0 -53
  284. package/src/lib/__tests__/update.test.ts +0 -351
  285. package/src/lib/__tests__/use-target.test.ts +0 -56
  286. package/src/lib/__tests__/validation.test.ts +0 -34
  287. package/src/lib/__tests__/view-assets.test.ts +0 -146
  288. package/src/lib/__tests__/view-open-intent.test.ts +0 -280
  289. package/src/lib/__tests__/view-port-allocation.test.ts +0 -82
  290. package/src/lib/__tests__/view-server.test.ts +0 -68
  291. package/src/lib/__tests__/view-session.test.ts +0 -99
  292. package/src/lib/__tests__/view-snapshot.test.ts +0 -77
  293. package/src/lib/admin-domain.ts +0 -43
  294. package/src/lib/admin-instance.ts +0 -56
  295. package/src/lib/admin-target.ts +0 -290
  296. package/src/lib/binary.ts +0 -110
  297. package/src/lib/browser.ts +0 -150
  298. package/src/lib/ca-fetch.ts +0 -133
  299. package/src/lib/command-dx.ts +0 -191
  300. package/src/lib/concurrency.ts +0 -31
  301. package/src/lib/config.ts +0 -46
  302. package/src/lib/domain-publication.ts +0 -104
  303. package/src/lib/failure-debug.ts +0 -26
  304. package/src/lib/format.ts +0 -4
  305. package/src/lib/idp-session.ts +0 -134
  306. package/src/lib/idp.ts +0 -906
  307. package/src/lib/instance-candidates.ts +0 -49
  308. package/src/lib/instance-target.ts +0 -197
  309. package/src/lib/instance.ts +0 -467
  310. package/src/lib/invocation.ts +0 -11
  311. package/src/lib/local-status.ts +0 -152
  312. package/src/lib/log.ts +0 -143
  313. package/src/lib/login-flow.ts +0 -201
  314. package/src/lib/meta.ts +0 -90
  315. package/src/lib/output.ts +0 -238
  316. package/src/lib/panel.ts +0 -61
  317. package/src/lib/port.ts +0 -41
  318. package/src/lib/proc.ts +0 -82
  319. package/src/lib/prompt.ts +0 -136
  320. package/src/lib/provision-instance.ts +0 -139
  321. package/src/lib/sdk-deps.ts +0 -104
  322. package/src/lib/self.ts +0 -22
  323. package/src/lib/skills.ts +0 -171
  324. package/src/lib/table.ts +0 -62
  325. package/src/lib/update.ts +0 -409
  326. package/src/lib/use-target.ts +0 -24
  327. package/src/lib/validation.ts +0 -59
  328. package/src/lib/view/assets.ts +0 -78
  329. package/src/lib/view/open-intent.ts +0 -67
  330. package/src/lib/view/port-allocation.ts +0 -19
  331. package/src/lib/view/resolve.ts +0 -111
  332. package/src/lib/view/server.ts +0 -244
  333. package/src/lib/view/session.ts +0 -152
  334. package/src/lib/view/snapshot.ts +0 -101
  335. package/src/paths/.spec/api.d.ts +0 -13
  336. package/src/paths/.spec/architecture.md +0 -5
  337. package/src/paths/.spec/layout.ts +0 -3
  338. package/src/paths/index.ts +0 -13
  339. package/src/program/.spec/api.d.ts +0 -42
  340. package/src/program/.spec/architecture.md +0 -18
  341. package/src/program/.spec/laws/program.ts +0 -29
  342. package/src/program/.spec/layout.ts +0 -14
  343. package/src/program/__tests__/program.test.ts +0 -378
  344. package/src/program/build.ts +0 -183
  345. package/src/program/command.ts +0 -42
  346. package/src/program/index.ts +0 -2
  347. package/src/program/options.ts +0 -41
  348. package/src/program/registry.ts +0 -63
  349. package/src/program/tsconfig.json +0 -6
  350. package/src/setup/__tests__/instance-step.test.ts +0 -256
  351. package/src/setup/__tests__/util.test.ts +0 -29
  352. package/src/setup/engine.ts +0 -83
  353. package/src/setup/render.ts +0 -107
  354. package/src/setup/steps/admin.ts +0 -93
  355. package/src/setup/steps/agent-browser.ts +0 -81
  356. package/src/setup/steps/auth.ts +0 -54
  357. package/src/setup/steps/domain.ts +0 -68
  358. package/src/setup/steps/index.ts +0 -18
  359. package/src/setup/steps/instance.ts +0 -206
  360. package/src/setup/steps/skills-bridge.ts +0 -70
  361. package/src/setup/steps/skills.ts +0 -59
  362. package/src/setup/types.ts +0 -61
  363. package/src/setup/util.ts +0 -34
  364. package/src/state/.spec/api.d.ts +0 -133
  365. package/src/state/.spec/architecture.md +0 -31
  366. package/src/state/.spec/capabilities/state.ts +0 -7
  367. package/src/state/.spec/flows/identity-update.ts +0 -22
  368. package/src/state/.spec/laws/state.ts +0 -73
  369. package/src/state/.spec/layout.ts +0 -14
  370. package/src/state/__tests__/exchange-credentials.test.ts +0 -188
  371. package/src/state/__tests__/files.test.ts +0 -113
  372. package/src/state/__tests__/fixtures/identity-transition.ts +0 -37
  373. package/src/state/__tests__/identities.test.ts +0 -142
  374. package/src/state/__tests__/paths.test.ts +0 -27
  375. package/src/state/exchange-credentials.ts +0 -219
  376. package/src/state/files.ts +0 -129
  377. package/src/state/identities.ts +0 -229
  378. package/src/state/index.ts +0 -29
  379. package/src/state/paths.ts +0 -61
  380. package/src/state/tsconfig.json +0 -6
  381. package/src/telemetry/__tests__/gate.test.ts +0 -63
  382. package/src/telemetry/__tests__/recorder.test.ts +0 -110
  383. package/src/telemetry/__tests__/redact.test.ts +0 -79
  384. package/src/telemetry/__tests__/session.test.ts +0 -166
  385. package/src/telemetry/__tests__/trigger.test.ts +0 -49
  386. package/src/telemetry/adapters/__tests__/claude-code.test.ts +0 -89
  387. package/src/telemetry/adapters/__tests__/codex.test.ts +0 -138
  388. package/src/telemetry/adapters/__tests__/index.test.ts +0 -88
  389. package/src/telemetry/adapters/claude-code.ts +0 -90
  390. package/src/telemetry/adapters/codex.ts +0 -160
  391. package/src/telemetry/adapters/index.ts +0 -45
  392. package/src/telemetry/adapters/types.ts +0 -21
  393. package/src/telemetry/analyze.ts +0 -227
  394. package/src/telemetry/gate.ts +0 -79
  395. package/src/telemetry/recorder.ts +0 -57
  396. package/src/telemetry/redact.ts +0 -53
  397. package/src/telemetry/session.ts +0 -88
  398. package/src/telemetry/settings.ts +0 -26
  399. package/src/telemetry/store.ts +0 -91
  400. package/src/telemetry/trigger.ts +0 -119
  401. package/src/telemetry/types.ts +0 -64
  402. package/src/test-utils.ts +0 -18
  403. package/studio/client/dist/assets/elk-api-ByzoDZWH.js +0 -1
  404. package/studio/client/dist/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  405. package/studio/client/dist/assets/index-B0RCgUOT.js +0 -8
  406. package/studio/client/dist/assets/index-BiGR8Oo9.css +0 -1
  407. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  408. package/studio/client/dist/assets/index-N8J8EKlB.js +0 -81
  409. package/studio/client/dist/index.html +0 -13
  410. package/studio/package.json +0 -65
  411. package/studio/server/agent/ask.test.ts +0 -74
  412. package/studio/server/agent/ask.ts +0 -71
  413. package/studio/server/agent/bridge/client.test.ts +0 -49
  414. package/studio/server/agent/bridge/client.ts +0 -37
  415. package/studio/server/agent/bridge/grant.test.ts +0 -62
  416. package/studio/server/agent/bridge/grant.ts +0 -84
  417. package/studio/server/agent/bridge/routes.test.ts +0 -151
  418. package/studio/server/agent/bridge/routes.ts +0 -148
  419. package/studio/server/agent/bridge/stdio.ts +0 -195
  420. package/studio/server/agent/conversation.test.ts +0 -89
  421. package/studio/server/agent/conversation.ts +0 -158
  422. package/studio/server/agent/harness/adapter.ts +0 -171
  423. package/studio/server/agent/harness/claude/adapter.test.ts +0 -348
  424. package/studio/server/agent/harness/claude/adapter.ts +0 -71
  425. package/studio/server/agent/harness/claude/ask.ts +0 -114
  426. package/studio/server/agent/harness/claude/capabilities.ts +0 -27
  427. package/studio/server/agent/harness/claude/command.ts +0 -63
  428. package/studio/server/agent/harness/claude/events.ts +0 -215
  429. package/studio/server/agent/harness/claude/loadout.ts +0 -132
  430. package/studio/server/agent/harness/claude/mcp.test.ts +0 -36
  431. package/studio/server/agent/harness/claude/mcp.ts +0 -41
  432. package/studio/server/agent/harness/claude/skills.ts +0 -43
  433. package/studio/server/agent/harness/codex/adapter.test.ts +0 -269
  434. package/studio/server/agent/harness/codex/adapter.ts +0 -116
  435. package/studio/server/agent/harness/codex/ask.test.ts +0 -176
  436. package/studio/server/agent/harness/codex/ask.ts +0 -181
  437. package/studio/server/agent/harness/codex/command.test.ts +0 -69
  438. package/studio/server/agent/harness/codex/command.ts +0 -43
  439. package/studio/server/agent/harness/codex/events.test.ts +0 -94
  440. package/studio/server/agent/harness/codex/events.ts +0 -132
  441. package/studio/server/agent/harness/codex/exec.ts +0 -113
  442. package/studio/server/agent/harness/codex/loadout.ts +0 -60
  443. package/studio/server/agent/harness/codex/mcp.test.ts +0 -32
  444. package/studio/server/agent/harness/codex/mcp.ts +0 -27
  445. package/studio/server/agent/harness/codex/models.test.ts +0 -167
  446. package/studio/server/agent/harness/codex/models.ts +0 -211
  447. package/studio/server/agent/harness/codex/skills.ts +0 -33
  448. package/studio/server/agent/harness/gateway/config.test.ts +0 -98
  449. package/studio/server/agent/harness/gateway/config.ts +0 -214
  450. package/studio/server/agent/harness/gateway/token.test.ts +0 -133
  451. package/studio/server/agent/harness/gateway/token.ts +0 -166
  452. package/studio/server/agent/harness/mock/adapter.ts +0 -190
  453. package/studio/server/agent/harness/mock/domain-edit.ts +0 -41
  454. package/studio/server/agent/harness/process.test.ts +0 -46
  455. package/studio/server/agent/harness/process.ts +0 -104
  456. package/studio/server/agent/harness/registry.ts +0 -37
  457. package/studio/server/agent/harness/selection.test.ts +0 -75
  458. package/studio/server/agent/harness/selection.ts +0 -85
  459. package/studio/server/agent/harness/skills.test.ts +0 -95
  460. package/studio/server/agent/harness/skills.ts +0 -100
  461. package/studio/server/agent/layout.test.ts +0 -95
  462. package/studio/server/agent/notify.ts +0 -12
  463. package/studio/server/agent/prompts/anchors.test.ts +0 -70
  464. package/studio/server/agent/prompts/anchors.ts +0 -153
  465. package/studio/server/agent/prompts/ask.ts +0 -34
  466. package/studio/server/agent/prompts/system.test.ts +0 -13
  467. package/studio/server/agent/prompts/system.ts +0 -99
  468. package/studio/server/agent/prompts/turn.ts +0 -66
  469. package/studio/server/agent/routes.test.ts +0 -176
  470. package/studio/server/agent/routes.ts +0 -214
  471. package/studio/server/agent/run/completion.ts +0 -193
  472. package/studio/server/agent/run/coordinator.test.ts +0 -337
  473. package/studio/server/agent/run/coordinator.ts +0 -104
  474. package/studio/server/agent/run/live-state.ts +0 -73
  475. package/studio/server/agent/run/preparation.ts +0 -163
  476. package/studio/server/agent/run/transcript.test.ts +0 -81
  477. package/studio/server/agent/run/transcript.ts +0 -196
  478. package/studio/server/agent/run/usage.test.ts +0 -70
  479. package/studio/server/agent/run/usage.ts +0 -62
  480. package/studio/server/agent/stream.ts +0 -37
  481. package/studio/server/agent/telemetry.ts +0 -13
  482. package/studio/server/api/canvas.ts +0 -43
  483. package/studio/server/api/comments.ts +0 -85
  484. package/studio/server/api/context.ts +0 -61
  485. package/studio/server/api/deployment.ts +0 -39
  486. package/studio/server/api/documents.ts +0 -55
  487. package/studio/server/api/domain.ts +0 -59
  488. package/studio/server/api/http.ts +0 -45
  489. package/studio/server/api/project.ts +0 -57
  490. package/studio/server/api/schema.ts +0 -12
  491. package/studio/server/api/views.ts +0 -57
  492. package/studio/server/api/workspace.ts +0 -60
  493. package/studio/server/api-agent-loadout.test.ts +0 -69
  494. package/studio/server/api.test.ts +0 -147
  495. package/studio/server/api.ts +0 -34
  496. package/studio/server/cache.test.ts +0 -122
  497. package/studio/server/cache.ts +0 -303
  498. package/studio/server/cli-consumers.test.ts +0 -494
  499. package/studio/server/cli.test.ts +0 -88
  500. package/studio/server/cli.ts +0 -240
  501. package/studio/server/client-package.test.ts +0 -147
  502. package/studio/server/client-package.ts +0 -266
  503. package/studio/server/detect.ts +0 -81
  504. package/studio/server/domain.test.ts +0 -77
  505. package/studio/server/domain.ts +0 -124
  506. package/studio/server/environment/dotenv-preview.test.ts +0 -39
  507. package/studio/server/environment/dotenv-preview.ts +0 -27
  508. package/studio/server/environment/files.test.ts +0 -53
  509. package/studio/server/environment/files.ts +0 -120
  510. package/studio/server/handoff/copy.ts +0 -171
  511. package/studio/server/handoff/service.test.ts +0 -22
  512. package/studio/server/handoff/service.ts +0 -62
  513. package/studio/server/index.ts +0 -148
  514. package/studio/server/instances/active.ts +0 -72
  515. package/studio/server/instances/deploy-record.test.ts +0 -31
  516. package/studio/server/instances/deploy-record.ts +0 -37
  517. package/studio/server/instances/deploy.ts +0 -56
  518. package/studio/server/instances/probe.test.ts +0 -67
  519. package/studio/server/instances/probe.ts +0 -67
  520. package/studio/server/instances/status.test.ts +0 -12
  521. package/studio/server/instances/status.ts +0 -49
  522. package/studio/server/introspect/anatomy/client-tree.ts +0 -57
  523. package/studio/server/introspect/anatomy/env-fields.ts +0 -66
  524. package/studio/server/introspect/anatomy/schema-definition.ts +0 -53
  525. package/studio/server/introspect/anatomy/source.ts +0 -181
  526. package/studio/server/introspect/anatomy/views/routes.ts +0 -114
  527. package/studio/server/introspect/anatomy/views.ts +0 -53
  528. package/studio/server/introspect/anatomy-extras.test.ts +0 -265
  529. package/studio/server/introspect/anatomy-extras.ts +0 -10
  530. package/studio/server/introspect/anatomy.test.ts +0 -41
  531. package/studio/server/introspect/anatomy.ts +0 -147
  532. package/studio/server/introspect/bundle.ts +0 -69
  533. package/studio/server/introspect/canonical-schema.test.ts +0 -179
  534. package/studio/server/introspect/canonical-schema.ts +0 -583
  535. package/studio/server/introspect/config-preview.test.ts +0 -32
  536. package/studio/server/introspect/config-preview.ts +0 -119
  537. package/studio/server/introspect/core-extractor.ts +0 -30
  538. package/studio/server/introspect/core.ts +0 -45
  539. package/studio/server/introspect/diff.test.ts +0 -124
  540. package/studio/server/introspect/diff.ts +0 -316
  541. package/studio/server/introspect/extractor.ts +0 -41
  542. package/studio/server/introspect/hash.ts +0 -24
  543. package/studio/server/introspect/overlay-tsmorph.test.ts +0 -146
  544. package/studio/server/introspect/overlay-tsmorph.ts +0 -9
  545. package/studio/server/introspect/overlay.test.ts +0 -44
  546. package/studio/server/introspect/overlay.ts +0 -40
  547. package/studio/server/introspect/revision.test.ts +0 -54
  548. package/studio/server/introspect/revision.ts +0 -49
  549. package/studio/server/introspect/runtime.test.ts +0 -157
  550. package/studio/server/introspect/runtime.ts +0 -140
  551. package/studio/server/introspect/schema-ir-json.test.ts +0 -70
  552. package/studio/server/introspect/schema-ir-json.ts +0 -151
  553. package/studio/server/introspect/schema-refs.test.ts +0 -55
  554. package/studio/server/introspect/schema-refs.ts +0 -32
  555. package/studio/server/introspect/source-overlay/annotations.ts +0 -14
  556. package/studio/server/introspect/source-overlay/handlers.ts +0 -161
  557. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -46
  558. package/studio/server/introspect/source-overlay/project.ts +0 -248
  559. package/studio/server/introspect/source-overlay/spans.ts +0 -330
  560. package/studio/server/json.ts +0 -46
  561. package/studio/server/lifecycle.ts +0 -42
  562. package/studio/server/sse.test.ts +0 -26
  563. package/studio/server/sse.ts +0 -60
  564. package/studio/server/state/baseline.test.ts +0 -267
  565. package/studio/server/state/baseline.ts +0 -354
  566. package/studio/server/state/comments.test.ts +0 -94
  567. package/studio/server/state/comments.ts +0 -484
  568. package/studio/server/state/context.ts +0 -199
  569. package/studio/server/state/documents.ts +0 -111
  570. package/studio/server/state/integrations.ts +0 -81
  571. package/studio/server/state/layout.test.ts +0 -34
  572. package/studio/server/state/layout.ts +0 -82
  573. package/studio/server/state/settings.test.ts +0 -78
  574. package/studio/server/state/settings.ts +0 -73
  575. package/studio/server/state/store.test.ts +0 -122
  576. package/studio/server/state/store.ts +0 -146
  577. package/studio/server/state/visibility.ts +0 -48
  578. package/studio/server/views/model.test.ts +0 -57
  579. package/studio/server/views/model.ts +0 -66
  580. package/studio/server/views/runtime.ts +0 -40
  581. package/studio/server/views/selection-repository.test.ts +0 -31
  582. package/studio/server/views/selection-repository.ts +0 -60
  583. package/studio/server/views/session.test.ts +0 -73
  584. package/studio/server/views/session.ts +0 -166
  585. package/studio/server/views/target.test.ts +0 -78
  586. package/studio/server/views/target.ts +0 -222
  587. package/studio/server/watch.test.ts +0 -36
  588. package/studio/server/watch.ts +0 -93
  589. package/studio/server/workspace/catalog.test.ts +0 -17
  590. package/studio/server/workspace/catalog.ts +0 -43
  591. package/studio/server/workspace/create.test.ts +0 -37
  592. package/studio/server/workspace/create.ts +0 -162
  593. package/studio/server/workspace/git.ts +0 -75
  594. package/studio/server/workspace/updates.ts +0 -83
  595. package/studio/server/workspace-state.ts +0 -26
  596. package/studio/server/workspace-watch.ts +0 -106
  597. package/studio/shared/agent-effort.test.ts +0 -12
  598. package/studio/shared/agent-effort.ts +0 -15
  599. package/studio/shared/agent-models.test.ts +0 -9
  600. package/studio/shared/agent-models.ts +0 -14
  601. package/studio/shared/contracts/README.md +0 -16
  602. package/studio/shared/contracts/agent.ts +0 -270
  603. package/studio/shared/contracts/runtime.ts +0 -50
  604. package/studio/shared/contracts/schema.ts +0 -393
  605. package/studio/shared/contracts/surface.test.ts +0 -317
  606. package/studio/shared/contracts/workspace.ts +0 -265
  607. package/studio/shared/layout.test.ts +0 -116
  608. package/studio/shared/schema/identity.test.ts +0 -34
  609. package/studio/shared/schema/identity.ts +0 -68
  610. package/studio/shared/settings-values.test.ts +0 -18
  611. package/studio/shared/settings-values.ts +0 -20
  612. package/studio/shared/types.ts +0 -14
  613. package/studio/tsconfig.json +0 -23
  614. package/tsconfig.json +0 -14
  615. package/viewer/dist/index.html +0 -93
  616. package/viewer/dist/main.js +0 -76
  617. package/viewer/tsconfig.json +0 -13
package/src/lib/idp.ts DELETED
@@ -1,906 +0,0 @@
1
- import { decodeJwt, type JWTPayload } from 'jose'
2
- import { mkdir, readFile, readdir, unlink } from 'node:fs/promises'
3
- import { dirname, join } from 'node:path'
4
- import { z } from 'zod'
5
-
6
- import { atomicWrite, IDPS_PATH, IDP_SESSIONS_DIR, paths } from '../state/index'
7
- import { log } from './log'
8
- import { validateName, validateUrl } from './validation'
9
-
10
- /**
11
- * Thrown when a refresh succeeds but the IdP mints an access token whose `aud`
12
- * does not match the one the caller requested. Distinct from a transport/grant
13
- * failure: the session is *healthy*, the IdP simply will not issue that
14
- * audience (e.g. WorkOS AuthKit ignores the `audience` param and stamps a fixed
15
- * API audience per environment). Re-login does not help — callers must target
16
- * an instance whose audience equals `actual`, or reconfigure the IdP/bookmark.
17
- */
18
- export class IdpAudienceMismatchError extends Error {
19
- readonly requested: string
20
- readonly actual: string | undefined
21
-
22
- constructor(requested: string, actual: string | undefined) {
23
- super(
24
- `IdP minted an access token for audience ${actual ?? '(none)'} but ${requested} was required`,
25
- )
26
- this.name = 'IdpAudienceMismatchError'
27
- this.requested = requested
28
- this.actual = actual
29
- }
30
- }
31
-
32
- /**
33
- * A token-endpoint request that the IdP answered with an OAuth error (or that
34
- * failed at the HTTP layer). Carries the structured OAuth `error` code so
35
- * callers can tell a definitively dead grant (`invalid_grant`) from a
36
- * transient outage — the message string alone cannot.
37
- */
38
- export class OAuthTokenError extends Error {
39
- /** OAuth `error` code, e.g. `invalid_grant`. */
40
- readonly code?: string
41
- /** OAuth `error_description`. */
42
- readonly description?: string
43
- /** HTTP status of the token response. */
44
- readonly status?: number
45
-
46
- constructor(args: { code?: string; description?: string; status?: number }) {
47
- super(
48
- `OAuth token request failed: ${args.description ?? args.code ?? `HTTP ${args.status ?? '?'}`}`,
49
- )
50
- this.name = 'OAuthTokenError'
51
- this.code = args.code
52
- this.description = args.description
53
- this.status = args.status
54
- }
55
- }
56
-
57
- export type RefreshFailureKind = 'session-ended' | 'org-rejected' | 'transient' | 'unknown'
58
-
59
- /**
60
- * Classify a `refreshSession` failure so callers only demand a re-login when
61
- * the grant is actually dead. `org-rejected` = healthy session, wrong/stale
62
- * org scope (re-login can't fix it); 5xx/429 and fetch-layer failures are
63
- * transient — the cached session is likely still valid.
64
- */
65
- export function classifyRefreshFailure(e: unknown): RefreshFailureKind {
66
- if (e instanceof OAuthTokenError) {
67
- if (
68
- /not a member of the organization|organization not found/i.test(e.description ?? e.message)
69
- ) {
70
- return 'org-rejected'
71
- }
72
- if (e.code === 'invalid_grant') return 'session-ended'
73
- if (e.status !== undefined && (e.status >= 500 || e.status === 429)) return 'transient'
74
- return 'unknown'
75
- }
76
- if (e instanceof Error) {
77
- if (e.name === 'AbortError' || e.name === 'TimeoutError') return 'transient'
78
- // Node's fetch rejects network-layer failures as TypeError.
79
- if (e instanceof TypeError) return 'transient'
80
- // Bun stamps codes like ConnectionRefused/ConnectionClosed/FailedToOpenSocket;
81
- // Node uses the classic ECONN*/ETIMEDOUT family.
82
- const code = (e as { code?: string }).code
83
- if (
84
- typeof code === 'string' &&
85
- /^(ECONN|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|ENETUNREACH|Connection|FailedToOpenSocket|Timeout)/.test(
86
- code,
87
- )
88
- ) {
89
- return 'transient'
90
- }
91
- }
92
- return 'unknown'
93
- }
94
-
95
- export const OidcMetadataSchema = z
96
- .object({
97
- issuer: z.string().url(),
98
- authorization_endpoint: z.string().url().optional(),
99
- token_endpoint: z.string().url(),
100
- jwks_uri: z.string().url(),
101
- device_authorization_endpoint: z.string().url().optional(),
102
- revocation_endpoint: z.string().url().optional(),
103
- scopes_supported: z.array(z.string()).optional(),
104
- grant_types_supported: z.array(z.string()).optional(),
105
- response_types_supported: z.array(z.string()).optional(),
106
- code_challenge_methods_supported: z.array(z.string()).optional(),
107
- })
108
- .passthrough()
109
-
110
- export type OidcMetadata = z.infer<typeof OidcMetadataSchema>
111
-
112
- export const IdpClientConfigSchema = z
113
- .object({
114
- client_id: z.string().optional(),
115
- client_secret_env: z.string().optional(),
116
- redirect_uris: z.array(z.string().url()).optional(),
117
- scope: z.string().optional(),
118
- public: z.boolean().optional(),
119
- token_response: z.enum(['oauth', 'workos-authkit']).optional(),
120
- token_request_format: z.enum(['form', 'json']).optional(),
121
- workos_application_id: z.string().optional(),
122
- workos_application_type: z.enum(['oauth', 'm2m']).optional(),
123
- })
124
- .passthrough()
125
-
126
- export type IdpClientConfig = z.infer<typeof IdpClientConfigSchema>
127
-
128
- export const IdpIndexEntrySchema = z.object({
129
- issuer: z.string().url(),
130
- builtIn: z.boolean().optional(),
131
- createdAt: z.string(),
132
- updatedAt: z.string(),
133
- })
134
-
135
- export const IdpStoreSchema = z.object({
136
- idps: z.record(z.string(), IdpIndexEntrySchema),
137
- })
138
-
139
- export type IdpStore = z.infer<typeof IdpStoreSchema>
140
- export type IdpIndexEntry = z.infer<typeof IdpIndexEntrySchema>
141
-
142
- export const IdpSessionSchema = z
143
- .object({
144
- identity: z.string(),
145
- idp: z.string(),
146
- issuer: z.string().url(),
147
- subject: z.string(),
148
- /** OAuth client that issued this session's refresh token. */
149
- clientId: z.string().optional(),
150
- audience: z.string().optional(),
151
- organizationId: z.string().optional(),
152
- access_token: z.string(),
153
- id_token: z.string().optional(),
154
- refresh_token: z.string().optional(),
155
- token_type: z.string().optional(),
156
- scope: z.string().optional(),
157
- expires_at: z.string().optional(),
158
- claims: z.record(z.string(), z.unknown()).optional(),
159
- /**
160
- * Access tokens by audience. WorkOS mints one `aud` per token, so a
161
- * session juggling several instances would otherwise burn a (single-use)
162
- * refresh-token rotation on every instance flip. The top-level
163
- * `access_token`/`expires_at` stay the most recently minted token for
164
- * back-compat with older CLI builds.
165
- */
166
- tokens: z
167
- .record(
168
- z.string(),
169
- z.object({ access_token: z.string(), expires_at: z.string().optional() }).passthrough(),
170
- )
171
- .optional(),
172
- updatedAt: z.string(),
173
- })
174
- .passthrough()
175
-
176
- export type IdpSession = z.infer<typeof IdpSessionSchema>
177
-
178
- export type TokenResponse = {
179
- access_token?: string
180
- accessToken?: string
181
- id_token?: string
182
- idToken?: string
183
- refresh_token?: string
184
- refreshToken?: string
185
- token_type?: string
186
- scope?: string
187
- expires_in?: number
188
- expiresIn?: number
189
- user?: { id?: string; [key: string]: unknown }
190
- organization_id?: string
191
- authentication_method?: string
192
- error?: string
193
- error_description?: string
194
- [key: string]: unknown
195
- }
196
-
197
- export type DeviceAuthorizationResponse = {
198
- device_code: string
199
- user_code?: string
200
- verification_uri?: string
201
- verification_uri_complete?: string
202
- expires_in: number
203
- interval?: number
204
- message?: string
205
- [key: string]: unknown
206
- }
207
-
208
- export type IdpConfig = {
209
- name: string
210
- entry: IdpIndexEntry
211
- metadata: OidcMetadata
212
- client: IdpClientConfig
213
- }
214
-
215
- export const BUILTIN_WORKOS_IDP_NAME = 'workos'
216
- const DEFAULT_WORKOS_API_HOST = 'https://api.workos.com'
217
- const DEFAULT_WORKOS_CLIENT_ID = 'client_01KC29HET5F3QAQ8GNTPZ7F320'
218
- const LEGACY_WORKOS_CLIENT_ID = 'client_01KC29HEGD7B40TV2C4QZ436BG'
219
- const WORKOS_CLIENT_ID_ENV_NAMES = ['WORKOS_CLIENT_ID', 'VITE_WORKOS_CLIENT_ID'] as const
220
-
221
- export function idpDir(name: string): string {
222
- return paths.idpDir(name)
223
- }
224
-
225
- export function idpMetadataPath(name: string): string {
226
- return join(idpDir(name), 'metadata.json')
227
- }
228
-
229
- export function idpClientPath(name: string): string {
230
- return join(idpDir(name), 'client.json')
231
- }
232
-
233
- export function idpSessionPath(identityName: string): string {
234
- validateName(identityName, 'Identity')
235
- return paths.idpSession(identityName)
236
- }
237
-
238
- export async function readIdpStore(): Promise<IdpStore> {
239
- try {
240
- const raw = await readFile(IDPS_PATH, 'utf-8')
241
- return IdpStoreSchema.parse(JSON.parse(raw))
242
- } catch (e) {
243
- if (e instanceof z.ZodError) {
244
- log.warn(`Invalid IdP index at ${IDPS_PATH} — using empty registry`)
245
- } else if ((e as { code?: string }).code !== 'ENOENT') {
246
- log.warn(`Could not read IdP index at ${IDPS_PATH} — using empty registry`)
247
- }
248
- return { idps: {} }
249
- }
250
- }
251
-
252
- export async function writeIdpStore(store: IdpStore): Promise<void> {
253
- await mkdir(dirname(IDPS_PATH), { recursive: true })
254
- await atomicWrite(IDPS_PATH, JSON.stringify(store, null, 2) + '\n')
255
- }
256
-
257
- export async function readIdpConfig(name: string): Promise<IdpConfig> {
258
- validateName(name, 'IdP')
259
- const store = await readIdpStore()
260
- const entry = store.idps[name]
261
- if (!entry)
262
- throw new Error(`IdP "${name}" not found. Run: astrale idp add ${name} --issuer <url>`)
263
- const [metadataRaw, clientRaw] = await Promise.all([
264
- readFile(idpMetadataPath(name), 'utf-8'),
265
- readFile(idpClientPath(name), 'utf-8').catch((e) => {
266
- if ((e as { code?: string }).code === 'ENOENT') return '{}'
267
- throw e
268
- }),
269
- ])
270
- return {
271
- name,
272
- entry,
273
- metadata: OidcMetadataSchema.parse(JSON.parse(metadataRaw)),
274
- client: IdpClientConfigSchema.parse(JSON.parse(clientRaw)),
275
- }
276
- }
277
-
278
- export async function readIdpConfigOrBuiltin(
279
- name: string,
280
- opts: { clientId?: string; persist?: boolean } = {},
281
- ): Promise<IdpConfig> {
282
- validateName(name, 'IdP')
283
- const store = await readIdpStore()
284
- if (store.idps[name]) {
285
- const existing = await readIdpConfig(name)
286
- const replacement = opts.persist
287
- ? legacyBuiltinWorkosReplacement(existing, opts.clientId)
288
- : undefined
289
- if (!replacement) return existing
290
- return upsertIdpConfig({
291
- name: replacement.name,
292
- metadata: replacement.metadata,
293
- client: replacement.client,
294
- builtIn: true,
295
- })
296
- }
297
-
298
- const builtin = builtinIdpConfig(name, opts.clientId)
299
- if (!builtin) {
300
- throw new Error(`IdP "${name}" not found. Run: astrale idp add ${name} --issuer <url>`)
301
- }
302
- if (!opts.persist) return builtin
303
- return upsertIdpConfig({
304
- name: builtin.name,
305
- metadata: builtin.metadata,
306
- client: builtin.client,
307
- builtIn: true,
308
- })
309
- }
310
-
311
- export async function listIdpConfigs(): Promise<IdpConfig[]> {
312
- const store = await readIdpStore()
313
- const entries = await Promise.all(
314
- Object.keys(store.idps).map((name) => readIdpConfig(name).catch(() => undefined)),
315
- )
316
- const configs = entries.filter((entry): entry is IdpConfig => !!entry)
317
- if (!store.idps[BUILTIN_WORKOS_IDP_NAME]) {
318
- const workos = builtinIdpConfig(BUILTIN_WORKOS_IDP_NAME)
319
- if (workos) configs.push(workos)
320
- }
321
- return configs
322
- }
323
-
324
- export async function upsertIdpConfig(args: {
325
- name: string
326
- metadata: OidcMetadata
327
- client?: IdpClientConfig
328
- builtIn?: boolean
329
- }): Promise<IdpConfig> {
330
- validateName(args.name, 'IdP')
331
- const store = await readIdpStore()
332
- const now = new Date().toISOString()
333
- const existing = store.idps[args.name]
334
- store.idps[args.name] = {
335
- issuer: args.metadata.issuer,
336
- builtIn: args.builtIn ?? existing?.builtIn,
337
- createdAt: existing?.createdAt ?? now,
338
- updatedAt: now,
339
- }
340
- await mkdir(idpDir(args.name), { recursive: true })
341
- await Promise.all([
342
- atomicWrite(idpMetadataPath(args.name), JSON.stringify(args.metadata, null, 2) + '\n'),
343
- atomicWrite(idpClientPath(args.name), JSON.stringify(args.client ?? {}, null, 2) + '\n'),
344
- writeIdpStore(store),
345
- ])
346
- return readIdpConfig(args.name)
347
- }
348
-
349
- export async function removeIdpConfig(name: string): Promise<void> {
350
- validateName(name, 'IdP')
351
- const store = await readIdpStore()
352
- const entry = store.idps[name]
353
- if (!entry) throw new Error(`IdP "${name}" not found`)
354
- if (entry.builtIn) throw new Error(`Cannot remove built-in IdP "${name}"`)
355
- delete store.idps[name]
356
- await writeIdpStore(store)
357
- await unlink(idpMetadataPath(name)).catch(() => undefined)
358
- await unlink(idpClientPath(name)).catch(() => undefined)
359
- }
360
-
361
- export async function fetchOidcMetadata(issuer: string): Promise<OidcMetadata> {
362
- validateUrl(issuer)
363
- const discoveryUrl = new URL('/.well-known/openid-configuration', issuer)
364
- const response = await fetch(discoveryUrl)
365
- if (!response.ok) {
366
- throw new Error(`OIDC discovery failed for ${issuer}: HTTP ${response.status}`)
367
- }
368
- const body = await response.json()
369
- let metadata = OidcMetadataSchema.parse(body)
370
- if (normalizeIssuer(metadata.issuer) !== normalizeIssuer(issuer)) {
371
- throw new Error(
372
- `OIDC issuer mismatch: discovery returned ${metadata.issuer}, expected ${issuer}`,
373
- )
374
- }
375
- if (!metadata.device_authorization_endpoint) {
376
- const oauthMetadata = await fetchOAuthAuthorizationServerMetadata(issuer).catch(() => undefined)
377
- if (oauthMetadata) metadata = OidcMetadataSchema.parse({ ...metadata, ...oauthMetadata })
378
- }
379
- return metadata
380
- }
381
-
382
- export function workosAuthKitMetadata(
383
- apiHost = 'https://api.workos.com',
384
- clientId?: string,
385
- ): OidcMetadata {
386
- validateUrl(apiHost)
387
- const base = apiHost.replace(/\/+$/, '')
388
- return OidcMetadataSchema.parse({
389
- issuer: base,
390
- authorization_endpoint: `${base}/user_management/authorize`,
391
- token_endpoint: `${base}/user_management/authenticate`,
392
- device_authorization_endpoint: `${base}/user_management/authorize/device`,
393
- jwks_uri: clientId ? `${base}/sso/jwks/${clientId}` : `${base}/sso/jwks`,
394
- grant_types_supported: ['urn:ietf:params:oauth:grant-type:device_code'],
395
- response_types_supported: ['code'],
396
- })
397
- }
398
-
399
- export function builtinIdpConfig(
400
- name: string,
401
- clientIdOverride?: string,
402
- env: NodeJS.ProcessEnv = process.env,
403
- ): IdpConfig | null {
404
- if (name !== BUILTIN_WORKOS_IDP_NAME) return null
405
- const clientId = clientIdOverride ?? workosClientIdFromEnv(env)
406
- if (!clientId) return null
407
- const apiHost = env.WORKOS_API_HOSTNAME ?? DEFAULT_WORKOS_API_HOST
408
- const now = new Date().toISOString()
409
- return {
410
- name: BUILTIN_WORKOS_IDP_NAME,
411
- entry: {
412
- issuer: apiHost.replace(/\/+$/, ''),
413
- builtIn: true,
414
- createdAt: now,
415
- updatedAt: now,
416
- },
417
- metadata: workosAuthKitMetadata(apiHost, clientId),
418
- client: {
419
- client_id: clientId,
420
- public: true,
421
- token_response: 'workos-authkit',
422
- token_request_format: 'json',
423
- },
424
- }
425
- }
426
-
427
- export function workosClientIdFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
428
- return (
429
- WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env[name]?.trim()).find(
430
- (value): value is string => typeof value === 'string' && value.length > 0,
431
- ) ?? DEFAULT_WORKOS_CLIENT_ID
432
- )
433
- }
434
-
435
- export function legacyBuiltinWorkosReplacement(
436
- existing: IdpConfig,
437
- clientIdOverride?: string,
438
- env: NodeJS.ProcessEnv = process.env,
439
- ): IdpConfig | undefined {
440
- if (
441
- existing.name !== BUILTIN_WORKOS_IDP_NAME ||
442
- !existing.entry.builtIn ||
443
- existing.client.client_id !== LEGACY_WORKOS_CLIENT_ID
444
- ) {
445
- return undefined
446
- }
447
- const replacement = builtinIdpConfig(existing.name, clientIdOverride, env)
448
- if (!replacement || replacement.client.client_id === LEGACY_WORKOS_CLIENT_ID) return undefined
449
- return replacement
450
- }
451
-
452
- async function fetchOAuthAuthorizationServerMetadata(
453
- issuer: string,
454
- ): Promise<Partial<OidcMetadata> | undefined> {
455
- const discoveryUrl = new URL('/.well-known/oauth-authorization-server', issuer)
456
- const response = await fetch(discoveryUrl)
457
- if (!response.ok) return undefined
458
- const body = (await response.json()) as Partial<OidcMetadata>
459
- if (typeof body.issuer === 'string' && normalizeIssuer(body.issuer) !== normalizeIssuer(issuer)) {
460
- return undefined
461
- }
462
- return body
463
- }
464
-
465
- export async function postForm(url: string, params: URLSearchParams): Promise<TokenResponse> {
466
- const response = await fetch(url, {
467
- method: 'POST',
468
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
469
- body: params,
470
- })
471
- return tokenResponseFrom(response)
472
- }
473
-
474
- export async function postJson(
475
- url: string,
476
- bodyInput: Record<string, string>,
477
- ): Promise<TokenResponse> {
478
- const response = await fetch(url, {
479
- method: 'POST',
480
- headers: { 'Content-Type': 'application/json' },
481
- body: JSON.stringify(bodyInput),
482
- })
483
- return tokenResponseFrom(response)
484
- }
485
-
486
- async function tokenResponseFrom(response: Response): Promise<TokenResponse> {
487
- const text = await response.text()
488
- let body: TokenResponse = {}
489
- try {
490
- body = text ? (JSON.parse(text) as TokenResponse) : {}
491
- } catch {
492
- // Non-JSON body (e.g. an HTML 502 from a proxy): surface the HTTP failure,
493
- // keep a snippet for diagnostics.
494
- throw new OAuthTokenError({
495
- status: response.status,
496
- description: `HTTP ${response.status} — non-JSON response: ${text.slice(0, 200)}`,
497
- })
498
- }
499
- if (!response.ok || body.error) {
500
- throw new OAuthTokenError({
501
- code: body.error,
502
- description: body.error_description,
503
- status: response.status,
504
- })
505
- }
506
- return body
507
- }
508
-
509
- export function tokenExpiresAt(token: TokenResponse): string | undefined {
510
- const expiresIn =
511
- typeof token.expires_in === 'number'
512
- ? token.expires_in
513
- : typeof token.expiresIn === 'number'
514
- ? token.expiresIn
515
- : undefined
516
- if (typeof expiresIn === 'number') return new Date(Date.now() + expiresIn * 1000).toISOString()
517
- return tokenExpiresAtFromJwt(token.access_token ?? token.accessToken ?? token.id_token)
518
- }
519
-
520
- export function decodeTokenClaims(token: string | undefined): JWTPayload | undefined {
521
- if (!token) return undefined
522
- try {
523
- return decodeJwt(token)
524
- } catch {
525
- return undefined
526
- }
527
- }
528
-
529
- export function tokenAudienceMatches(token: string | undefined, audience: string): boolean {
530
- const actual = decodeTokenClaims(token)?.aud
531
- if (Array.isArray(actual)) return actual.includes(audience)
532
- return actual === audience
533
- }
534
-
535
- function tokenExpiresAtFromJwt(token: string | undefined): string | undefined {
536
- const claims = decodeTokenClaims(token)
537
- return typeof claims?.exp === 'number' ? new Date(claims.exp * 1000).toISOString() : undefined
538
- }
539
-
540
- export function subjectFromToken(token: TokenResponse, fallback: string): string {
541
- const claims = decodeTokenClaims(token.id_token ?? token.access_token)
542
- const sub = claims?.sub
543
- return typeof sub === 'string' && sub ? sub : (token.user?.id ?? fallback)
544
- }
545
-
546
- export function issuerFromToken(token: TokenResponse, fallback: string): string {
547
- const claims = decodeTokenClaims(token.id_token ?? token.access_token)
548
- const iss = claims?.iss
549
- return typeof iss === 'string' && iss ? iss : fallback
550
- }
551
-
552
- export function normalizeTokenResponse(token: TokenResponse): TokenResponse {
553
- return {
554
- ...token,
555
- access_token: token.access_token ?? token.accessToken,
556
- id_token: token.id_token ?? token.idToken,
557
- refresh_token: token.refresh_token ?? token.refreshToken,
558
- }
559
- }
560
-
561
- export function identityNameFromClaims(claims: JWTPayload | undefined, fallback: string): string {
562
- const preferred = [claims?.email, claims?.preferred_username, claims?.sub, fallback].find(
563
- (v) => typeof v === 'string' && v.length > 0,
564
- ) as string
565
- const normalized = preferred.replace(/[^a-zA-Z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '')
566
- return normalized || fallback
567
- }
568
-
569
- export async function saveIdpSession(session: IdpSession): Promise<void> {
570
- const path = idpSessionPath(session.identity)
571
- await mkdir(dirname(path), { recursive: true })
572
- await atomicWrite(path, JSON.stringify(session, null, 2) + '\n')
573
- }
574
-
575
- export async function readIdpSession(identityName: string): Promise<IdpSession | null> {
576
- try {
577
- const raw = await readFile(idpSessionPath(identityName), 'utf-8')
578
- return IdpSessionSchema.parse(JSON.parse(raw))
579
- } catch (e) {
580
- if ((e as { code?: string }).code === 'ENOENT') return null
581
- if (e instanceof z.ZodError) {
582
- throw new Error(`Invalid IdP session cache for "${identityName}"`)
583
- }
584
- throw e
585
- }
586
- }
587
-
588
- export async function deleteIdpSession(identityName: string): Promise<void> {
589
- await unlink(idpSessionPath(identityName)).catch(() => undefined)
590
- }
591
-
592
- export async function listIdpSessions(): Promise<IdpSession[]> {
593
- const out: IdpSession[] = []
594
- let entries: string[] = []
595
- try {
596
- entries = (await readdir(IDP_SESSIONS_DIR)).filter((entry) => entry.endsWith('.json'))
597
- } catch {
598
- return out
599
- }
600
- for (const entry of entries) {
601
- const name = entry.replace(/\.json$/, '')
602
- const session = await readIdpSession(name).catch(() => null)
603
- if (session) out.push(session)
604
- }
605
- return out
606
- }
607
-
608
- export function isSessionExpired(
609
- session: Pick<IdpSession, 'expires_at'> & { access_token?: string },
610
- skewMs = 60_000,
611
- ): boolean {
612
- const expiresAt = session.expires_at ?? tokenExpiresAtFromJwt(session.access_token)
613
- if (!expiresAt) return false
614
- return new Date(expiresAt).getTime() <= Date.now() + skewMs
615
- }
616
-
617
- /**
618
- * A still-fresh access token usable for `audience`, or undefined when a
619
- * refresh is needed. Checks the per-audience `tokens` map first, then the
620
- * top-level token's own `aud` claim. Without an `audience`, freshness of the
621
- * top-level token is the only requirement.
622
- */
623
- export function accessTokenForAudience(session: IdpSession, audience?: string): string | undefined {
624
- if (audience === undefined) {
625
- return isSessionExpired(session) ? undefined : session.access_token
626
- }
627
- const entry = session.tokens?.[audience]
628
- if (entry && !isSessionExpired(entry)) return entry.access_token
629
- if (!isSessionExpired(session) && tokenAudienceMatches(session.access_token, audience)) {
630
- return session.access_token
631
- }
632
- return undefined
633
- }
634
-
635
- /**
636
- * Fold a freshly minted access token into the per-audience map under every
637
- * `aud` it carries, dropping entries that have already expired.
638
- */
639
- export function withCachedToken(
640
- tokens: IdpSession['tokens'],
641
- accessToken: string,
642
- expiresAt: string | undefined,
643
- ): IdpSession['tokens'] {
644
- const next: NonNullable<IdpSession['tokens']> = {}
645
- for (const [aud, entry] of Object.entries(tokens ?? {})) {
646
- if (!isSessionExpired(entry)) next[aud] = entry
647
- }
648
- const aud = decodeTokenClaims(accessToken)?.aud
649
- const audiences = Array.isArray(aud) ? aud : typeof aud === 'string' ? [aud] : []
650
- for (const audience of audiences) {
651
- next[audience] = { access_token: accessToken, expires_at: expiresAt }
652
- }
653
- return Object.keys(next).length > 0 ? next : undefined
654
- }
655
-
656
- export function requireClientId(idp: IdpConfig, override?: string): string {
657
- const clientId = override ?? idp.client.client_id
658
- if (!clientId) {
659
- throw new Error(`IdP "${idp.name}" has no client_id. Re-run idp add with --client-id.`)
660
- }
661
- return clientId
662
- }
663
-
664
- export function resolveClientSecret(idp: IdpConfig, overrideEnv?: string): string | undefined {
665
- const envName = overrideEnv ?? idp.client.client_secret_env
666
- if (!envName) return undefined
667
- const secret = process.env[envName]
668
- if (!secret) throw new Error(`Client secret env var ${envName} is not set`)
669
- return secret
670
- }
671
-
672
- export async function refreshSession(
673
- identityName: string,
674
- session: IdpSession,
675
- opts: { readonly audience?: string; readonly organizationId?: string } = {},
676
- ): Promise<IdpSession> {
677
- if (!session.refresh_token)
678
- throw new Error(`IdP session for "${identityName}" has no refresh token`)
679
- const idp = await readIdpConfig(session.idp)
680
- const clientId = requireClientId(idp, session.clientId)
681
- const params = new URLSearchParams({
682
- grant_type: 'refresh_token',
683
- refresh_token: session.refresh_token,
684
- client_id: clientId,
685
- })
686
- const audience = opts.audience ?? session.audience
687
- if (audience) params.set('audience', audience)
688
- const organizationId = opts.organizationId ?? session.organizationId
689
- if (organizationId) params.set('organization_id', organizationId)
690
- if (process.env.ASTRALE_DEBUG_ORG)
691
- console.error(
692
- '[debug-org] refresh',
693
- JSON.stringify({
694
- audience,
695
- organizationId,
696
- sub: (session.claims as { sub?: string } | undefined)?.sub,
697
- }),
698
- )
699
- const secret = resolveClientSecret(idp)
700
- if (secret) params.set('client_secret', secret)
701
- const token = normalizeTokenResponse(
702
- idp.client.token_request_format === 'json'
703
- ? await postJson(idp.metadata.token_endpoint, Object.fromEntries(params))
704
- : await postForm(idp.metadata.token_endpoint, params),
705
- )
706
- if (!token.access_token) throw new Error('Refresh response did not include access_token')
707
- const claims = decodeTokenClaims(token.id_token ?? token.access_token)
708
- const expiresAt = tokenExpiresAt(token)
709
- const next: IdpSession = {
710
- ...session,
711
- clientId,
712
- access_token: token.access_token,
713
- id_token: token.id_token ?? session.id_token,
714
- refresh_token: token.refresh_token ?? session.refresh_token,
715
- token_type: token.token_type ?? session.token_type,
716
- scope: token.scope ?? session.scope,
717
- audience,
718
- organizationId: organizationId ?? session.organizationId,
719
- expires_at: expiresAt,
720
- tokens: withCachedToken(session.tokens, token.access_token, expiresAt),
721
- claims: claims ? (claims as Record<string, unknown>) : session.claims,
722
- updatedAt: new Date().toISOString(),
723
- }
724
- // Persist the rotated session BEFORE the audience check. WorkOS refresh tokens
725
- // are single-use: the token request above already exchanged the old one, so the
726
- // new refresh_token must be saved even when the audience doesn't match — else
727
- // the cache is stranded on the now-invalid old token and every subsequent
728
- // refresh dies with "Refresh token already exchanged".
729
- await saveIdpSession(next)
730
- if (audience && !tokenAudienceMatches(next.access_token, audience)) {
731
- const actual = decodeTokenClaims(next.access_token)?.aud
732
- throw new IdpAudienceMismatchError(
733
- audience,
734
- Array.isArray(actual) ? actual.join(', ') : (actual as string | undefined),
735
- )
736
- }
737
- return next
738
- }
739
-
740
- export async function requestClientCredentials(args: {
741
- idp: IdpConfig
742
- clientId?: string
743
- clientSecretEnv?: string
744
- scope?: string
745
- audience?: string
746
- }): Promise<TokenResponse> {
747
- const clientId = requireClientId(args.idp, args.clientId)
748
- const secret = resolveClientSecret(args.idp, args.clientSecretEnv)
749
- if (!secret) throw new Error('Client credentials flow requires a client secret env var')
750
- const params = new URLSearchParams({
751
- grant_type: 'client_credentials',
752
- client_id: clientId,
753
- client_secret: secret,
754
- })
755
- if (args.scope) params.set('scope', args.scope)
756
- if (args.audience) params.set('audience', args.audience)
757
- return postForm(args.idp.metadata.token_endpoint, params)
758
- }
759
-
760
- export async function requestDeviceAuthorization(args: {
761
- idp: IdpConfig
762
- clientId?: string
763
- scope?: string
764
- audience?: string
765
- }): Promise<DeviceAuthorizationResponse> {
766
- const endpoint = args.idp.metadata.device_authorization_endpoint
767
- if (!endpoint)
768
- throw new Error(`IdP "${args.idp.name}" does not advertise device_authorization_endpoint`)
769
- const params = new URLSearchParams({
770
- client_id: requireClientId(args.idp, args.clientId),
771
- })
772
- if (args.scope) params.set('scope', args.scope)
773
- if (args.audience) params.set('audience', args.audience)
774
- const response =
775
- args.idp.client.token_request_format === 'json'
776
- ? await fetch(endpoint, {
777
- method: 'POST',
778
- headers: { 'Content-Type': 'application/json' },
779
- body: JSON.stringify(Object.fromEntries(params)),
780
- })
781
- : await fetch(endpoint, {
782
- method: 'POST',
783
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
784
- body: params,
785
- })
786
- const body = (await response.json()) as DeviceAuthorizationResponse & {
787
- error?: string
788
- error_description?: string
789
- }
790
- if (!response.ok || body.error) {
791
- throw new Error(
792
- body.error_description ??
793
- body.error ??
794
- `Device authorization failed: HTTP ${response.status}`,
795
- )
796
- }
797
- return body
798
- }
799
-
800
- export async function pollDeviceToken(args: {
801
- idp: IdpConfig
802
- deviceCode: string
803
- clientId?: string
804
- clientSecretEnv?: string
805
- intervalSec?: number
806
- expiresInSec: number
807
- }): Promise<TokenResponse> {
808
- const clientId = requireClientId(args.idp, args.clientId)
809
- const secret = resolveClientSecret(args.idp, args.clientSecretEnv)
810
- let intervalMs = Math.max(args.intervalSec ?? 5, 1) * 1000
811
- const deadline = Date.now() + args.expiresInSec * 1000
812
- while (Date.now() < deadline) {
813
- await new Promise((r) => setTimeout(r, intervalMs))
814
- const params = new URLSearchParams({
815
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
816
- device_code: args.deviceCode,
817
- client_id: clientId,
818
- })
819
- if (secret) params.set('client_secret', secret)
820
- const response =
821
- args.idp.client.token_request_format === 'json'
822
- ? await fetch(args.idp.metadata.token_endpoint, {
823
- method: 'POST',
824
- headers: { 'Content-Type': 'application/json' },
825
- body: JSON.stringify(Object.fromEntries(params)),
826
- })
827
- : await fetch(args.idp.metadata.token_endpoint, {
828
- method: 'POST',
829
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
830
- body: params,
831
- })
832
- const body = (await response.json()) as TokenResponse
833
- const token = normalizeTokenResponse(body)
834
- if (response.ok && token.access_token) return token
835
- if (body.error === 'authorization_pending') continue
836
- if (body.error === 'slow_down') {
837
- intervalMs += 5_000
838
- continue
839
- }
840
- throw new Error(
841
- body.error_description ??
842
- body.error ??
843
- `Device token request failed: HTTP ${response.status}`,
844
- )
845
- }
846
- throw new Error('Device authorization expired before completion')
847
- }
848
-
849
- export async function exchangeAuthorizationCode(args: {
850
- idp: IdpConfig
851
- code: string
852
- redirectUri: string
853
- codeVerifier?: string
854
- clientId?: string
855
- clientSecretEnv?: string
856
- }): Promise<TokenResponse> {
857
- const params = new URLSearchParams({
858
- grant_type: 'authorization_code',
859
- code: args.code,
860
- redirect_uri: args.redirectUri,
861
- client_id: requireClientId(args.idp, args.clientId),
862
- })
863
- if (args.codeVerifier) params.set('code_verifier', args.codeVerifier)
864
- const secret = resolveClientSecret(args.idp, args.clientSecretEnv)
865
- if (secret) params.set('client_secret', secret)
866
- return postForm(args.idp.metadata.token_endpoint, params)
867
- }
868
-
869
- export type WorkosApplication = {
870
- id: string
871
- client_id?: string
872
- name?: string
873
- application_type?: 'oauth' | 'm2m'
874
- scopes?: string[]
875
- redirect_uris?: Array<{ uri?: string; default?: boolean }>
876
- uses_pkce?: boolean
877
- }
878
-
879
- export async function fetchWorkosApplication(args: {
880
- apiKeyEnv: string
881
- app: string
882
- }): Promise<WorkosApplication> {
883
- const apiKey = process.env[args.apiKeyEnv]
884
- if (!apiKey) throw new Error(`WorkOS API key env var ${args.apiKeyEnv} is not set`)
885
- const response = await fetch(
886
- `https://api.workos.com/connect/applications/${encodeURIComponent(args.app)}`,
887
- {
888
- headers: { Authorization: `Bearer ${apiKey}` },
889
- },
890
- )
891
- const body = (await response.json()) as {
892
- error?: string
893
- message?: string
894
- connect_application?: WorkosApplication
895
- } & WorkosApplication
896
- if (!response.ok) {
897
- throw new Error(
898
- body.message ?? body.error ?? `WorkOS application fetch failed: HTTP ${response.status}`,
899
- )
900
- }
901
- return body.connect_application ?? body
902
- }
903
-
904
- function normalizeIssuer(value: string): string {
905
- return value.replace(/\/+$/, '')
906
- }