@undefineds.co/xpod 0.4.3 → 0.4.5

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 (223) hide show
  1. package/config/cloud.json +1 -1
  2. package/config/main.json +36 -2
  3. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +3 -0
  4. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
  5. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +2 -1
  6. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +101 -32
  7. package/dist/api/ai-gateway/connect/DeviceCodeProtocol.d.ts +80 -0
  8. package/dist/api/ai-gateway/connect/DeviceCodeProtocol.js +3 -0
  9. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +38 -0
  10. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +63 -0
  11. package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.d.ts +24 -0
  12. package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.js +136 -0
  13. package/dist/api/ai-gateway/connect/OAuthConnectAdapter.d.ts +2 -0
  14. package/dist/api/ai-gateway/connect/OAuthConnectAdapter.js +2 -1
  15. package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.d.ts +17 -13
  16. package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.js +52 -19
  17. package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.d.ts +4 -28
  18. package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.js +7 -58
  19. package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.d.ts +4 -0
  20. package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.js +116 -0
  21. package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +10 -0
  22. package/dist/api/ai-gateway/connect/SessionImportProfiles.js +112 -0
  23. package/dist/api/ai-gateway/connect/index.d.ts +125 -23
  24. package/dist/api/ai-gateway/connect/index.js +1277 -260
  25. package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +4 -1
  26. package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +154 -19
  27. package/dist/api/ai-gateway/providers/DeepSeekRuntimeAdapter.js +10 -6
  28. package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -0
  29. package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +25 -1
  30. package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +24 -0
  31. package/dist/api/ai-gateway/providers/OfferingAuthorization.js +37 -0
  32. package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.d.ts +1 -1
  33. package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.js +5 -3
  34. package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +6 -3
  35. package/dist/api/ai-gateway/providers/ProviderRegistry.js +55 -16
  36. package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.d.ts +2 -0
  37. package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.js +37 -4
  38. package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +7 -0
  39. package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +2 -1
  40. package/dist/api/ai-gateway/routing/ModelRouter.js +3 -1
  41. package/dist/api/container/common.js +30 -40
  42. package/dist/api/container/index.js +6 -2
  43. package/dist/api/container/routes.js +5 -22
  44. package/dist/api/handlers/AiClientConfigurationHandler.js +39 -1
  45. package/dist/api/handlers/AiGatewayManagementHandler.d.ts +3 -0
  46. package/dist/api/handlers/AiGatewayManagementHandler.js +173 -58
  47. package/dist/api/service/AiClientConfigurationService.d.ts +4 -15
  48. package/dist/api/service/AiClientConfigurationService.js +17 -64
  49. package/dist/cli/commands/start.js +2 -0
  50. package/dist/components/components.jsonld +1 -0
  51. package/dist/components/context.jsonld +80 -0
  52. package/dist/http/InternalPodDataHttpHandler.d.ts +3 -0
  53. package/dist/http/InternalPodDataHttpHandler.js +13 -2
  54. package/dist/http/InternalPodDataHttpHandler.jsonld +12 -0
  55. package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +1 -1
  56. package/dist/identity/oidc/RememberedClientPromptFactory.js +5 -2
  57. package/dist/identity/oidc/RememberedConsentHandler.js +1 -1
  58. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +1 -0
  59. package/dist/identity/oidc/ScopedPickWebIdHandler.js +26 -0
  60. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +4 -0
  61. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.d.ts +10 -0
  62. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.js +21 -0
  63. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.jsonld +172 -0
  64. package/dist/index.d.ts +2 -1
  65. package/dist/index.js +4 -2
  66. package/dist/runtime/component-parameter-keys.js +18 -2
  67. package/dist/storage/accessors/MixDataAccessor.js +6 -2
  68. package/dist/storage/rdf/PostgresRdfEngine.js +10 -2
  69. package/dist/storage/rdf/RdfContentTypes.js +4 -0
  70. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +3 -0
  71. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -16
  72. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +1 -3
  73. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +2 -1
  74. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +2 -2
  75. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +4 -1
  76. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +127 -57
  77. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +6 -4
  78. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +436 -83
  79. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +3 -2
  80. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +212 -76
  81. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +6 -4
  82. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +58 -41
  83. package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +4 -1
  84. package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.js +63 -4
  85. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +46 -6
  86. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +143 -14
  87. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +19 -3
  88. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +45 -7
  89. package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.d.ts +7 -1
  90. package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.js +305 -40
  91. package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +383 -50
  92. package/node_modules/@undefineds.co/ai-connections/dist/client-config/json-env-adapter.js +3 -2
  93. package/node_modules/@undefineds.co/ai-connections/dist/client-config/pi.js +12 -3
  94. package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.d.ts +2 -0
  95. package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.js +39 -4
  96. package/node_modules/@undefineds.co/ai-connections/dist/client-config/types.d.ts +8 -1
  97. package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.d.ts +2 -0
  98. package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.js +14 -0
  99. package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +2 -2
  100. package/node_modules/@undefineds.co/ai-connections/dist/controller.js +216 -57
  101. package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +3 -1
  102. package/node_modules/@undefineds.co/ai-connections/dist/index.js +16 -2
  103. package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +6 -1
  104. package/node_modules/@undefineds.co/drizzle-solid/dist/core/execution/ldp-executor.js +27 -6
  105. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +1 -1
  106. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +2 -2
  107. package/node_modules/@undefineds.co/drizzle-solid/dist/core/sparql/builder/update-builder.js +12 -1
  108. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/builder.js +1 -1
  109. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/array.js +8 -0
  110. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/default.js +9 -1
  111. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/inline.js +3 -3
  112. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/execution/ldp-executor.js +27 -6
  113. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +1 -1
  114. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +2 -2
  115. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/builder/update-builder.js +12 -1
  116. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/builder.js +1 -1
  117. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/array.js +8 -0
  118. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/default.js +9 -1
  119. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/inline.js +3 -3
  120. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +31 -0
  121. package/package.json +2 -2
  122. package/static/app/assets/{index-BikOyGPu.js → index-BCZVzMpj.js} +44 -44
  123. package/static/app/assets/inrupt-smoke.js +2 -2
  124. package/static/app/assets/main.css +1 -1
  125. package/static/app/assets/main.js +10 -10
  126. package/static/auth-callback/assets/{AiConfigContext-DrCH6ckh.js → AiConfigContext-DVkh8Kg2.js} +1 -1
  127. package/static/auth-callback/assets/{AiConfigPage-DVrlSSdA.js → AiConfigPage-HWVWpe-P.js} +1 -1
  128. package/static/auth-callback/assets/{DocumentProcessingPanel-_Md-v2R2.js → DocumentProcessingPanel-DDq-mH17.js} +1 -1
  129. package/static/auth-callback/assets/{IndexLifecyclePanel-BbWwe23H.js → IndexLifecyclePanel-Cx4cjrdP.js} +1 -1
  130. package/static/auth-callback/assets/{IndexSubjectPanel-upH9MjU-.js → IndexSubjectPanel-DzSw8M9j.js} +1 -1
  131. package/static/auth-callback/assets/{ModelAssignmentsPanel-CVGH4t4g.js → ModelAssignmentsPanel-BsRxGc2p.js} +1 -1
  132. package/static/auth-callback/assets/ModelsPage-DEe1lo6Q.js +10 -0
  133. package/static/auth-callback/assets/{NetworkPage-Dcbrb1fd.js → NetworkPage-DBiEh1Oz.js} +1 -1
  134. package/static/auth-callback/assets/{PaneListHeader-DrY-1wBq.js → PaneListHeader-lEEgjyN9.js} +1 -1
  135. package/static/auth-callback/assets/{SearchIndexingPanel-Dw25y53v.js → SearchIndexingPanel-CZCUUGt6.js} +1 -1
  136. package/static/auth-callback/assets/{StatusSubjectPanel-BHlz9rNF.js → StatusSubjectPanel-21qdueMr.js} +1 -1
  137. package/static/auth-callback/assets/{StatusWorkspace-BH7exQP5.js → StatusWorkspace-R8RKsqVz.js} +1 -1
  138. package/static/auth-callback/assets/{SystemSettingsPage-BYLKnM9f.js → SystemSettingsPage-BQ4e-4Wy.js} +1 -1
  139. package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DT34LKku.js → SystemSettingsSubjectPanel-BopXD7SE.js} +1 -1
  140. package/static/auth-callback/assets/{activity-DdULRcSI.js → activity-DSfmTGfY.js} +1 -1
  141. package/static/auth-callback/assets/ai-connections-C03UWyPh.js +1 -0
  142. package/static/auth-callback/assets/{auth-callback-D7l2P25I.js → auth-callback-DleaitAS.js} +91 -91
  143. package/static/auth-callback/assets/auth-callback-vPSC2d2F.css +1 -0
  144. package/static/auth-callback/assets/{badge-j4zjFnmg.js → badge-B0aLu1sl.js} +1 -1
  145. package/static/auth-callback/assets/{download-DGXoks01.js → download-D_bFwdYJ.js} +1 -1
  146. package/static/auth-callback/assets/{external-link-CvbgXXaI.js → external-link-DRfjTaQu.js} +1 -1
  147. package/static/auth-callback/assets/{index-LRWvKJ2i.js → index-CG23cLYQ.js} +1 -1
  148. package/static/auth-callback/assets/{index-BOK3j1dz.js → index-CyV9ejwx.js} +1 -1
  149. package/static/auth-callback/assets/{index-browser-C1Qpe0g4.js → index-browser-D70paxIg.js} +1 -1
  150. package/static/auth-callback/assets/{key-round-CmgS5UdQ.js → key-round-BjV_mVYH.js} +1 -1
  151. package/static/auth-callback/assets/{rotate-ccw-c4CSG6Rq.js → rotate-ccw-CKoOAfse.js} +1 -1
  152. package/static/auth-callback/assets/{skeleton-ZPMTiRSM.js → skeleton-BZNjZaHx.js} +1 -1
  153. package/static/auth-callback/assets/{waypoints-xjyBflU5.js → waypoints-DoaJVzZv.js} +1 -1
  154. package/static/auth-callback/assets/{workspace-layout-B9nj6F5J.js → workspace-layout-CaP46_ZR.js} +1 -1
  155. package/static/auth-callback/auth-callback.html +2 -2
  156. package/static/dashboard/assets/{AiConfigContext-BWOOSYNr.js → AiConfigContext-BSrR27yD.js} +1 -1
  157. package/static/dashboard/assets/{AiConfigPage-CG2kQ9Wy.js → AiConfigPage-D65Z2LET.js} +1 -1
  158. package/static/dashboard/assets/{DocumentProcessingPanel-B4VXajfj.js → DocumentProcessingPanel-DyTe7Nei.js} +1 -1
  159. package/static/dashboard/assets/{IndexLifecyclePanel-CWCy0CC8.js → IndexLifecyclePanel-fK8ZGlrL.js} +1 -1
  160. package/static/dashboard/assets/{IndexSubjectPanel-CSgyQnG_.js → IndexSubjectPanel-CZPGor7v.js} +1 -1
  161. package/static/dashboard/assets/{ModelAssignmentsPanel-CdGIGidT.js → ModelAssignmentsPanel-CfYn5LMQ.js} +1 -1
  162. package/static/dashboard/assets/ModelsPage-djlJsghe.js +25 -0
  163. package/static/dashboard/assets/{NetworkPage-COia9NCH.js → NetworkPage-Coj6GnPl.js} +1 -1
  164. package/static/dashboard/assets/{PaneListHeader-SZWyr602.js → PaneListHeader-CUuFNSsZ.js} +1 -1
  165. package/static/dashboard/assets/{SearchIndexingPanel-D6PZtG6k.js → SearchIndexingPanel-CyJLioXS.js} +1 -1
  166. package/static/dashboard/assets/{StatusSubjectPanel-CxRD4kv0.js → StatusSubjectPanel-Cv26GSVC.js} +1 -1
  167. package/static/dashboard/assets/{StatusWorkspace-D3PfmY9-.js → StatusWorkspace-CDjFrsmB.js} +1 -1
  168. package/static/dashboard/assets/{SystemSettingsPage-COg1MmMj.js → SystemSettingsPage-BuNOyNoa.js} +1 -1
  169. package/static/dashboard/assets/{SystemSettingsSubjectPanel-BSVVB9Ol.js → SystemSettingsSubjectPanel-B2dasdez.js} +1 -1
  170. package/static/dashboard/assets/{activity-BJJx5cN-.js → activity-D1d2j_4Z.js} +1 -1
  171. package/static/dashboard/assets/ai-connections-C03UWyPh.js +1 -0
  172. package/static/dashboard/assets/{badge-elmrFSCj.js → badge-BeAAv6sp.js} +1 -1
  173. package/static/dashboard/assets/{dashboard-IvQrNmru.js → dashboard-BnGrUGv8.js} +68 -68
  174. package/static/dashboard/assets/dashboard-vPSC2d2F.css +1 -0
  175. package/static/dashboard/assets/{download-C3FH2KzG.js → download-DfFGiZRn.js} +1 -1
  176. package/static/dashboard/assets/{external-link-Bx7F0uKb.js → external-link-IsjU_LC9.js} +1 -1
  177. package/static/dashboard/assets/{index-liRoRIP1.js → index-BWQTucPe.js} +1 -1
  178. package/static/dashboard/assets/{index-M4-kWiGz.js → index-Dj75OjnW.js} +1 -1
  179. package/static/dashboard/assets/{key-round-CXg0bKAj.js → key-round-BJ_9wmQ_.js} +1 -1
  180. package/static/dashboard/assets/{rotate-ccw-yxJKOBrX.js → rotate-ccw-D3JGiFbR.js} +1 -1
  181. package/static/dashboard/assets/{skeleton-x9jNGrQT.js → skeleton-CC4nc-z-.js} +1 -1
  182. package/static/dashboard/assets/{waypoints-CTKeRsGp.js → waypoints-h7sqFqiG.js} +1 -1
  183. package/static/dashboard/assets/{workspace-layout--YkgkS38.js → workspace-layout-ZAPTOHhs.js} +1 -1
  184. package/static/dashboard/dashboard.html +2 -2
  185. package/static/settings/assets/{AiConfigContext-CelxXFcQ.js → AiConfigContext-lGkWpvKP.js} +1 -1
  186. package/static/settings/assets/{AiConfigPage-BaP-EovM.js → AiConfigPage-BbZWIBZq.js} +1 -1
  187. package/static/settings/assets/{DocumentProcessingPanel-DzLZluFv.js → DocumentProcessingPanel-DvYdjT-V.js} +1 -1
  188. package/static/settings/assets/{IndexLifecyclePanel-Bzj1-_oI.js → IndexLifecyclePanel-W5OGQZj7.js} +1 -1
  189. package/static/settings/assets/{IndexSubjectPanel-B263QLUh.js → IndexSubjectPanel-g_Aa5soq.js} +1 -1
  190. package/static/settings/assets/{ModelAssignmentsPanel-BAdT4UR0.js → ModelAssignmentsPanel-COlMBKXj.js} +1 -1
  191. package/static/settings/assets/ModelsPage-mApKi-aw.js +10 -0
  192. package/static/settings/assets/{NetworkPage-BK6a7l4g.js → NetworkPage-BDT05JUq.js} +1 -1
  193. package/static/settings/assets/{PaneListHeader-BAS2ICPq.js → PaneListHeader-CByhNpMG.js} +1 -1
  194. package/static/settings/assets/{SearchIndexingPanel-Cb_p-NgW.js → SearchIndexingPanel-BFAyzXls.js} +1 -1
  195. package/static/settings/assets/{StatusSubjectPanel-CcjqUua6.js → StatusSubjectPanel-Bz_XZ3VU.js} +1 -1
  196. package/static/settings/assets/{StatusWorkspace-7Ibty3_k.js → StatusWorkspace-CeVypHcW.js} +1 -1
  197. package/static/settings/assets/{SystemSettingsPage-DPSz4dg4.js → SystemSettingsPage-Dh7cQIfx.js} +1 -1
  198. package/static/settings/assets/{SystemSettingsSubjectPanel-Cb4HkKT5.js → SystemSettingsSubjectPanel-CSnpciO0.js} +1 -1
  199. package/static/settings/assets/{activity-Qhsr5Pxu.js → activity-DXz3EfFN.js} +1 -1
  200. package/static/settings/assets/ai-connections-C03UWyPh.js +1 -0
  201. package/static/settings/assets/{badge-B1vf2qCl.js → badge-1ZA144i4.js} +1 -1
  202. package/static/settings/assets/{download-CYNt0aZ-.js → download-CUHimlYa.js} +1 -1
  203. package/static/settings/assets/{external-link-ClKb39NT.js → external-link-BYHSVj2Z.js} +1 -1
  204. package/static/settings/assets/{index-y8ew3MLM.js → index-DKPDMdW5.js} +1 -1
  205. package/static/settings/assets/{index-browser-DJhvgpNI.js → index-browser-BaEFz0e0.js} +1 -1
  206. package/static/settings/assets/{index-BgiIDSch.js → index-viSgSvbO.js} +1 -1
  207. package/static/settings/assets/{key-round-5d-DrJz-.js → key-round-COByPOg8.js} +1 -1
  208. package/static/settings/assets/{rotate-ccw-CHZY7kS5.js → rotate-ccw-BC2EN6cE.js} +1 -1
  209. package/static/settings/assets/{settings-D5VRWyx6.js → settings-DLH9XUoT.js} +86 -86
  210. package/static/settings/assets/settings-vPSC2d2F.css +1 -0
  211. package/static/settings/assets/{skeleton-FNabNxNE.js → skeleton-B0-FOhKL.js} +1 -1
  212. package/static/settings/assets/{waypoints-BnL_8ljo.js → waypoints-DGMsvqWo.js} +1 -1
  213. package/static/settings/assets/{workspace-layout-D5q3F59S.js → workspace-layout-B0SVrJIu.js} +1 -1
  214. package/static/settings/settings.html +2 -2
  215. package/static/auth-callback/assets/ModelsPage-BpkVFKbf.js +0 -10
  216. package/static/auth-callback/assets/ai-connections-Bm52UO7Y.js +0 -1
  217. package/static/auth-callback/assets/auth-callback-01yz-UDU.css +0 -1
  218. package/static/dashboard/assets/ModelsPage-Chd5UK0D.js +0 -25
  219. package/static/dashboard/assets/ai-connections-Bm52UO7Y.js +0 -1
  220. package/static/dashboard/assets/dashboard-01yz-UDU.css +0 -1
  221. package/static/settings/assets/ModelsPage-C0NFa1zq.js +0 -10
  222. package/static/settings/assets/ai-connections-Bm52UO7Y.js +0 -1
  223. package/static/settings/assets/settings-01yz-UDU.css +0 -1
