@astrale-os/cli 1.0.0-beta.8 → 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 (599) 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 -93172
  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/instance/model.d.ts +0 -39
  11. package/dist/types/connect-core.d.ts +0 -22
  12. package/dist/types/connection/auth.d.ts +0 -36
  13. package/dist/types/errors.d.ts +0 -23
  14. package/dist/types/identity/registry.d.ts +0 -25
  15. package/dist/types/keys/algorithm.d.ts +0 -6
  16. package/dist/types/keys/credential.d.ts +0 -21
  17. package/dist/types/keys/index.d.ts +0 -4
  18. package/dist/types/keys/pair.d.ts +0 -34
  19. package/dist/types/lib/admin-target.d.ts +0 -78
  20. package/dist/types/lib/ca-fetch.d.ts +0 -2
  21. package/dist/types/lib/config.d.ts +0 -71
  22. package/dist/types/lib/failure-debug.d.ts +0 -1
  23. package/dist/types/lib/format.d.ts +0 -1
  24. package/dist/types/lib/idp-session.d.ts +0 -33
  25. package/dist/types/lib/idp.d.ts +0 -404
  26. package/dist/types/lib/instance-target.d.ts +0 -38
  27. package/dist/types/lib/instance.d.ts +0 -196
  28. package/dist/types/lib/invocation.d.ts +0 -3
  29. package/dist/types/lib/log.d.ts +0 -33
  30. package/dist/types/lib/login-flow.d.ts +0 -49
  31. package/dist/types/lib/meta.d.ts +0 -36
  32. package/dist/types/lib/output.d.ts +0 -87
  33. package/dist/types/lib/proc.d.ts +0 -43
  34. package/dist/types/lib/table.d.ts +0 -18
  35. package/dist/types/lib/update.d.ts +0 -131
  36. package/dist/types/lib/validation.d.ts +0 -11
  37. package/dist/types/paths/index.d.ts +0 -2
  38. package/dist/types/state/exchange-credentials.d.ts +0 -25
  39. package/dist/types/state/files.d.ts +0 -9
  40. package/dist/types/state/identities.d.ts +0 -42
  41. package/dist/types/state/index.d.ts +0 -8
  42. package/dist/types/state/paths.d.ts +0 -32
  43. package/src/__tests__/fixtures/publication.ts +0 -20
  44. package/src/admin/.spec/api.d.ts +0 -3
  45. package/src/admin/.spec/architecture.md +0 -15
  46. package/src/admin/.spec/icon.svg +0 -3
  47. package/src/admin/.spec/layout.ts +0 -6
  48. package/src/admin/__tests__/binding.test.ts +0 -31
  49. package/src/admin/__tests__/fixture.ts +0 -101
  50. package/src/admin/binding.ts +0 -98
  51. package/src/admin/catalog/.spec/api.d.ts +0 -65
  52. package/src/admin/catalog/.spec/architecture.md +0 -6
  53. package/src/admin/catalog/.spec/icon.svg +0 -3
  54. package/src/admin/catalog/.spec/layout.ts +0 -6
  55. package/src/admin/catalog/__tests__/client.test.ts +0 -142
  56. package/src/admin/catalog/client.ts +0 -218
  57. package/src/admin/catalog/index.ts +0 -13
  58. package/src/admin/catalog/model.ts +0 -41
  59. package/src/admin/catalog/tsconfig.json +0 -8
  60. package/src/admin/graph/.spec/api.d.ts +0 -22
  61. package/src/admin/graph/.spec/architecture.md +0 -5
  62. package/src/admin/graph/.spec/icon.svg +0 -3
  63. package/src/admin/graph/.spec/layout.ts +0 -3
  64. package/src/admin/graph/index.ts +0 -6
  65. package/src/admin/graph/nodes.ts +0 -56
  66. package/src/admin/index.ts +0 -2
  67. package/src/admin/instance/.spec/api.d.ts +0 -66
  68. package/src/admin/instance/.spec/architecture.md +0 -10
  69. package/src/admin/instance/.spec/icon.svg +0 -3
  70. package/src/admin/instance/.spec/layout.ts +0 -6
  71. package/src/admin/instance/__tests__/client.test.ts +0 -266
  72. package/src/admin/instance/client.ts +0 -290
  73. package/src/admin/instance/index.ts +0 -16
  74. package/src/admin/instance/model.ts +0 -66
  75. package/src/admin/instance/tsconfig.json +0 -8
  76. package/src/commands/__tests__/admin-instance.test.ts +0 -88
  77. package/src/commands/__tests__/auth-login.test.ts +0 -231
  78. package/src/commands/__tests__/auth-token.test.ts +0 -223
  79. package/src/commands/__tests__/call-describe.test.ts +0 -80
  80. package/src/commands/__tests__/call.test.ts +0 -29
  81. package/src/commands/__tests__/domain-install-operation.test.ts +0 -126
  82. package/src/commands/__tests__/domain-install-owned.test.ts +0 -191
  83. package/src/commands/__tests__/domain-list.test.ts +0 -133
  84. package/src/commands/__tests__/domain-uninstall.test.ts +0 -53
  85. package/src/commands/__tests__/install-direct.test.ts +0 -21
  86. package/src/commands/__tests__/install-identity-override.test.ts +0 -76
  87. package/src/commands/__tests__/instance-bookmark.test.ts +0 -166
  88. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  89. package/src/commands/__tests__/instance-list-admin.test.ts +0 -26
  90. package/src/commands/__tests__/instance-list-rows.test.ts +0 -64
  91. package/src/commands/__tests__/instance-use.test.ts +0 -67
  92. package/src/commands/__tests__/introspect-parse.test.ts +0 -21
  93. package/src/commands/__tests__/logs.test.ts +0 -97
  94. package/src/commands/__tests__/read-commands.test.ts +0 -294
  95. package/src/commands/__tests__/setup-plan.test.ts +0 -61
  96. package/src/commands/__tests__/studio-descriptor.test.ts +0 -22
  97. package/src/commands/__tests__/token-ttl.test.ts +0 -21
  98. package/src/commands/__tests__/update.test.ts +0 -95
  99. package/src/commands/__tests__/view-build.test.ts +0 -58
  100. package/src/commands/__tests__/view.test.ts +0 -149
  101. package/src/commands/admin/status.ts +0 -61
  102. package/src/commands/admin/use.ts +0 -100
  103. package/src/commands/auth/login.ts +0 -82
  104. package/src/commands/auth/logout.ts +0 -52
  105. package/src/commands/auth/status.ts +0 -86
  106. package/src/commands/auth/token.ts +0 -174
  107. package/src/commands/browser.ts +0 -207
  108. package/src/commands/call-describe.ts +0 -123
  109. package/src/commands/call.ts +0 -205
  110. package/src/commands/domain/install.ts +0 -548
  111. package/src/commands/domain/list.ts +0 -155
  112. package/src/commands/domain/publish.ts +0 -133
  113. package/src/commands/domain/uninstall.ts +0 -128
  114. package/src/commands/get.ts +0 -69
  115. package/src/commands/identity/__tests__/register.test.ts +0 -93
  116. package/src/commands/identity/create.ts +0 -35
  117. package/src/commands/identity/delete.ts +0 -24
  118. package/src/commands/identity/export.ts +0 -46
  119. package/src/commands/identity/import.ts +0 -61
  120. package/src/commands/identity/list.ts +0 -56
  121. package/src/commands/identity/register.ts +0 -196
  122. package/src/commands/identity/sync.ts +0 -38
  123. package/src/commands/identity/unsync.ts +0 -34
  124. package/src/commands/identity/use.ts +0 -24
  125. package/src/commands/identity/whoami.ts +0 -34
  126. package/src/commands/idp/add.ts +0 -150
  127. package/src/commands/idp/list.ts +0 -57
  128. package/src/commands/idp/refresh.ts +0 -38
  129. package/src/commands/idp/remove.ts +0 -36
  130. package/src/commands/idp/show.ts +0 -29
  131. package/src/commands/instance/active.ts +0 -73
  132. package/src/commands/instance/bookmark.ts +0 -101
  133. package/src/commands/instance/create.ts +0 -69
  134. package/src/commands/instance/delete.ts +0 -68
  135. package/src/commands/instance/forget.ts +0 -26
  136. package/src/commands/instance/list.ts +0 -197
  137. package/src/commands/instance/status.ts +0 -38
  138. package/src/commands/instance/use.ts +0 -259
  139. package/src/commands/introspect.ts +0 -110
  140. package/src/commands/logs.ts +0 -283
  141. package/src/commands/mutate.ts +0 -122
  142. package/src/commands/query.ts +0 -136
  143. package/src/commands/session/analyze.ts +0 -50
  144. package/src/commands/session/list.ts +0 -36
  145. package/src/commands/setup.ts +0 -54
  146. package/src/commands/status.ts +0 -60
  147. package/src/commands/studio.ts +0 -434
  148. package/src/commands/token.ts +0 -107
  149. package/src/commands/update.ts +0 -334
  150. package/src/commands/use.ts +0 -86
  151. package/src/commands/view-serve.ts +0 -26
  152. package/src/commands/view.ts +0 -614
  153. package/src/connect-core.test.ts +0 -38
  154. package/src/connect-core.ts +0 -42
  155. package/src/connection/.spec/api.d.ts +0 -110
  156. package/src/connection/.spec/architecture.md +0 -47
  157. package/src/connection/.spec/capabilities/connection.ts +0 -13
  158. package/src/connection/.spec/examples/call.ts +0 -7
  159. package/src/connection/.spec/flows/command.ts +0 -20
  160. package/src/connection/.spec/flows/session.ts +0 -61
  161. package/src/connection/.spec/laws/connection.ts +0 -205
  162. package/src/connection/.spec/layout.ts +0 -21
  163. package/src/connection/__tests__/auth.test.ts +0 -128
  164. package/src/connection/__tests__/ca-fetch.test.ts +0 -60
  165. package/src/connection/__tests__/call.test.ts +0 -17
  166. package/src/connection/__tests__/credential.test.ts +0 -119
  167. package/src/connection/__tests__/errors.test.ts +0 -577
  168. package/src/connection/__tests__/exchange.test.ts +0 -295
  169. package/src/connection/__tests__/failure-fixtures.ts +0 -39
  170. package/src/connection/__tests__/failure-safety.test.ts +0 -75
  171. package/src/connection/__tests__/fixtures/localhost-cert.pem +0 -19
  172. package/src/connection/__tests__/fixtures/localhost-key.base64 +0 -1
  173. package/src/connection/__tests__/managed.test.ts +0 -39
  174. package/src/connection/__tests__/reasons.test.ts +0 -78
  175. package/src/connection/__tests__/self.test.ts +0 -71
  176. package/src/connection/__tests__/session.test.ts +0 -140
  177. package/src/connection/__tests__/target.test.ts +0 -93
  178. package/src/connection/auth.ts +0 -236
  179. package/src/connection/call.ts +0 -7
  180. package/src/connection/command.ts +0 -67
  181. package/src/connection/credential.ts +0 -117
  182. package/src/connection/errors.ts +0 -1
  183. package/src/connection/exchange.ts +0 -311
  184. package/src/connection/failure/classify.ts +0 -110
  185. package/src/connection/failure/index.ts +0 -18
  186. package/src/connection/failure/model.ts +0 -28
  187. package/src/connection/failure/render.ts +0 -116
  188. package/src/connection/index.ts +0 -8
  189. package/src/connection/reasons.ts +0 -209
  190. package/src/connection/self.ts +0 -138
  191. package/src/connection/session.ts +0 -185
  192. package/src/connection/target.ts +0 -112
  193. package/src/connection/tsconfig.json +0 -6
  194. package/src/errors.ts +0 -66
  195. package/src/graph/.spec/api.d.ts +0 -41
  196. package/src/graph/.spec/laws/documents.ts +0 -24
  197. package/src/graph/.spec/laws/projection.ts +0 -13
  198. package/src/graph/.spec/layout.ts +0 -14
  199. package/src/graph/__tests__/mutation.test.ts +0 -51
  200. package/src/graph/__tests__/projection.test.ts +0 -22
  201. package/src/graph/__tests__/query.test.ts +0 -173
  202. package/src/graph/class.ts +0 -30
  203. package/src/graph/index.ts +0 -4
  204. package/src/graph/mutation.ts +0 -46
  205. package/src/graph/projection.ts +0 -21
  206. package/src/graph/query.ts +0 -97
  207. package/src/graph/tsconfig.json +0 -6
  208. package/src/identity/.history/ard/bootstrap-root-transfer.md +0 -57
  209. package/src/identity/.history/ard/domain-mediated-registration.md +0 -36
  210. package/src/identity/.spec/api.d.ts +0 -124
  211. package/src/identity/.spec/architecture.md +0 -33
  212. package/src/identity/.spec/capabilities/identity.ts +0 -7
  213. package/src/identity/.spec/flows/bootstrap-root.ts +0 -79
  214. package/src/identity/.spec/flows/domain-mediated-registration.ts +0 -51
  215. package/src/identity/.spec/flows/import.ts +0 -29
  216. package/src/identity/.spec/laws/identity.ts +0 -56
  217. package/src/identity/.spec/layout.ts +0 -13
  218. package/src/identity/.spec/schemas/identity-export-v1.schema.json +0 -25
  219. package/src/identity/__tests__/fixtures/registry-journey.ts +0 -53
  220. package/src/identity/__tests__/registration.test.ts +0 -64
  221. package/src/identity/__tests__/registry.test.ts +0 -70
  222. package/src/identity/__tests__/transfer.test.ts +0 -198
  223. package/src/identity/index.ts +0 -23
  224. package/src/identity/registration.ts +0 -72
  225. package/src/identity/registry.ts +0 -179
  226. package/src/identity/transfer.ts +0 -187
  227. package/src/identity/tsconfig.json +0 -6
  228. package/src/index.ts +0 -1
  229. package/src/keys/.spec/api.d.ts +0 -74
  230. package/src/keys/.spec/architecture.md +0 -13
  231. package/src/keys/.spec/laws/keys.ts +0 -43
  232. package/src/keys/.spec/layout.ts +0 -6
  233. package/src/keys/__tests__/algorithm.test.ts +0 -39
  234. package/src/keys/__tests__/keys.test.ts +0 -168
  235. package/src/keys/algorithm.ts +0 -33
  236. package/src/keys/credential.ts +0 -112
  237. package/src/keys/index.ts +0 -14
  238. package/src/keys/pair.ts +0 -219
  239. package/src/keys/tsconfig.json +0 -6
  240. package/src/lib/__tests__/admin-target.test.ts +0 -184
  241. package/src/lib/__tests__/binary.test.ts +0 -55
  242. package/src/lib/__tests__/command-dx.test.ts +0 -102
  243. package/src/lib/__tests__/concurrency.test.ts +0 -62
  244. package/src/lib/__tests__/config.test.ts +0 -54
  245. package/src/lib/__tests__/design.test.ts +0 -99
  246. package/src/lib/__tests__/domain-publication.test.ts +0 -133
  247. package/src/lib/__tests__/format.test.ts +0 -22
  248. package/src/lib/__tests__/idp-session.driver.ts +0 -53
  249. package/src/lib/__tests__/idp-session.test.ts +0 -379
  250. package/src/lib/__tests__/idp.test.ts +0 -415
  251. package/src/lib/__tests__/instance-candidates.test.ts +0 -148
  252. package/src/lib/__tests__/instance-target.test.ts +0 -212
  253. package/src/lib/__tests__/instance.test.ts +0 -192
  254. package/src/lib/__tests__/local-status.test.ts +0 -202
  255. package/src/lib/__tests__/log-errors.test.ts +0 -64
  256. package/src/lib/__tests__/log.test.ts +0 -31
  257. package/src/lib/__tests__/meta.test.ts +0 -55
  258. package/src/lib/__tests__/output.test.ts +0 -162
  259. package/src/lib/__tests__/panel.test.ts +0 -40
  260. package/src/lib/__tests__/port.test.ts +0 -44
  261. package/src/lib/__tests__/prompt.test.ts +0 -25
  262. package/src/lib/__tests__/sdk-deps.test.ts +0 -68
  263. package/src/lib/__tests__/self.test.ts +0 -50
  264. package/src/lib/__tests__/studio-server-deps.test.ts +0 -111
  265. package/src/lib/__tests__/table.test.ts +0 -53
  266. package/src/lib/__tests__/update.test.ts +0 -351
  267. package/src/lib/__tests__/use-target.test.ts +0 -56
  268. package/src/lib/__tests__/validation.test.ts +0 -34
  269. package/src/lib/__tests__/view-assets.test.ts +0 -146
  270. package/src/lib/__tests__/view-open-intent.test.ts +0 -280
  271. package/src/lib/__tests__/view-port-allocation.test.ts +0 -82
  272. package/src/lib/__tests__/view-server.test.ts +0 -68
  273. package/src/lib/__tests__/view-session.test.ts +0 -99
  274. package/src/lib/__tests__/view-snapshot.test.ts +0 -77
  275. package/src/lib/admin-domain.ts +0 -43
  276. package/src/lib/admin-instance.ts +0 -50
  277. package/src/lib/admin-target.ts +0 -290
  278. package/src/lib/binary.ts +0 -110
  279. package/src/lib/browser.ts +0 -150
  280. package/src/lib/ca-fetch.ts +0 -133
  281. package/src/lib/command-dx.ts +0 -188
  282. package/src/lib/concurrency.ts +0 -31
  283. package/src/lib/config.ts +0 -46
  284. package/src/lib/domain-publication.ts +0 -102
  285. package/src/lib/failure-debug.ts +0 -26
  286. package/src/lib/format.ts +0 -4
  287. package/src/lib/idp-session.ts +0 -134
  288. package/src/lib/idp.ts +0 -906
  289. package/src/lib/instance-candidates.ts +0 -49
  290. package/src/lib/instance-target.ts +0 -197
  291. package/src/lib/instance.ts +0 -463
  292. package/src/lib/invocation.ts +0 -11
  293. package/src/lib/local-status.ts +0 -152
  294. package/src/lib/log.ts +0 -143
  295. package/src/lib/login-flow.ts +0 -201
  296. package/src/lib/meta.ts +0 -90
  297. package/src/lib/output.ts +0 -238
  298. package/src/lib/panel.ts +0 -61
  299. package/src/lib/port.ts +0 -41
  300. package/src/lib/proc.ts +0 -82
  301. package/src/lib/prompt.ts +0 -136
  302. package/src/lib/provision-instance.ts +0 -162
  303. package/src/lib/sdk-deps.ts +0 -104
  304. package/src/lib/self.ts +0 -22
  305. package/src/lib/skills.ts +0 -171
  306. package/src/lib/table.ts +0 -62
  307. package/src/lib/update.ts +0 -409
  308. package/src/lib/use-target.ts +0 -24
  309. package/src/lib/validation.ts +0 -59
  310. package/src/lib/view/assets.ts +0 -78
  311. package/src/lib/view/open-intent.ts +0 -67
  312. package/src/lib/view/port-allocation.ts +0 -19
  313. package/src/lib/view/resolve.ts +0 -111
  314. package/src/lib/view/server.ts +0 -244
  315. package/src/lib/view/session.ts +0 -152
  316. package/src/lib/view/snapshot.ts +0 -101
  317. package/src/paths/.spec/api.d.ts +0 -13
  318. package/src/paths/.spec/architecture.md +0 -5
  319. package/src/paths/.spec/layout.ts +0 -3
  320. package/src/paths/index.ts +0 -13
  321. package/src/program/.spec/api.d.ts +0 -42
  322. package/src/program/.spec/architecture.md +0 -18
  323. package/src/program/.spec/laws/program.ts +0 -29
  324. package/src/program/.spec/layout.ts +0 -14
  325. package/src/program/__tests__/program.test.ts +0 -362
  326. package/src/program/build.ts +0 -183
  327. package/src/program/command.ts +0 -42
  328. package/src/program/index.ts +0 -2
  329. package/src/program/options.ts +0 -41
  330. package/src/program/registry.ts +0 -63
  331. package/src/program/tsconfig.json +0 -6
  332. package/src/setup/__tests__/instance-step.test.ts +0 -239
  333. package/src/setup/__tests__/util.test.ts +0 -29
  334. package/src/setup/engine.ts +0 -83
  335. package/src/setup/render.ts +0 -107
  336. package/src/setup/steps/admin.ts +0 -93
  337. package/src/setup/steps/agent-browser.ts +0 -81
  338. package/src/setup/steps/auth.ts +0 -54
  339. package/src/setup/steps/domain.ts +0 -68
  340. package/src/setup/steps/index.ts +0 -18
  341. package/src/setup/steps/instance.ts +0 -199
  342. package/src/setup/steps/skills-bridge.ts +0 -70
  343. package/src/setup/steps/skills.ts +0 -59
  344. package/src/setup/types.ts +0 -61
  345. package/src/setup/util.ts +0 -34
  346. package/src/state/.spec/api.d.ts +0 -133
  347. package/src/state/.spec/architecture.md +0 -31
  348. package/src/state/.spec/capabilities/state.ts +0 -7
  349. package/src/state/.spec/flows/identity-update.ts +0 -22
  350. package/src/state/.spec/laws/state.ts +0 -73
  351. package/src/state/.spec/layout.ts +0 -14
  352. package/src/state/__tests__/exchange-credentials.test.ts +0 -188
  353. package/src/state/__tests__/files.test.ts +0 -113
  354. package/src/state/__tests__/fixtures/identity-transition.ts +0 -37
  355. package/src/state/__tests__/identities.test.ts +0 -142
  356. package/src/state/__tests__/paths.test.ts +0 -27
  357. package/src/state/exchange-credentials.ts +0 -219
  358. package/src/state/files.ts +0 -129
  359. package/src/state/identities.ts +0 -229
  360. package/src/state/index.ts +0 -29
  361. package/src/state/paths.ts +0 -61
  362. package/src/state/tsconfig.json +0 -6
  363. package/src/telemetry/__tests__/gate.test.ts +0 -63
  364. package/src/telemetry/__tests__/recorder.test.ts +0 -110
  365. package/src/telemetry/__tests__/redact.test.ts +0 -79
  366. package/src/telemetry/__tests__/session.test.ts +0 -166
  367. package/src/telemetry/__tests__/trigger.test.ts +0 -49
  368. package/src/telemetry/adapters/__tests__/claude-code.test.ts +0 -89
  369. package/src/telemetry/adapters/__tests__/codex.test.ts +0 -138
  370. package/src/telemetry/adapters/__tests__/index.test.ts +0 -88
  371. package/src/telemetry/adapters/claude-code.ts +0 -90
  372. package/src/telemetry/adapters/codex.ts +0 -160
  373. package/src/telemetry/adapters/index.ts +0 -45
  374. package/src/telemetry/adapters/types.ts +0 -21
  375. package/src/telemetry/analyze.ts +0 -227
  376. package/src/telemetry/gate.ts +0 -79
  377. package/src/telemetry/recorder.ts +0 -57
  378. package/src/telemetry/redact.ts +0 -53
  379. package/src/telemetry/session.ts +0 -88
  380. package/src/telemetry/settings.ts +0 -26
  381. package/src/telemetry/store.ts +0 -91
  382. package/src/telemetry/trigger.ts +0 -119
  383. package/src/telemetry/types.ts +0 -64
  384. package/src/test-utils.ts +0 -18
  385. package/studio/client/dist/assets/elk-api-Di4OXGNH.js +0 -1
  386. package/studio/client/dist/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  387. package/studio/client/dist/assets/index-BLm6J11H.js +0 -81
  388. package/studio/client/dist/assets/index-BiGR8Oo9.css +0 -1
  389. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  390. package/studio/client/dist/assets/index-DTjvkOUX.js +0 -8
  391. package/studio/client/dist/index.html +0 -13
  392. package/studio/package.json +0 -65
  393. package/studio/server/agent/ask.test.ts +0 -74
  394. package/studio/server/agent/ask.ts +0 -71
  395. package/studio/server/agent/bridge/client.test.ts +0 -49
  396. package/studio/server/agent/bridge/client.ts +0 -37
  397. package/studio/server/agent/bridge/grant.test.ts +0 -62
  398. package/studio/server/agent/bridge/grant.ts +0 -84
  399. package/studio/server/agent/bridge/routes.test.ts +0 -151
  400. package/studio/server/agent/bridge/routes.ts +0 -148
  401. package/studio/server/agent/bridge/stdio.ts +0 -195
  402. package/studio/server/agent/conversation.test.ts +0 -89
  403. package/studio/server/agent/conversation.ts +0 -158
  404. package/studio/server/agent/harness/adapter.ts +0 -171
  405. package/studio/server/agent/harness/claude/adapter.test.ts +0 -348
  406. package/studio/server/agent/harness/claude/adapter.ts +0 -71
  407. package/studio/server/agent/harness/claude/ask.ts +0 -114
  408. package/studio/server/agent/harness/claude/capabilities.ts +0 -27
  409. package/studio/server/agent/harness/claude/command.ts +0 -63
  410. package/studio/server/agent/harness/claude/events.ts +0 -215
  411. package/studio/server/agent/harness/claude/loadout.ts +0 -132
  412. package/studio/server/agent/harness/claude/mcp.test.ts +0 -36
  413. package/studio/server/agent/harness/claude/mcp.ts +0 -41
  414. package/studio/server/agent/harness/claude/skills.ts +0 -43
  415. package/studio/server/agent/harness/codex/adapter.test.ts +0 -269
  416. package/studio/server/agent/harness/codex/adapter.ts +0 -116
  417. package/studio/server/agent/harness/codex/ask.test.ts +0 -176
  418. package/studio/server/agent/harness/codex/ask.ts +0 -181
  419. package/studio/server/agent/harness/codex/command.test.ts +0 -69
  420. package/studio/server/agent/harness/codex/command.ts +0 -43
  421. package/studio/server/agent/harness/codex/events.test.ts +0 -94
  422. package/studio/server/agent/harness/codex/events.ts +0 -132
  423. package/studio/server/agent/harness/codex/exec.ts +0 -113
  424. package/studio/server/agent/harness/codex/loadout.ts +0 -60
  425. package/studio/server/agent/harness/codex/mcp.test.ts +0 -32
  426. package/studio/server/agent/harness/codex/mcp.ts +0 -27
  427. package/studio/server/agent/harness/codex/models.test.ts +0 -167
  428. package/studio/server/agent/harness/codex/models.ts +0 -211
  429. package/studio/server/agent/harness/codex/skills.ts +0 -33
  430. package/studio/server/agent/harness/gateway/config.test.ts +0 -98
  431. package/studio/server/agent/harness/gateway/config.ts +0 -214
  432. package/studio/server/agent/harness/gateway/token.test.ts +0 -133
  433. package/studio/server/agent/harness/gateway/token.ts +0 -166
  434. package/studio/server/agent/harness/mock/adapter.ts +0 -190
  435. package/studio/server/agent/harness/mock/domain-edit.ts +0 -41
  436. package/studio/server/agent/harness/process.test.ts +0 -46
  437. package/studio/server/agent/harness/process.ts +0 -104
  438. package/studio/server/agent/harness/registry.ts +0 -37
  439. package/studio/server/agent/harness/selection.test.ts +0 -75
  440. package/studio/server/agent/harness/selection.ts +0 -85
  441. package/studio/server/agent/harness/skills.test.ts +0 -95
  442. package/studio/server/agent/harness/skills.ts +0 -100
  443. package/studio/server/agent/layout.test.ts +0 -95
  444. package/studio/server/agent/notify.ts +0 -12
  445. package/studio/server/agent/prompts/anchors.test.ts +0 -70
  446. package/studio/server/agent/prompts/anchors.ts +0 -153
  447. package/studio/server/agent/prompts/ask.ts +0 -34
  448. package/studio/server/agent/prompts/system.test.ts +0 -13
  449. package/studio/server/agent/prompts/system.ts +0 -99
  450. package/studio/server/agent/prompts/turn.ts +0 -66
  451. package/studio/server/agent/routes.test.ts +0 -176
  452. package/studio/server/agent/routes.ts +0 -214
  453. package/studio/server/agent/run/completion.ts +0 -193
  454. package/studio/server/agent/run/coordinator.test.ts +0 -337
  455. package/studio/server/agent/run/coordinator.ts +0 -104
  456. package/studio/server/agent/run/live-state.ts +0 -73
  457. package/studio/server/agent/run/preparation.ts +0 -163
  458. package/studio/server/agent/run/transcript.test.ts +0 -81
  459. package/studio/server/agent/run/transcript.ts +0 -196
  460. package/studio/server/agent/run/usage.test.ts +0 -70
  461. package/studio/server/agent/run/usage.ts +0 -62
  462. package/studio/server/agent/stream.ts +0 -37
  463. package/studio/server/agent/telemetry.ts +0 -13
  464. package/studio/server/api/canvas.ts +0 -43
  465. package/studio/server/api/comments.ts +0 -85
  466. package/studio/server/api/context.ts +0 -61
  467. package/studio/server/api/deployment.ts +0 -39
  468. package/studio/server/api/documents.ts +0 -55
  469. package/studio/server/api/domain.ts +0 -59
  470. package/studio/server/api/http.ts +0 -45
  471. package/studio/server/api/project.ts +0 -57
  472. package/studio/server/api/schema.ts +0 -12
  473. package/studio/server/api/views.ts +0 -57
  474. package/studio/server/api/workspace.ts +0 -60
  475. package/studio/server/api-agent-loadout.test.ts +0 -69
  476. package/studio/server/api.test.ts +0 -147
  477. package/studio/server/api.ts +0 -34
  478. package/studio/server/cache.test.ts +0 -122
  479. package/studio/server/cache.ts +0 -303
  480. package/studio/server/cli-consumers.test.ts +0 -494
  481. package/studio/server/cli.test.ts +0 -88
  482. package/studio/server/cli.ts +0 -240
  483. package/studio/server/client-package.test.ts +0 -147
  484. package/studio/server/client-package.ts +0 -266
  485. package/studio/server/detect.ts +0 -81
  486. package/studio/server/domain.test.ts +0 -77
  487. package/studio/server/domain.ts +0 -124
  488. package/studio/server/environment/dotenv-preview.test.ts +0 -39
  489. package/studio/server/environment/dotenv-preview.ts +0 -27
  490. package/studio/server/environment/files.test.ts +0 -53
  491. package/studio/server/environment/files.ts +0 -120
  492. package/studio/server/handoff/copy.ts +0 -171
  493. package/studio/server/handoff/service.test.ts +0 -22
  494. package/studio/server/handoff/service.ts +0 -62
  495. package/studio/server/index.ts +0 -148
  496. package/studio/server/instances/active.ts +0 -72
  497. package/studio/server/instances/deploy-record.test.ts +0 -31
  498. package/studio/server/instances/deploy-record.ts +0 -37
  499. package/studio/server/instances/deploy.ts +0 -56
  500. package/studio/server/instances/probe.test.ts +0 -67
  501. package/studio/server/instances/probe.ts +0 -67
  502. package/studio/server/instances/status.test.ts +0 -12
  503. package/studio/server/instances/status.ts +0 -49
  504. package/studio/server/introspect/anatomy/client-tree.ts +0 -57
  505. package/studio/server/introspect/anatomy/env-fields.ts +0 -66
  506. package/studio/server/introspect/anatomy/schema-definition.ts +0 -53
  507. package/studio/server/introspect/anatomy/source.ts +0 -181
  508. package/studio/server/introspect/anatomy/views/routes.ts +0 -114
  509. package/studio/server/introspect/anatomy/views.ts +0 -53
  510. package/studio/server/introspect/anatomy-extras.test.ts +0 -265
  511. package/studio/server/introspect/anatomy-extras.ts +0 -10
  512. package/studio/server/introspect/anatomy.test.ts +0 -41
  513. package/studio/server/introspect/anatomy.ts +0 -147
  514. package/studio/server/introspect/bundle.ts +0 -69
  515. package/studio/server/introspect/canonical-schema.test.ts +0 -179
  516. package/studio/server/introspect/canonical-schema.ts +0 -583
  517. package/studio/server/introspect/config-preview.test.ts +0 -32
  518. package/studio/server/introspect/config-preview.ts +0 -119
  519. package/studio/server/introspect/core-extractor.ts +0 -30
  520. package/studio/server/introspect/core.ts +0 -45
  521. package/studio/server/introspect/diff.test.ts +0 -124
  522. package/studio/server/introspect/diff.ts +0 -316
  523. package/studio/server/introspect/extractor.ts +0 -41
  524. package/studio/server/introspect/hash.ts +0 -24
  525. package/studio/server/introspect/overlay-tsmorph.test.ts +0 -146
  526. package/studio/server/introspect/overlay-tsmorph.ts +0 -9
  527. package/studio/server/introspect/overlay.test.ts +0 -44
  528. package/studio/server/introspect/overlay.ts +0 -40
  529. package/studio/server/introspect/revision.test.ts +0 -54
  530. package/studio/server/introspect/revision.ts +0 -49
  531. package/studio/server/introspect/runtime.test.ts +0 -157
  532. package/studio/server/introspect/runtime.ts +0 -140
  533. package/studio/server/introspect/schema-ir-json.test.ts +0 -70
  534. package/studio/server/introspect/schema-ir-json.ts +0 -151
  535. package/studio/server/introspect/schema-refs.test.ts +0 -55
  536. package/studio/server/introspect/schema-refs.ts +0 -32
  537. package/studio/server/introspect/source-overlay/annotations.ts +0 -14
  538. package/studio/server/introspect/source-overlay/handlers.ts +0 -161
  539. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -46
  540. package/studio/server/introspect/source-overlay/project.ts +0 -248
  541. package/studio/server/introspect/source-overlay/spans.ts +0 -330
  542. package/studio/server/json.ts +0 -46
  543. package/studio/server/lifecycle.ts +0 -42
  544. package/studio/server/sse.test.ts +0 -26
  545. package/studio/server/sse.ts +0 -60
  546. package/studio/server/state/baseline.test.ts +0 -267
  547. package/studio/server/state/baseline.ts +0 -354
  548. package/studio/server/state/comments.test.ts +0 -94
  549. package/studio/server/state/comments.ts +0 -484
  550. package/studio/server/state/context.ts +0 -199
  551. package/studio/server/state/documents.ts +0 -111
  552. package/studio/server/state/integrations.ts +0 -81
  553. package/studio/server/state/layout.test.ts +0 -34
  554. package/studio/server/state/layout.ts +0 -82
  555. package/studio/server/state/settings.test.ts +0 -78
  556. package/studio/server/state/settings.ts +0 -73
  557. package/studio/server/state/store.test.ts +0 -122
  558. package/studio/server/state/store.ts +0 -146
  559. package/studio/server/state/visibility.ts +0 -48
  560. package/studio/server/views/model.test.ts +0 -57
  561. package/studio/server/views/model.ts +0 -66
  562. package/studio/server/views/runtime.ts +0 -40
  563. package/studio/server/views/selection-repository.test.ts +0 -31
  564. package/studio/server/views/selection-repository.ts +0 -60
  565. package/studio/server/views/session.test.ts +0 -73
  566. package/studio/server/views/session.ts +0 -166
  567. package/studio/server/views/target.test.ts +0 -78
  568. package/studio/server/views/target.ts +0 -222
  569. package/studio/server/watch.test.ts +0 -36
  570. package/studio/server/watch.ts +0 -93
  571. package/studio/server/workspace/catalog.test.ts +0 -17
  572. package/studio/server/workspace/catalog.ts +0 -43
  573. package/studio/server/workspace/create.test.ts +0 -37
  574. package/studio/server/workspace/create.ts +0 -162
  575. package/studio/server/workspace/git.ts +0 -75
  576. package/studio/server/workspace/updates.ts +0 -83
  577. package/studio/server/workspace-state.ts +0 -26
  578. package/studio/server/workspace-watch.ts +0 -106
  579. package/studio/shared/agent-effort.test.ts +0 -12
  580. package/studio/shared/agent-effort.ts +0 -15
  581. package/studio/shared/agent-models.test.ts +0 -9
  582. package/studio/shared/agent-models.ts +0 -14
  583. package/studio/shared/contracts/README.md +0 -16
  584. package/studio/shared/contracts/agent.ts +0 -270
  585. package/studio/shared/contracts/runtime.ts +0 -50
  586. package/studio/shared/contracts/schema.ts +0 -393
  587. package/studio/shared/contracts/surface.test.ts +0 -317
  588. package/studio/shared/contracts/workspace.ts +0 -265
  589. package/studio/shared/layout.test.ts +0 -116
  590. package/studio/shared/schema/identity.test.ts +0 -34
  591. package/studio/shared/schema/identity.ts +0 -68
  592. package/studio/shared/settings-values.test.ts +0 -18
  593. package/studio/shared/settings-values.ts +0 -20
  594. package/studio/shared/types.ts +0 -14
  595. package/studio/tsconfig.json +0 -23
  596. package/tsconfig.json +0 -14
  597. package/viewer/dist/index.html +0 -93
  598. package/viewer/dist/main.js +0 -76
  599. 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
- }