package/config/cloud.json CHANGED
@@ -139,7 +139,7 @@
139
139
  "unstructuredDataAccessor": {
140
140
  "@id": "urn:undefineds:xpod:RemoteDataAccessor"
141
141
  },
142
- "presignedRedirectEnabled": true,
142
+ "presignedRedirectEnabled": false,
143
143
  "textSearchIndexingEnabled": true,
144
144
  "rdfSearchIntentSink": {
145
145
  "@id": "urn:undefineds:xpod:RdfSearchIntentSink"
package/config/main.json CHANGED
@@ -1,5 +1,8 @@
1
1
  {
2
- "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
2
+ "@context": [
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
4
+ "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld"
5
+ ],
3
6
  "import": [
4
7
  "css:config/app/init/static-root.json",
5
8
  "css:config/app/main/default.json",
@@ -67,7 +70,38 @@
67
70
  "@id": "urn:solid-server:default:IdentityProviderFactory"
68
71
  },
69
72
  "overrideParameters": {
70
- "@type": "IdentityProviderFactory",
73
+ "@type": "SessionBoundIdentityProviderFactory",
74
+ "args_promptFactory": {
75
+ "@id": "urn:solid-server:default:PromptFactory"
76
+ },
77
+ "args_adapterFactory": {
78
+ "@id": "urn:solid-server:default:IdpAdapterFactory"
79
+ },
80
+ "args_baseUrl": {
81
+ "@id": "urn:solid-server:default:variable:baseUrl"
82
+ },
83
+ "args_oidcPath": "/.oidc",
84
+ "args_clientCredentialsStore": {
85
+ "@id": "urn:solid-server:default:ClientCredentialsStore"
86
+ },
87
+ "args_storage": {
88
+ "@id": "urn:solid-server:default:KeyStorage"
89
+ },
90
+ "args_jwkGenerator": {
91
+ "@id": "urn:solid-server:default:JwkGenerator"
92
+ },
93
+ "args_showStackTrace": {
94
+ "@id": "urn:solid-server:default:variable:showStackTrace"
95
+ },
96
+ "args_errorHandler": {
97
+ "@id": "urn:solid-server:default:ErrorHandler"
98
+ },
99
+ "args_responseWriter": {
100
+ "@id": "urn:solid-server:default:ResponseWriter"
101
+ },
102
+ "args_interactionRoute": {
103
+ "@id": "urn:solid-server:default:IndexRoute"
104
+ },
71
105
  "config": {
72
106
  "extraParams": [
73
107
  "provisionCode"
@@ -5,6 +5,9 @@ import { type GatewayDeployment } from './GatewayApiKey';
5
5
  import type { InvocationTokenCodec } from './InvocationTokenCodec';
6
6
  export interface GatewayAccessKeyRecord {
7
7
  id: string;
8
+ /** CSS credentials are saved configuration, never legacy Gateway authentication records. */
9
+ kind?: 'client-credentials';
10
+ credentialResource?: string;
8
11
  owner: string;
9
12
  secretHash: string;
10
13
  deployment: GatewayDeployment;
@@ -53,7 +53,7 @@ class GatewayApiKeyAuthenticator {
53
53
  catch (cause) {
54
54
  return infrastructureError(cause);
55
55
  }
56
- if (!record) {
56
+ if (!record || record.kind === 'client-credentials') {
57
57
  await (0, GatewayApiKey_1.verifyGatewayApiKeySecret)(parsed.secret, await this.dummyHash);
58
58
  return invalidGatewayApiKey();
59
59
  }
@@ -64,8 +64,9 @@ export declare class PodGatewayAccessKeyRepository implements GatewayAccessKeyRe
64
64
  private resolveTrustedFetch;
65
65
  private wrapPodFetch;
66
66
  private readSecrets;
67
+ private readSecretSnapshot;
67
68
  private writeSecret;
68
69
  private deleteSecret;
69
- private writeSecrets;
70
+ private mutateSecrets;
70
71
  }
71
72
  export {};
@@ -20,6 +20,23 @@ class PodGatewayAccessKeyRepository {
20
20
  }
21
21
  async create(record, context) {
22
22
  const { db, resource, fetch, podUrl } = await this.dbForOwner(record.owner, context);
23
+ if (record.kind === 'client-credentials') {
24
+ if (!record.plaintext || !record.credentialResource) {
25
+ throw new Error('client_credentials_registration_incomplete');
26
+ }
27
+ const locator = this.locatorCodec.decode(record.id);
28
+ if (locator?.owner !== record.owner || locator.deployment !== record.deployment) {
29
+ throw new Error('client_credentials_registration_owner_mismatch');
30
+ }
31
+ await this.mutateSecrets(record.owner, podUrl, fetch, (secrets) => {
32
+ secrets.keys[record.id] = {
33
+ kind: 'client-credentials', plaintext: record.plaintext, createdAt: record.createdAt.toISOString(),
34
+ name: record.name, owner: record.owner, deployment: record.deployment,
35
+ credentialResource: record.credentialResource,
36
+ };
37
+ });
38
+ return { ...record, scopes: [], secretHash: '' };
39
+ }
23
40
  const valid = models_1.aiGatewayRepository.validateAccessKey(toGatewayAccessKeyInsert(record));
24
41
  await db.insert(resource).values(valid).execute();
25
42
  if (record.plaintext) {
@@ -33,19 +50,30 @@ class PodGatewayAccessKeyRepository {
33
50
  if (!locator) {
34
51
  return undefined;
35
52
  }
36
- const { db, resource } = await this.dbForOwner(locator.owner, context);
53
+ const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
54
+ // Legacy authentication reads only its RDF verifier rows. Recoverable CSS
55
+ // credentials belong exclusively to owner-authorized management requests.
56
+ if (!context?.internalPodAccess) {
57
+ const saved = (await this.readSecrets(locator.owner, podUrl, fetch)).keys[id];
58
+ if (saved?.kind === 'client-credentials')
59
+ return clientCredentialRecord(id, locator.owner, saved);
60
+ }
37
61
  const row = await db.findById(resource, gatewayAccessKeyStorageId(id));
38
62
  return row ? recordFromRow(row) : undefined;
39
63
  }
40
64
  async listByOwner(owner, context) {
41
- const { db, listResource } = await this.dbForOwner(owner, context);
65
+ const { db, listResource, fetch, podUrl } = await this.dbForOwner(owner, context);
66
+ const secrets = await this.readSecrets(owner, podUrl, fetch);
42
67
  const rows = await db
43
68
  .select()
44
69
  .from(listResource)
45
70
  .where((0, drizzle_solid_1.eq)(listResource.owner, owner))
46
71
  .execute();
47
- return rows
48
- .map(recordFromRow)
72
+ const credentials = Object.entries(secrets.keys)
73
+ .filter(([id]) => this.locatorCodec.decode(id)?.owner === owner)
74
+ .map(([id, saved]) => clientCredentialRecord(id, owner, saved))
75
+ .filter((record) => Boolean(record));
76
+ return [...rows.map(recordFromRow).filter((record) => secrets.keys[record.id]?.kind !== 'client-credentials'), ...credentials]
49
77
  .filter((record) => !record.revokedAt)
50
78
  .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
51
79
  }
@@ -54,7 +82,10 @@ class PodGatewayAccessKeyRepository {
54
82
  if (!locator) {
55
83
  return undefined;
56
84
  }
57
- const { db, resource } = await this.dbForOwner(locator.owner, context);
85
+ const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
86
+ if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
87
+ throw new Error('client_credentials_suspension_unsupported');
88
+ }
58
89
  const row = await db.updateById(resource, gatewayAccessKeyStorageId(id), { disabledAt: enabled ? null : changedAt });
59
90
  return row ? recordFromRow(row) : undefined;
60
91
  }
@@ -63,7 +94,10 @@ class PodGatewayAccessKeyRepository {
63
94
  if (!locator) {
64
95
  return undefined;
65
96
  }
66
- const { db, resource } = await this.dbForOwner(locator.owner, context);
97
+ const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
98
+ if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
99
+ throw new Error('client_credentials_revocation_requires_account');
100
+ }
67
101
  const row = await db.updateById(resource, gatewayAccessKeyStorageId(id), { revokedAt });
68
102
  return row ? recordFromRow(row) : undefined;
69
103
  }
@@ -73,6 +107,12 @@ class PodGatewayAccessKeyRepository {
73
107
  return false;
74
108
  }
75
109
  const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
110
+ if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
111
+ // The Account host revokes the actual CSS credential. This operation
112
+ // removes only its saved client configuration, not an authentication row.
113
+ await this.deleteSecret(locator.owner, podUrl, id, fetch);
114
+ return true;
115
+ }
76
116
  const storageId = gatewayAccessKeyStorageId(id);
77
117
  await db.updateById(resource, storageId, { revokedAt: new Date() });
78
118
  await this.deleteSecret(locator.owner, podUrl, id, fetch);
@@ -162,56 +202,85 @@ class PodGatewayAccessKeyRepository {
162
202
  };
163
203
  }
164
204
  async readSecrets(owner, podUrl, trustedFetch) {
205
+ return (await this.readSecretSnapshot(owner, podUrl, trustedFetch)).secrets;
206
+ }
207
+ async readSecretSnapshot(owner, podUrl, trustedFetch) {
165
208
  const response = await trustedFetch((0, AiConnectionsServiceAccess_1.resolveGatewayAccessKeySecretResourceUrl)(owner, podUrl), {
166
209
  method: 'GET',
167
210
  headers: { Accept: 'application/json' },
168
211
  });
169
- if (!response.ok) {
170
- return emptySecrets();
171
- }
212
+ if (response.status === 404)
213
+ return { secrets: emptySecrets(), exists: false };
214
+ if (!response.ok)
215
+ throw new Error('gateway_key_secret_read_failed');
172
216
  const text = (await response.text()).trim();
173
217
  if (!text || !response.headers.get('content-type')?.toLowerCase().includes('application/json')) {
174
- return emptySecrets();
218
+ throw new Error('gateway_key_secret_invalid_document');
175
219
  }
176
220
  try {
177
221
  const parsed = JSON.parse(text);
178
- if (parsed.version !== 1 || !parsed.keys || typeof parsed.keys !== 'object') {
179
- return emptySecrets();
222
+ if (parsed.version !== 1 || !parsed.keys || typeof parsed.keys !== 'object' || Array.isArray(parsed.keys)) {
223
+ throw new Error('gateway_key_secret_invalid_document');
224
+ }
225
+ if (Object.values(parsed.keys).some((value) => !value || typeof value !== 'object' || typeof value.plaintext !== 'string')) {
226
+ throw new Error('gateway_key_secret_invalid_document');
180
227
  }
181
228
  return {
182
- version: 1,
183
- keys: Object.fromEntries(Object.entries(parsed.keys).filter(([, value]) => value && typeof value === 'object' && typeof value.plaintext === 'string')),
229
+ exists: true,
230
+ etag: response.headers.get('etag') ?? undefined,
231
+ secrets: {
232
+ version: 1,
233
+ keys: parsed.keys,
234
+ },
184
235
  };
185
236
  }
186
237
  catch {
187
- return emptySecrets();
238
+ throw new Error('gateway_key_secret_invalid_document');
188
239
  }
189
240
  }
190
241
  async writeSecret(owner, podUrl, keyId, plaintext, trustedFetch) {
191
- const secrets = await this.readSecrets(owner, podUrl, trustedFetch);
192
- secrets.keys[keyId] = {
193
- plaintext,
194
- createdAt: new Date().toISOString(),
195
- };
196
- await this.writeSecrets(owner, podUrl, secrets, trustedFetch);
242
+ await this.mutateSecrets(owner, podUrl, trustedFetch, (secrets) => {
243
+ secrets.keys[keyId] = { plaintext, createdAt: new Date().toISOString() };
244
+ });
197
245
  }
198
246
  async deleteSecret(owner, podUrl, keyId, trustedFetch) {
199
- const secrets = await this.readSecrets(owner, podUrl, trustedFetch);
200
- delete secrets.keys[keyId];
201
- await this.writeSecrets(owner, podUrl, secrets, trustedFetch);
247
+ await this.mutateSecrets(owner, podUrl, trustedFetch, (secrets) => { delete secrets.keys[keyId]; });
202
248
  }
203
- async writeSecrets(owner, podUrl, secrets, trustedFetch) {
204
- const response = await trustedFetch((0, AiConnectionsServiceAccess_1.resolveGatewayAccessKeySecretResourceUrl)(owner, podUrl), {
205
- method: 'PUT',
206
- headers: { 'Content-Type': 'application/json' },
207
- body: JSON.stringify(secrets, null, 2),
208
- });
209
- if (!response.ok) {
210
- throw new Error('gateway_key_secret_write_failed');
249
+ async mutateSecrets(owner, podUrl, trustedFetch, mutate) {
250
+ for (let attempt = 0; attempt < 3; attempt++) {
251
+ const snapshot = await this.readSecretSnapshot(owner, podUrl, trustedFetch);
252
+ if (snapshot.exists && (!snapshot.etag || !/^"[^"]*"$/u.test(snapshot.etag))) {
253
+ throw new Error('gateway_key_secret_etag_required');
254
+ }
255
+ mutate(snapshot.secrets);
256
+ const response = await trustedFetch((0, AiConnectionsServiceAccess_1.resolveGatewayAccessKeySecretResourceUrl)(owner, podUrl), {
257
+ method: 'PUT',
258
+ headers: {
259
+ 'Content-Type': 'application/json',
260
+ ...(snapshot.exists ? { 'If-Match': snapshot.etag } : { 'If-None-Match': '*' }),
261
+ },
262
+ body: JSON.stringify(snapshot.secrets, null, 2),
263
+ });
264
+ if (response.status === 412)
265
+ continue;
266
+ if (!response.ok)
267
+ throw new Error('gateway_key_secret_write_failed');
268
+ return;
211
269
  }
270
+ throw new Error('gateway_key_secret_write_conflict');
212
271
  }
213
272
  }
214
273
  exports.PodGatewayAccessKeyRepository = PodGatewayAccessKeyRepository;
274
+ function clientCredentialRecord(id, owner, saved) {
275
+ const createdAt = toDate(saved.createdAt);
276
+ if (saved.kind !== 'client-credentials' || saved.owner !== owner || !saved.credentialResource || !createdAt
277
+ || (saved.deployment !== 'cloud' && saved.deployment !== 'local'))
278
+ return undefined;
279
+ return {
280
+ id, owner, kind: 'client-credentials', credentialResource: saved.credentialResource,
281
+ name: saved.name, createdAt, deployment: saved.deployment, scopes: [], secretHash: '',
282
+ };
283
+ }
215
284
  function createDefaultGatewayAccessKeyDb(input) {
216
285
  const resource = input.resource ?? models_1.gatewayAccessKeyResource;
217
286
  const listResource = input.listResource ?? resource;
@@ -0,0 +1,80 @@
1
+ export type DeviceCodeHttpBodyEncoding = 'form' | 'json';
2
+ export type DeviceCodeBeginCodec = 'oauthDeviceCode' | 'oauthDeviceCodePkce' | 'deviceCodeJson';
3
+ export type DeviceCodePollCodec = 'oauthDeviceCode' | 'oauthDeviceCodePkce' | 'deviceCodeJson';
4
+ export type DeviceCodeTokenExchangeCodec = 'none' | 'authorizationCodeForm';
5
+ export type OAuthConnectMode = 'deviceCodeOAuth' | 'authorizationCodeOAuth';
6
+ export interface DeviceCodeEndpointDescriptor {
7
+ endpoint: string;
8
+ headers?: Record<string, string>;
9
+ }
10
+ export interface DeviceCodeProtocolDescriptor {
11
+ id: string;
12
+ verificationUriOrigins?: string[];
13
+ begin: DeviceCodeEndpointDescriptor & {
14
+ codec: DeviceCodeBeginCodec;
15
+ deviceCodeField?: string;
16
+ userCodeField?: string;
17
+ verificationUriField?: string;
18
+ verificationUriCompleteField?: string;
19
+ expiresInField?: string;
20
+ expiresAtField?: string;
21
+ intervalField?: string;
22
+ defaultExpiresInSeconds?: number;
23
+ defaultIntervalSeconds?: number;
24
+ };
25
+ poll: DeviceCodeEndpointDescriptor & {
26
+ codec: DeviceCodePollCodec;
27
+ deviceCodeField?: string;
28
+ pendingHttpStatuses?: number[];
29
+ };
30
+ tokenExchange?: DeviceCodeEndpointDescriptor & {
31
+ codec: DeviceCodeTokenExchangeCodec;
32
+ redirectUri?: string;
33
+ codeField?: string;
34
+ codeVerifierField?: string;
35
+ };
36
+ refresh?: DeviceCodeEndpointDescriptor & {
37
+ codec: 'refreshTokenForm';
38
+ };
39
+ defaultVerificationUri?: string;
40
+ accountIdClaim?: string | string[];
41
+ }
42
+ export interface AuthorizationCodeProtocolDescriptor {
43
+ id: string;
44
+ authorization: DeviceCodeEndpointDescriptor & {
45
+ redirectUris: string[];
46
+ scopes?: string[];
47
+ responseType?: 'code';
48
+ codeChallengeMethod?: 'S256';
49
+ extraParams?: Record<string, string>;
50
+ };
51
+ token: DeviceCodeEndpointDescriptor & {
52
+ codec: 'authorizationCodeForm';
53
+ codeField?: string;
54
+ codeVerifierField?: string;
55
+ };
56
+ refresh?: DeviceCodeEndpointDescriptor & {
57
+ codec: 'refreshTokenForm';
58
+ };
59
+ accountIdClaim?: string | string[];
60
+ }
61
+ interface BaseOAuthIntegration {
62
+ provider: string;
63
+ offeringId: string;
64
+ mode: OAuthConnectMode;
65
+ integrationId: string;
66
+ issuedBy: string;
67
+ clientId: string;
68
+ accountLabel?: string;
69
+ accountId?: string;
70
+ }
71
+ export interface DeviceCodeOAuthIntegration extends BaseOAuthIntegration {
72
+ mode: 'deviceCodeOAuth';
73
+ protocol: DeviceCodeProtocolDescriptor;
74
+ }
75
+ export interface AuthorizationCodeOAuthIntegration extends BaseOAuthIntegration {
76
+ mode: 'authorizationCodeOAuth';
77
+ protocol: AuthorizationCodeProtocolDescriptor;
78
+ }
79
+ export type OAuthIntegration = DeviceCodeOAuthIntegration | AuthorizationCodeOAuthIntegration;
80
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=DeviceCodeProtocol.js.map
@@ -0,0 +1,38 @@
1
+ import type { ProviderSecret } from '../credentials/CredentialVault';
2
+ import type { GatewayDeployment } from '../auth/InvocationTokenCodec';
3
+ import type { SessionImportProfile } from './SessionImportProfiles';
4
+ export interface LocalSessionImportResult {
5
+ secret: ProviderSecret;
6
+ /**
7
+ * How the imported credential authenticates upstream. The import itself is
8
+ * local, but an imported subscription session is still an OAuth credential.
9
+ */
10
+ credentialAuthMode?: 'deviceCodeOAuth' | 'local';
11
+ accountLabel?: string;
12
+ metadata?: Record<string, unknown>;
13
+ }
14
+ export interface LocalSessionImportInput {
15
+ deployment: GatewayDeployment;
16
+ }
17
+ export interface LocalSessionImportAdapter {
18
+ provider: string;
19
+ offeringId: string;
20
+ importSession(input: LocalSessionImportInput): Promise<LocalSessionImportResult>;
21
+ }
22
+ export interface FileSessionImportAdapterOptions {
23
+ profile: SessionImportProfile;
24
+ homeDir?: string;
25
+ readFile?: (filePath: string, encoding: BufferEncoding) => Promise<string>;
26
+ maxBytes?: number;
27
+ }
28
+ export declare class FileSessionImportAdapter implements LocalSessionImportAdapter {
29
+ readonly provider: string;
30
+ readonly offeringId: string;
31
+ private readonly profile;
32
+ private readonly homeDir;
33
+ private readonly readFile;
34
+ private readonly maxBytes;
35
+ constructor(options: FileSessionImportAdapterOptions);
36
+ importSession(input: LocalSessionImportInput): Promise<LocalSessionImportResult>;
37
+ private readSessionFile;
38
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileSessionImportAdapter = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_os_1 = __importDefault(require("node:os"));
9
+ const DEFAULT_MAX_SESSION_FILE_BYTES = 256 * 1024;
10
+ class FileSessionImportAdapter {
11
+ constructor(options) {
12
+ this.profile = options.profile;
13
+ this.provider = options.profile.provider;
14
+ this.offeringId = options.profile.offeringId;
15
+ this.homeDir = options.homeDir ?? node_os_1.default.homedir();
16
+ this.readFile = options.readFile ?? node_fs_1.promises.readFile;
17
+ this.maxBytes = options.maxBytes ?? DEFAULT_MAX_SESSION_FILE_BYTES;
18
+ }
19
+ async importSession(input) {
20
+ if (input.deployment !== 'local') {
21
+ throw new Error('local_session_import_unavailable_in_cloud');
22
+ }
23
+ const raw = await this.readSessionFile(this.profile.resolvePath(this.homeDir));
24
+ const payload = parseJsonObject(raw);
25
+ return this.profile.importSession(payload);
26
+ }
27
+ async readSessionFile(filePath) {
28
+ let raw;
29
+ try {
30
+ raw = await this.readFile(filePath, 'utf8');
31
+ }
32
+ catch (error) {
33
+ if (isErrno(error, 'ENOENT')) {
34
+ throw new Error('local_session_file_missing');
35
+ }
36
+ throw new Error('local_session_file_read_failed');
37
+ }
38
+ if (Buffer.byteLength(raw, 'utf8') > this.maxBytes) {
39
+ throw new Error('local_session_file_too_large');
40
+ }
41
+ return raw;
42
+ }
43
+ }
44
+ exports.FileSessionImportAdapter = FileSessionImportAdapter;
45
+ function parseJsonObject(raw) {
46
+ let parsed;
47
+ try {
48
+ parsed = JSON.parse(raw);
49
+ }
50
+ catch {
51
+ throw new Error('local_session_file_invalid_json');
52
+ }
53
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
54
+ throw new Error('local_session_file_invalid_json');
55
+ }
56
+ return parsed;
57
+ }
58
+ function isErrno(error, code) {
59
+ return error instanceof Error
60
+ && 'code' in error
61
+ && error.code === code;
62
+ }
63
+ //# sourceMappingURL=FileSessionImportAdapter.js.map
@@ -0,0 +1,24 @@
1
+ export interface AuthorizationCodeCallbackReceiver {
2
+ register(input: {
3
+ redirectUris: string[];
4
+ state: string;
5
+ expiresAt: Date;
6
+ onCallback(result: {
7
+ code?: string;
8
+ error?: string;
9
+ }): Promise<void> | void;
10
+ }): Promise<{
11
+ redirectUri: string;
12
+ close(): void;
13
+ }>;
14
+ }
15
+ type RegistrationInput = Parameters<AuthorizationCodeCallbackReceiver['register']>[0];
16
+ /** Receives authorization codes locally; credential exchange belongs to the authenticated caller. */
17
+ export declare class LoopbackAuthorizationCallbackReceiver implements AuthorizationCodeCallbackReceiver {
18
+ private readonly listeners;
19
+ private pending;
20
+ register(input: RegistrationInput): ReturnType<AuthorizationCodeCallbackReceiver['register']>;
21
+ private registerSerial;
22
+ private handle;
23
+ }
24
+ export {};
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoopbackAuthorizationCallbackReceiver = void 0;
4
+ const node_http_1 = require("node:http");
5
+ /** Receives authorization codes locally; credential exchange belongs to the authenticated caller. */
6
+ class LoopbackAuthorizationCallbackReceiver {
7
+ constructor() {
8
+ this.listeners = new Map();
9
+ this.pending = Promise.resolve();
10
+ }
11
+ register(input) {
12
+ const result = this.pending.then(() => this.registerSerial(input));
13
+ this.pending = result.catch(() => undefined);
14
+ return result;
15
+ }
16
+ async registerSerial(input) {
17
+ if (!input.state || !Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) {
18
+ throw new Error('Authorization callback registration is invalid or expired.');
19
+ }
20
+ if ([...this.listeners.values()].some(listener => listener.registrations.has(input.state))) {
21
+ throw new Error('Authorization callback state is already registered.');
22
+ }
23
+ const uris = input.redirectUris.map(value => {
24
+ let uri;
25
+ try {
26
+ uri = new URL(value);
27
+ }
28
+ catch {
29
+ throw new Error('Invalid loopback authorization redirect URI.');
30
+ }
31
+ if (uri.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(uri.hostname) ||
32
+ uri.username || uri.password || uri.search || uri.hash || uri.port === '0') {
33
+ throw new Error('Invalid loopback authorization redirect URI.');
34
+ }
35
+ return uri;
36
+ });
37
+ for (const uri of uris) {
38
+ const port = Number(uri.port || 80);
39
+ let listener = this.listeners.get(port);
40
+ if (!listener) {
41
+ const registrations = new Map();
42
+ const server = (0, node_http_1.createServer)((request, response) => {
43
+ void this.handle(request, response, port, registrations);
44
+ });
45
+ try {
46
+ await new Promise((resolve, reject) => {
47
+ server.once('error', reject);
48
+ server.listen(port, '127.0.0.1', () => {
49
+ server.removeListener('error', reject);
50
+ resolve();
51
+ });
52
+ });
53
+ }
54
+ catch (error) {
55
+ if (error.code === 'EADDRINUSE') {
56
+ continue;
57
+ }
58
+ throw new Error('Unable to start the local authorization callback listener.');
59
+ }
60
+ server.unref();
61
+ listener = { server, registrations };
62
+ this.listeners.set(port, listener);
63
+ }
64
+ const selected = listener;
65
+ let timer;
66
+ let active = true;
67
+ const close = () => {
68
+ if (!active) {
69
+ return;
70
+ }
71
+ active = false;
72
+ clearTimeout(timer);
73
+ selected.registrations.delete(input.state);
74
+ if (selected.registrations.size === 0 && this.listeners.get(port) === selected) {
75
+ this.listeners.delete(port);
76
+ selected.server.close();
77
+ }
78
+ };
79
+ selected.registrations.set(input.state, { ...input, path: uri.pathname, close });
80
+ timer = setTimeout(close, Math.max(0, Math.min(input.expiresAt.getTime() - Date.now(), 2_147_483_647)));
81
+ timer.unref();
82
+ return { redirectUri: uri.toString(), close };
83
+ }
84
+ throw new Error('The registered local authorization callback ports are unavailable. Close the application using them and retry.');
85
+ }
86
+ async handle(request, response, port, registrations) {
87
+ const reply = (status, success = false) => {
88
+ response.writeHead(status, {
89
+ 'Content-Type': 'text/html; charset=utf-8',
90
+ 'Cache-Control': 'no-store',
91
+ 'Connection': 'close',
92
+ 'Content-Security-Policy': "default-src 'none'; frame-ancestors 'none'",
93
+ 'Referrer-Policy': 'no-referrer',
94
+ });
95
+ response.end(success ? '授权已返回 Xpod,请切回应用完成连接。' : '授权回调无效或已过期,请返回应用重试。');
96
+ };
97
+ const allowedHosts = ['localhost', '127.0.0.1'].map(host => port === 80 ? host : `${host}:${port}`);
98
+ if (request.method !== 'GET' || !allowedHosts.includes(request.headers.host ?? '') ||
99
+ !request.url?.startsWith('/') || request.url.startsWith('//') ||
100
+ request.rawHeaders.filter((value, index) => index % 2 === 0 && value.toLowerCase() === 'host').length !== 1) {
101
+ reply(400);
102
+ return;
103
+ }
104
+ let uri;
105
+ try {
106
+ uri = new URL(request.url, `http://127.0.0.1:${port}`);
107
+ }
108
+ catch {
109
+ reply(400);
110
+ return;
111
+ }
112
+ const query = uri.searchParams;
113
+ if (['state', 'code', 'error'].some(key => query.getAll(key).length > 1) ||
114
+ !query.get('state') || (!!query.get('code') === !!query.get('error')) ||
115
+ (query.has('code') && query.has('error'))) {
116
+ reply(400);
117
+ return;
118
+ }
119
+ const registration = registrations.get(query.get('state'));
120
+ if (!registration || registration.path !== request.url.split('?')[0] || uri.hash ||
121
+ registration.expiresAt.getTime() <= Date.now()) {
122
+ reply(400);
123
+ return;
124
+ }
125
+ registration.close();
126
+ try {
127
+ await registration.onCallback(query.has('code') ? { code: query.get('code') } : { error: query.get('error') });
128
+ reply(200, !query.has('error'));
129
+ }
130
+ catch {
131
+ reply(500);
132
+ }
133
+ }
134
+ }
135
+ exports.LoopbackAuthorizationCallbackReceiver = LoopbackAuthorizationCallbackReceiver;
136
+ //# sourceMappingURL=LoopbackAuthorizationCallbackReceiver.js.map
@@ -4,12 +4,14 @@ import type { AuthContext } from '../../auth/AuthContext';
4
4
  import type { ConnectCredentialRecord, PodCredentialRepository } from './index';
5
5
  export interface OAuthConnectCredentialStoreOptions {
6
6
  provider: string;
7
+ offeringId: string;
7
8
  deployment: GatewayDeployment;
8
9
  credentialRepository: PodCredentialRepository;
9
10
  vault: CredentialVault;
10
11
  }
11
12
  export declare class OAuthConnectCredentialStore {
12
13
  private readonly provider;
14
+ private readonly offeringId;
13
15
  private readonly credentialRepository;
14
16
  private readonly vault;
15
17
  constructor(options: OAuthConnectCredentialStoreOptions);