@undefineds.co/xpod 0.3.31 → 0.3.33

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 (218) hide show
  1. package/dist/api/auth/AuthContext.d.ts +3 -2
  2. package/dist/api/auth/AuthContext.js +2 -1
  3. package/dist/api/auth/AuthContext.js.map +1 -1
  4. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
  5. package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
  6. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  7. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
  8. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
  9. package/dist/api/chatkit/pod-store.d.ts +3 -0
  10. package/dist/api/chatkit/pod-store.js +93 -59
  11. package/dist/api/chatkit/pod-store.js.map +1 -1
  12. package/dist/api/chatkit/schema.d.ts +5 -6
  13. package/dist/api/container/business-token.d.ts +1 -1
  14. package/dist/api/container/business-token.js +5 -1
  15. package/dist/api/container/business-token.js.map +1 -1
  16. package/dist/api/container/common.js +14 -10
  17. package/dist/api/container/common.js.map +1 -1
  18. package/dist/api/container/routes.js +16 -3
  19. package/dist/api/container/routes.js.map +1 -1
  20. package/dist/api/container/types.d.ts +2 -4
  21. package/dist/api/container/types.js.map +1 -1
  22. package/dist/api/handlers/ChatHandler.d.ts +1 -1
  23. package/dist/api/handlers/ChatHandler.js +1 -1
  24. package/dist/api/handlers/ChatHandler.js.map +1 -1
  25. package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
  26. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  27. package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
  28. package/dist/api/handlers/PodManagementHandler.js +114 -12
  29. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  30. package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
  31. package/dist/api/handlers/ProvisionHandler.js +339 -32
  32. package/dist/api/handlers/ProvisionHandler.js.map +1 -1
  33. package/dist/api/handlers/QuotaHandler.js +0 -12
  34. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  35. package/dist/api/handlers/index.d.ts +0 -1
  36. package/dist/api/handlers/index.js +0 -1
  37. package/dist/api/handlers/index.js.map +1 -1
  38. package/dist/api/matrix/PodMatrixStore.js +26 -21
  39. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  40. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  41. package/dist/api/runs/schema.d.ts +5 -7
  42. package/dist/api/runs/store.js +6 -4
  43. package/dist/api/runs/store.js.map +1 -1
  44. package/dist/api/runtime.js +3 -3
  45. package/dist/api/runtime.js.map +1 -1
  46. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  47. package/dist/api/tasks/schema.d.ts +17 -13
  48. package/dist/api/tasks/schema.js +7 -2
  49. package/dist/api/tasks/schema.js.map +1 -1
  50. package/dist/api/tasks/store.js +1 -2
  51. package/dist/api/tasks/store.js.map +1 -1
  52. package/dist/components/context.jsonld +12 -0
  53. package/dist/edge/EdgeNodeAgent.d.ts +1 -1
  54. package/dist/edge/EdgeNodeAgent.js +1 -1
  55. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  56. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
  57. package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
  58. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  59. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
  60. package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
  61. package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
  62. package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
  63. package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
  64. package/dist/http/ClusterIngressRouter.js +6 -3
  65. package/dist/http/ClusterIngressRouter.js.map +1 -1
  66. package/dist/http/ClusterWebSocketConfigurator.js +6 -2
  67. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  68. package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
  69. package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
  70. package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
  71. package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
  72. package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
  73. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  74. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
  75. package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
  76. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  77. package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
  78. package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
  79. package/dist/http/search/SearchHttpHandler.js +2 -2
  80. package/dist/http/search/SearchHttpHandler.js.map +1 -1
  81. package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
  82. package/dist/identity/drizzle/AccountRepository.js +9 -113
  83. package/dist/identity/drizzle/AccountRepository.js.map +1 -1
  84. package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
  85. package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
  86. package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
  87. package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
  88. package/dist/identity/drizzle/DdnsRepository.js +13 -49
  89. package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
  90. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
  91. package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
  92. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  93. package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
  94. package/dist/identity/drizzle/PodLookupRepository.js +103 -126
  95. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  96. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
  97. package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
  98. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
  99. package/dist/identity/drizzle/db.d.ts +2 -1
  100. package/dist/identity/drizzle/db.js +173 -297
  101. package/dist/identity/drizzle/db.js.map +1 -1
  102. package/dist/identity/drizzle/schema.pg.d.ts +3 -11
  103. package/dist/identity/drizzle/schema.pg.js +10 -45
  104. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  105. package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
  106. package/dist/identity/drizzle/schema.sqlite.js +13 -46
  107. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  108. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
  109. package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
  110. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
  111. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
  112. package/dist/provision/ProvisionCodeCodec.js +10 -1
  113. package/dist/provision/ProvisionCodeCodec.js.map +1 -1
  114. package/dist/provision/ProvisionPodCreator.d.ts +8 -2
  115. package/dist/provision/ProvisionPodCreator.js +134 -41
  116. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  117. package/dist/provision/ProvisionPodCreator.jsonld +38 -3
  118. package/dist/quota/DrizzleQuotaService.d.ts +0 -4
  119. package/dist/quota/DrizzleQuotaService.js +1 -21
  120. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  121. package/dist/quota/DrizzleQuotaService.jsonld +0 -16
  122. package/dist/quota/NoopQuotaService.d.ts +0 -4
  123. package/dist/quota/NoopQuotaService.js +0 -8
  124. package/dist/quota/NoopQuotaService.js.map +1 -1
  125. package/dist/quota/NoopQuotaService.jsonld +0 -16
  126. package/dist/quota/QuotaService.d.ts +0 -4
  127. package/dist/quota/QuotaService.js.map +1 -1
  128. package/dist/quota/QuotaService.jsonld +0 -16
  129. package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
  130. package/dist/service/EdgeNodeSignalClient.js +0 -4
  131. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  132. package/dist/service/PodMigrationService.d.ts +2 -2
  133. package/dist/service/PodMigrationService.js +4 -4
  134. package/dist/service/PodMigrationService.js.map +1 -1
  135. package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
  136. package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
  137. package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
  138. package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
  139. package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
  140. package/dist/storage/quota/UsageRepository.d.ts +10 -32
  141. package/dist/storage/quota/UsageRepository.js +84 -281
  142. package/dist/storage/quota/UsageRepository.js.map +1 -1
  143. package/dist/storage/vector/VectorIndexingListener.js +2 -2
  144. package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
  145. package/dist/subdomain/SubdomainService.d.ts +1 -1
  146. package/dist/subdomain/SubdomainService.js +1 -1
  147. package/dist/subdomain/SubdomainService.js.map +1 -1
  148. package/dist/subdomain/SubdomainService.jsonld +1 -1
  149. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts +21 -0
  150. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts.map +1 -0
  151. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js +85 -0
  152. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js.map +1 -0
  153. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts +10 -0
  154. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts.map +1 -0
  155. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js +365 -0
  156. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js.map +1 -0
  157. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts +1 -0
  158. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts.map +1 -1
  159. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js +3 -1
  160. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js.map +1 -1
  161. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
  162. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js +5 -1
  163. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js.map +1 -1
  164. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts +2 -0
  165. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts.map +1 -1
  166. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js +2 -1
  167. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js.map +1 -1
  168. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts +18 -0
  169. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts.map +1 -1
  170. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js +234 -10
  171. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js.map +1 -1
  172. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts +13 -0
  173. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts.map +1 -1
  174. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js +19 -0
  175. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js.map +1 -1
  176. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts +21 -0
  177. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts.map +1 -0
  178. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js +78 -0
  179. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js.map +1 -0
  180. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts +10 -0
  181. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts.map +1 -0
  182. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js +362 -0
  183. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js.map +1 -0
  184. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts +1 -0
  185. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts.map +1 -1
  186. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js +1 -0
  187. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js.map +1 -1
  188. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
  189. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js +5 -1
  190. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
  191. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts +2 -0
  192. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts.map +1 -1
  193. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js +1 -0
  194. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js.map +1 -1
  195. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts +18 -0
  196. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts.map +1 -1
  197. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js +225 -10
  198. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js.map +1 -1
  199. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts +13 -0
  200. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts.map +1 -1
  201. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js +19 -0
  202. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js.map +1 -1
  203. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts +5 -4
  204. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts.map +1 -1
  205. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js +4 -3
  206. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js.map +1 -1
  207. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts +5 -4
  208. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts.map +1 -1
  209. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js +20 -3
  210. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js.map +1 -1
  211. package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
  212. package/package.json +3 -3
  213. package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
  214. package/dist/api/handlers/ApiKeyHandler.js +0 -153
  215. package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
  216. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
  217. package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
  218. package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"QuotaAdminHttpHandler.js","sourceRoot":"","sources":["../../../src/http/quota/QuotaAdminHttpHandler.ts"],"names":[],"mappings":";;;AAAA,wEAAwE;AACxE,iEAAqD;AACrD,8DAAsD;AAEtD,8DAOiC;AACjC,kDAAgE;AAChE,gFAA6E;AAC7E,wFAAqF;AAcrF,MAAa,qBAAsB,SAAQ,8BAAW;IAQpD,YAAmB,OAAqC;QACtD,KAAK,EAAE,CAAC;QARS,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAC9B,WAAM,GAAG,IAAA,gDAAwB,GAAE,CAAC;QAQnD,MAAM,EAAE,GAAG,IAAA,wBAAmB,EAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACtD,IAAI,CAAC,WAAW,GAAG,IAAI,qCAAiB,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,6CAAqB,CAAC,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,aAAa,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;IAEe,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,EAAoB;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,0CAAuB,CAAC,4BAA4B,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAEe,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAoB;QAClE,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACvD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,CAAC,CAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,4CAAyB,CAAC,CAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAE,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;QAE/D,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,KAAK;gBACR,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBACvC,MAAM;YACR,KAAK,KAAK;gBACR,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAChD,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAC1C,MAAM;QACV,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,MAAmB,EAAE,QAAsB;QACjE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE;gBAC5B,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,MAAM,CAAC,EAAE;gBACpB,UAAU,EAAE,KAAK,IAAI,IAAI;aAC1B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,sCAAmB,CAAC,yBAAyB,CAAC,CAAC;QAC3D,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,MAAM,CAAC,EAAE;YAChB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;YAChC,UAAU,EAAE,KAAK,IAAI,IAAI;SAC1B,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,MAAmB,EAAE,OAAoB,EAAE,QAAsB;QACvF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,IAAI,sCAAmB,CAAC,iCAAiC,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,OAAO,GAAG,IAA+B,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,sCAAmB,CAAC,yBAAyB,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE;gBAC5B,MAAM,EAAE,SAAS;gBACjB,UAAU,EAAE,MAAM,CAAC,IAAI;gBACvB,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACnB,UAAU,EAAE,MAAM,IAAI,IAAI;aAC3B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAE9D,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,UAAU,EAAE,MAAM,IAAI,IAAI;SAC3B,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,MAAmB,EAAE,QAAsB;QACpE,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,sCAAmB,CAAC,yBAAyB,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,QAAQ,EAAE,MAAM,CAAC,EAAE;SACpB,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,OAAoB;QAClD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACpD,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,wCAAqB,CAAC,6BAA6B,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,OAAgC,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAuC,CAAC;QACnF,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,IAAI,wCAAqB,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,wCAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,qCAAkB,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,QAAgB;QAClC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,sCAAmB,CAAC,qDAAqD,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,CAAE,KAAK,EAAE,UAAU,CAAE,GAAG,QAAQ,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,sCAAmB,CAAC,qBAAqB,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YACzB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;QACjE,CAAC;QACD,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACrB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,sCAAmB,CAAC,sBAAsB,CAAC,CAAC;IACxD,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,OAAoB;QACzC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,IAAI,sCAAmB,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,IAA6B;QAChD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,sCAAmB,CAAC,+BAA+B,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAqB,CAAC;QAC9C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,sCAAmB,CAAC,mDAAmD,CAAC,CAAC;QACrF,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,YAAY,CAAC,QAAsB;QACzC,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QACtD,QAAQ,CAAC,GAAG,EAAE,CAAC;IACjB,CAAC;IAEO,SAAS,CAAC,QAAsB,EAAE,MAAc,EAAE,OAAgB;QACxE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC;QAC7B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAC;QACtE,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAChD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACxC,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,OAAoB;QACzC,OAAO,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC5B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBACnC,IAAI,IAAI,KAAK,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACvC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,OAAoB;QACjC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;QAC/E,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACjG,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3E,MAAM,MAAM,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAChG,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC;QAClC,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,MAAM,UAAU,EAAE,CAAC,CAAC;IACtD,CAAC;IAEO,YAAY,CAAC,OAAgC;QACnD,MAAM,SAAS,GAAG,CAAC,GAAW,EAAsB,EAAE;YACpD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAClD,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5E,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAChD,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AA9PD,sDA8PC","sourcesContent":["import { createSolidTokenVerifier } from '@solid/access-token-verifier';\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n \n BadRequestHttpError,\n ForbiddenHttpError,\n MethodNotAllowedHttpError,\n NotImplementedHttpError,\n UnauthorizedHttpError,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { AccountRepository } from '../../identity/drizzle/AccountRepository';\nimport { AccountRoleRepository } from '../../identity/drizzle/AccountRoleRepository';\nimport type { QuotaService } from '../../quota/QuotaService';\n\ninterface QuotaAdminHttpHandlerOptions {\n identityDbUrl: string;\n basePath?: string;\n roleRepository?: AccountRoleRepository;\n quotaService: QuotaService;\n}\n\ntype QuotaTarget =\n | { type: 'account'; id: string }\n | { type: 'pod'; id: string };\n\nexport class QuotaAdminHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n private readonly verify = createSolidTokenVerifier();\n private readonly accountRepo: AccountRepository;\n private readonly roleRepo: AccountRoleRepository;\n private readonly quotaService: QuotaService;\n private readonly basePath: string;\n\n public constructor(options: QuotaAdminHttpHandlerOptions) {\n super();\n const db = getIdentityDatabase(options.identityDbUrl);\n this.accountRepo = new AccountRepository(db);\n this.roleRepo = options.roleRepository ?? new AccountRoleRepository(db);\n this.basePath = options.basePath ?? '/api/quota/';\n this.quotaService = options.quotaService;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.getUrl(request).pathname;\n if (!path.startsWith(this.basePath)) {\n throw new NotImplementedHttpError('Not a quota admin request.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (![ 'GET', 'PUT', 'DELETE' ].includes(method)) {\n throw new MethodNotAllowedHttpError([ 'GET', 'PUT', 'DELETE', 'OPTIONS' ]);\n }\n\n await this.authenticateAdmin(request);\n\n const target = this.parseTarget(this.getUrl(request).pathname);\n\n switch (method) {\n case 'GET':\n await this.handleGet(target, response);\n break;\n case 'PUT':\n await this.handlePut(target, request, response);\n break;\n case 'DELETE':\n await this.handleDelete(target, response);\n break;\n }\n }\n\n private async handleGet(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'account') {\n const quota = await this.quotaService.getAccountLimit(target.id);\n this.writeJson(response, 200, {\n type: 'account',\n accountId: target.id,\n quotaLimit: quota ?? null,\n });\n return;\n }\n\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n const quota = await this.quotaService.getPodLimit(target.id);\n this.writeJson(response, 200, {\n type: 'pod',\n podId: target.id,\n accountId: podInfo.accountId,\n baseUrl: podInfo.baseUrl ?? null,\n quotaLimit: quota ?? null,\n });\n }\n\n private async handlePut(target: QuotaTarget, request: HttpRequest, response: HttpResponse): Promise<void> {\n const body = await this.readJson(request);\n if (body == null || typeof body !== 'object') {\n throw new BadRequestHttpError('Request body must be an object.');\n }\n const payload = body as Record<string, unknown>;\n const quota = this.extractQuota(payload);\n\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountLimit(target.id, quota);\n const latest = await this.quotaService.getAccountLimit(target.id);\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quotaLimit: latest ?? null,\n });\n return;\n }\n\n await this.quotaService.setPodLimit(target.id, quota);\n const latest = await this.quotaService.getPodLimit(target.id);\n\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quotaLimit: latest ?? null,\n });\n }\n\n private async handleDelete(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountLimit(target.id, null);\n } else {\n await this.quotaService.setPodLimit(target.id, null);\n }\n this.writeJson(response, 200, {\n status: 'cleared',\n targetType: target.type,\n targetId: target.id,\n });\n }\n\n private async authenticateAdmin(request: HttpRequest): Promise<void> {\n const authorization = request.headers.authorization;\n if (!authorization || !authorization.startsWith('Bearer ')) {\n throw new UnauthorizedHttpError('Quota管理接口需要携带 Bearer Token。');\n }\n let payload: Record<string, unknown>;\n try {\n payload = await this.verify(authorization) as unknown as Record<string, unknown>;\n } catch (error: unknown) {\n throw new UnauthorizedHttpError('无法验证访问令牌。', { cause: error });\n }\n const webId = this.extractWebId(payload);\n if (!webId) {\n throw new UnauthorizedHttpError('访问令牌缺少 webid。');\n }\n const context = await this.roleRepo.findByWebId(webId);\n if (!context || !context.roles.includes('admin')) {\n throw new ForbiddenHttpError('仅限管理员修改配额。');\n }\n }\n\n private parseTarget(pathname: string): QuotaTarget {\n const relative = pathname.slice(this.basePath.length);\n const segments = relative.split('/').filter(Boolean);\n if (segments.length !== 2) {\n throw new BadRequestHttpError('Quota path must match /accounts/{id} or /pods/{id}.');\n }\n const [ scope, identifier ] = segments;\n if (!identifier) {\n throw new BadRequestHttpError('Missing identifier.');\n }\n if (scope === 'accounts') {\n return { type: 'account', id: decodeURIComponent(identifier) };\n }\n if (scope === 'pods') {\n return { type: 'pod', id: decodeURIComponent(identifier) };\n }\n throw new BadRequestHttpError('Unknown quota scope.');\n }\n\n private async readJson(request: HttpRequest): Promise<unknown> {\n const body = await this.readBody(request);\n if (!body) {\n return undefined;\n }\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new BadRequestHttpError('Body must contain valid JSON.', { cause: error });\n }\n }\n\n private extractQuota(body: Record<string, unknown>): number | null {\n if (!Object.prototype.hasOwnProperty.call(body, 'quotaLimit')) {\n throw new BadRequestHttpError('Body must include quotaLimit.');\n }\n const quotaValue = body.quotaLimit as unknown;\n if (quotaValue === null) {\n return null;\n }\n if (typeof quotaValue !== 'number' || !Number.isFinite(quotaValue) || quotaValue < 0) {\n throw new BadRequestHttpError('quotaLimit must be a non-negative number or null.');\n }\n return quotaValue;\n }\n\n private writeOptions(response: HttpResponse): void {\n response.statusCode = 204;\n response.setHeader('Allow', 'GET,PUT,DELETE,OPTIONS');\n response.end();\n }\n\n private writeJson(response: HttpResponse, status: number, payload: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.setHeader('Cache-Control', 'no-store');\n response.end(JSON.stringify(payload));\n }\n\n private async readBody(request: HttpRequest): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => resolve(data));\n request.on('error', reject);\n });\n }\n\n private getUrl(request: HttpRequest): URL {\n const hostHeader = request.headers.host ?? request.headers.Host ?? 'localhost';\n const protoHeader = request.headers['x-forwarded-proto'] ?? request.headers['X-Forwarded-Proto'];\n const protocol = Array.isArray(protoHeader) ? protoHeader[0] : protoHeader;\n const scheme = typeof protocol === 'string' ? protocol.split(',')[0]?.trim() ?? 'http' : 'http';\n const rawUrl = request.url ?? '/';\n return new URL(rawUrl, `${scheme}://${hostHeader}`);\n }\n\n private extractWebId(payload: Record<string, unknown>): string | undefined {\n const getString = (key: string): string | undefined => {\n const value = payload[key];\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n };\n const direct = getString('webid') ?? getString('webId') ?? getString('sub');\n if (direct) {\n return direct;\n }\n const clientId = getString('client_id');\n if (clientId && clientId.startsWith('https://')) {\n return clientId;\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"QuotaAdminHttpHandler.js","sourceRoot":"","sources":["../../../src/http/quota/QuotaAdminHttpHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSolidTokenVerifier } from '@solid/access-token-verifier';\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n BadRequestHttpError,\n ForbiddenHttpError,\n MethodNotAllowedHttpError,\n NotImplementedHttpError,\n UnauthorizedHttpError,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { AccountRepository } from '../../identity/drizzle/AccountRepository';\nimport { AccountRoleRepository } from '../../identity/drizzle/AccountRoleRepository';\nimport type { AccountQuota, QuotaService } from '../../quota/QuotaService';\n\ninterface QuotaAdminHttpHandlerOptions {\n identityDbUrl: string;\n basePath?: string;\n roleRepository?: AccountRoleRepository;\n quotaService: QuotaService;\n}\n\ntype QuotaTarget =\n | { type: 'account'; id: string }\n | { type: 'pod'; id: string };\n\nexport class QuotaAdminHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n private readonly verify = createSolidTokenVerifier();\n private readonly accountRepo: AccountRepository;\n private readonly roleRepo: AccountRoleRepository;\n private readonly quotaService: QuotaService;\n private readonly basePath: string;\n\n public constructor(options: QuotaAdminHttpHandlerOptions) {\n super();\n const db = getIdentityDatabase(options.identityDbUrl);\n this.accountRepo = new AccountRepository(db);\n this.roleRepo = options.roleRepository ?? new AccountRoleRepository(db);\n this.basePath = options.basePath ?? '/api/quota/';\n this.quotaService = options.quotaService;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.getUrl(request).pathname;\n if (!path.startsWith(this.basePath)) {\n throw new NotImplementedHttpError('Not a quota admin request.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (![ 'GET', 'PUT', 'DELETE' ].includes(method)) {\n throw new MethodNotAllowedHttpError([ 'GET', 'PUT', 'DELETE', 'OPTIONS' ]);\n }\n\n await this.authenticateAdmin(request);\n\n const target = this.parseTarget(this.getUrl(request).pathname);\n\n switch (method) {\n case 'GET':\n await this.handleGet(target, response);\n break;\n case 'PUT':\n await this.handlePut(target, request, response);\n break;\n case 'DELETE':\n await this.handleDelete(target, response);\n break;\n }\n }\n\n private async handleGet(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'account') {\n const quota = await this.quotaService.getAccountQuota(target.id);\n this.writeJson(response, 200, {\n type: 'account',\n accountId: target.id,\n quota,\n });\n return;\n }\n\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n const quota = await this.quotaService.getPodQuota(target.id);\n this.writeJson(response, 200, {\n type: 'pod',\n podId: target.id,\n accountId: podInfo.accountId,\n baseUrl: podInfo.baseUrl ?? null,\n quota,\n });\n }\n\n private async handlePut(target: QuotaTarget, request: HttpRequest, response: HttpResponse): Promise<void> {\n const body = await this.readJson(request);\n if (body == null || typeof body !== 'object') {\n throw new BadRequestHttpError('Request body must be an object.');\n }\n const payload = body as Record<string, unknown>;\n const quota = this.extractQuota(payload);\n\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountQuota(target.id, quota);\n const latest = await this.quotaService.getAccountQuota(target.id);\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quota: latest,\n });\n return;\n }\n\n await this.quotaService.setPodQuota(target.id, quota);\n const latest = await this.quotaService.getPodQuota(target.id);\n\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quota: latest,\n });\n }\n\n private async handleDelete(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.clearAccountQuota(target.id);\n } else {\n await this.quotaService.clearPodQuota(target.id);\n }\n this.writeJson(response, 200, {\n status: 'cleared',\n targetType: target.type,\n targetId: target.id,\n });\n }\n\n private async authenticateAdmin(request: HttpRequest): Promise<void> {\n const authorization = request.headers.authorization;\n if (!authorization || !authorization.startsWith('Bearer ')) {\n throw new UnauthorizedHttpError('Quota管理接口需要携带 Bearer Token。');\n }\n let payload: Record<string, unknown>;\n try {\n payload = await this.verify(authorization) as unknown as Record<string, unknown>;\n } catch (error: unknown) {\n throw new UnauthorizedHttpError('无法验证访问令牌。', { cause: error });\n }\n const webId = this.extractWebId(payload);\n if (!webId) {\n throw new UnauthorizedHttpError('访问令牌缺少 webid。');\n }\n const context = await this.roleRepo.findByWebId(webId);\n if (!context || !context.roles.includes('admin')) {\n throw new ForbiddenHttpError('仅限管理员修改配额。');\n }\n }\n\n private parseTarget(pathname: string): QuotaTarget {\n const relative = pathname.slice(this.basePath.length);\n const segments = relative.split('/').filter(Boolean);\n if (segments.length !== 2) {\n throw new BadRequestHttpError('Quota path must match /accounts/{id} or /pods/{id}.');\n }\n const [ scope, identifier ] = segments;\n if (!identifier) {\n throw new BadRequestHttpError('Missing identifier.');\n }\n if (scope === 'accounts') {\n return { type: 'account', id: decodeURIComponent(identifier) };\n }\n if (scope === 'pods') {\n return { type: 'pod', id: decodeURIComponent(identifier) };\n }\n throw new BadRequestHttpError('Unknown quota scope.');\n }\n\n private async readJson(request: HttpRequest): Promise<unknown> {\n const body = await this.readBody(request);\n if (!body) {\n return undefined;\n }\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new BadRequestHttpError('Body must contain valid JSON.', { cause: error });\n }\n }\n\n private extractQuota(body: Record<string, unknown>): Partial<AccountQuota> {\n const quota: Partial<AccountQuota> = {};\n let hasQuotaField = false;\n for (const field of [ 'storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly' ] as const) {\n if (!Object.prototype.hasOwnProperty.call(body, field)) {\n continue;\n }\n const value = body[field];\n if (value !== null && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {\n throw new BadRequestHttpError(`${field} must be a non-negative number or null.`);\n }\n quota[field] = value;\n hasQuotaField = true;\n }\n if (!hasQuotaField) {\n throw new BadRequestHttpError('Body must include at least one quota field.');\n }\n return quota;\n }\n\n private writeOptions(response: HttpResponse): void {\n response.statusCode = 204;\n response.setHeader('Allow', 'GET,PUT,DELETE,OPTIONS');\n response.end();\n }\n\n private writeJson(response: HttpResponse, status: number, payload: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.setHeader('Cache-Control', 'no-store');\n response.end(JSON.stringify(payload));\n }\n\n private async readBody(request: HttpRequest): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => resolve(data));\n request.on('error', reject);\n });\n }\n\n private getUrl(request: HttpRequest): URL {\n const hostHeader = request.headers.host ?? request.headers.Host ?? 'localhost';\n const protoHeader = request.headers['x-forwarded-proto'] ?? request.headers['X-Forwarded-Proto'];\n const protocol = Array.isArray(protoHeader) ? protoHeader[0] : protoHeader;\n const scheme = typeof protocol === 'string' ? protocol.split(',')[0]?.trim() ?? 'http' : 'http';\n const rawUrl = request.url ?? '/';\n return new URL(rawUrl, `${scheme}://${hostHeader}`);\n }\n\n private extractWebId(payload: Record<string, unknown>): string | undefined {\n const getString = (key: string): string | undefined => {\n const value = payload[key];\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n };\n const direct = getString('webid') ?? getString('webId') ?? getString('sub');\n if (direct) {\n return direct;\n }\n const clientId = getString('client_id');\n if (clientId && clientId.startsWith('https://')) {\n return clientId;\n }\n return undefined;\n }\n}\n"]}
@@ -173,8 +173,8 @@ class SearchHttpHandler extends community_server_1.HttpHandler {
173
173
  async getAiCredential(podBaseUrl) {
174
174
  try {
175
175
  const query = `
176
- PREFIX cred: <${models_1.XPOD_CREDENTIAL.NAMESPACE}>
177
- PREFIX ai: <${models_1.XPOD_AI.NAMESPACE}>
176
+ PREFIX cred: <${models_1.UDFS.NAMESPACE}>
177
+ PREFIX ai: <${models_1.UDFS.NAMESPACE}>
178
178
  SELECT ?apiKey ?baseUrl ?provider ?proxyUrl WHERE {
179
179
  ?cred a cred:Credential ;
180
180
  cred:service "ai" ;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchHttpHandler.js","sourceRoot":"","sources":["../../../src/http/search/SearchHttpHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SearchHttpHandler - 语义搜索 HTTP 处理器\n *\n * 提供 /-/search 端点,支持基于向量的语义搜索。\n *\n * 端点:\n * - GET {path}/-/search?q=... 简单搜索\n * - POST {path}/-/search 复杂搜索(支持 filter 等)\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n NotImplementedHttpError,\n MethodNotAllowedHttpError,\n HttpError,\n IdentifierSetMultiMap,\n} from '@solid/community-server';\nimport { PERMISSIONS } from '@solidlab/policy-engine';\nimport type { CredentialsExtractor, PermissionReader, Authorizer, ResourceIdentifier } from '@solid/community-server';\nimport type { VectorStore } from '../../storage/vector/VectorStore';\nimport type { EmbeddingService } from '../../ai/service/EmbeddingService';\nimport type { SparqlEngine } from '../../storage/sparql/SubgraphQueryEngine';\nimport type { AiCredential } from '../../ai/service/types';\nimport type { VectorSearchOptions } from '../../storage/vector/types';\nimport { XPOD_AI, XPOD_CREDENTIAL, normalizeAIConfigProviderId } from '@undefineds.co/models';\n\nconst ALLOWED_METHODS = ['GET', 'POST', 'OPTIONS'];\n\n// ============================================\n// 请求/响应类型\n// ============================================\n\ninterface SearchRequest {\n /** 查询文本 */\n query?: string;\n /** 预计算的查询向量 */\n vector?: number[];\n /** 返回结果数量,默认 10 */\n limit?: number;\n /** 相似度阈值 (0-1) */\n threshold?: number;\n /** 过滤条件 */\n filter?: {\n type?: string;\n graphPrefix?: string;\n subjectPrefix?: string;\n };\n /** embedding 模型 */\n model?: string;\n}\n\ninterface SearchResult {\n /** 资源 URI */\n subject: string;\n /** 相似度分数 (0-1) */\n score: number;\n /** 距离 */\n distance?: number;\n /** 文本片段 */\n snippet?: string;\n}\n\ninterface SearchResponse {\n results: SearchResult[];\n model: string;\n took_ms: number;\n}\n\n// ============================================\n// 错误处理\n// ============================================\n\ntype SearchErrorCode =\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'NO_CREDENTIAL'\n | 'EMBEDDING_ERROR'\n | 'SEARCH_ERROR';\n\nclass SearchApiError extends Error {\n constructor(\n public readonly code: SearchErrorCode,\n public readonly statusCode: number,\n message: string,\n ) {\n super(message);\n this.name = 'SearchApiError';\n }\n\n static invalidRequest(message: string): SearchApiError {\n return new SearchApiError('INVALID_REQUEST', 400, message);\n }\n\n static noCredential(): SearchApiError {\n return new SearchApiError('NO_CREDENTIAL', 400, 'No AI credential found. Please configure AI credentials in your Pod settings.');\n }\n\n static embeddingError(message: string): SearchApiError {\n return new SearchApiError('EMBEDDING_ERROR', 502, `Embedding generation failed: ${message}`);\n }\n\n static searchError(message: string): SearchApiError {\n return new SearchApiError('SEARCH_ERROR', 500, `Search failed: ${message}`);\n }\n}\n\n// ============================================\n// Handler\n// ============================================\n\nexport interface SearchHttpHandlerOptions {\n sidecarPath?: string;\n defaultModel?: string;\n defaultLimit?: number;\n}\n\nexport class SearchHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n\n private readonly vectorStore: VectorStore;\n private readonly embeddingService: EmbeddingService;\n private readonly sparqlEngine: SparqlEngine;\n private readonly credentialsExtractor: CredentialsExtractor;\n private readonly permissionReader: PermissionReader;\n private readonly authorizer: Authorizer;\n private readonly sidecarPath: string;\n private readonly defaultModel: string;\n private readonly defaultLimit: number;\n\n public constructor(\n vectorStore: VectorStore,\n embeddingService: EmbeddingService,\n sparqlEngine: SparqlEngine,\n credentialsExtractor: CredentialsExtractor,\n permissionReader: PermissionReader,\n authorizer: Authorizer,\n options: SearchHttpHandlerOptions = {},\n ) {\n super();\n this.vectorStore = vectorStore;\n this.embeddingService = embeddingService;\n this.sparqlEngine = sparqlEngine;\n this.credentialsExtractor = credentialsExtractor;\n this.permissionReader = permissionReader;\n this.authorizer = authorizer;\n this.sidecarPath = options.sidecarPath ?? '/-/search';\n this.defaultModel = options.defaultModel ?? 'text-embedding-004';\n this.defaultLimit = options.defaultLimit ?? 10;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.parseUrl(request).pathname;\n if (!path.includes(this.sidecarPath)) {\n throw new NotImplementedHttpError('Request is not targeting a search endpoint.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (!ALLOWED_METHODS.includes(method)) {\n throw new MethodNotAllowedHttpError(ALLOWED_METHODS);\n }\n\n try {\n const url = this.parseUrl(request);\n const path = decodeURIComponent(url.pathname);\n\n const sidecarIndex = path.indexOf(this.sidecarPath);\n if (sidecarIndex === -1) {\n throw new NotImplementedHttpError('Request is not targeting a search endpoint.');\n }\n\n // 提取 base path(sidecar 之前的路径)\n let basePath = path.slice(0, sidecarIndex);\n if (!basePath.endsWith('/')) {\n basePath = `${basePath}/`;\n }\n\n const origin = `${url.protocol}//${url.host}`;\n const baseUrl = `${origin}${basePath}`;\n\n this.logger.debug(`Search request: ${method} ${path}, baseUrl=${baseUrl}`);\n\n // 鉴权\n await this.authorizeFor(baseUrl, request, [PERMISSIONS.Read]);\n\n // 解析请求\n const searchRequest = await this.parseSearchRequest(request, url);\n\n // 执行搜索\n const result = await this.executeSearch(searchRequest, baseUrl);\n\n this.sendJsonResponse(response, result);\n } catch (error: unknown) {\n this.handleError(response, error);\n }\n }\n\n /**\n * 解析搜索请求\n */\n private async parseSearchRequest(request: HttpRequest, url: URL): Promise<SearchRequest> {\n const method = (request.method ?? 'GET').toUpperCase();\n\n if (method === 'GET') {\n // GET 请求从 query string 解析\n const query = url.searchParams.get('q') || url.searchParams.get('query');\n const limit = url.searchParams.get('limit');\n const threshold = url.searchParams.get('threshold');\n const model = url.searchParams.get('model');\n\n if (!query) {\n throw SearchApiError.invalidRequest('Missing query parameter \"q\"');\n }\n\n return {\n query,\n limit: limit ? parseInt(limit, 10) : undefined,\n threshold: threshold ? parseFloat(threshold) : undefined,\n model: model || undefined,\n };\n }\n\n // POST 请求从 body 解析\n const body = await this.readJsonBody<SearchRequest>(request);\n\n if (!body.query && !body.vector) {\n throw SearchApiError.invalidRequest('Either \"query\" or \"vector\" is required');\n }\n\n return body;\n }\n\n /**\n * 执行搜索\n */\n private async executeSearch(request: SearchRequest, baseUrl: string): Promise<SearchResponse> {\n const startTime = Date.now();\n const model = request.model || this.defaultModel;\n\n let queryVector = request.vector;\n\n // 如果提供了 query 文本,需要生成 embedding\n if (request.query && !queryVector) {\n // 获取 AI 凭据\n const credential = await this.getAiCredential(baseUrl);\n if (!credential) {\n throw SearchApiError.noCredential();\n }\n\n try {\n queryVector = await this.embeddingService.embed(request.query, credential, model);\n } catch (error) {\n throw SearchApiError.embeddingError(error instanceof Error ? error.message : String(error));\n }\n }\n\n if (!queryVector) {\n throw SearchApiError.invalidRequest('Failed to generate query vector');\n }\n\n // 执行向量搜索\n const searchOptions: VectorSearchOptions = {\n limit: request.limit ?? this.defaultLimit,\n threshold: request.threshold,\n };\n\n try {\n const vectorResults = await this.vectorStore.search(model, queryVector, searchOptions);\n\n // 转换结果\n const results: SearchResult[] = vectorResults.map((r) => ({\n subject: this.vectorIdToSubject(r.id, baseUrl),\n score: r.score,\n distance: r.distance,\n }));\n\n return {\n results,\n model,\n took_ms: Date.now() - startTime,\n };\n } catch (error) {\n throw SearchApiError.searchError(error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * 获取 AI 凭据\n */\n private async getAiCredential(podBaseUrl: string): Promise<AiCredential | null> {\n try {\n const query = `\n PREFIX cred: <${XPOD_CREDENTIAL.NAMESPACE}>\n PREFIX ai: <${XPOD_AI.NAMESPACE}>\n SELECT ?apiKey ?baseUrl ?provider ?proxyUrl WHERE {\n ?cred a cred:Credential ;\n cred:service \"ai\" ;\n cred:status \"active\" ;\n cred:apiKey ?apiKey .\n OPTIONAL { ?cred cred:provider ?provider }\n OPTIONAL {\n ?cred cred:provider ?provider .\n ?provider ai:baseUrl ?baseUrl .\n }\n OPTIONAL {\n ?cred cred:provider ?provider .\n ?provider ai:proxyUrl ?proxyUrl .\n }\n } LIMIT 1\n `;\n\n const bindingsStream = await this.sparqlEngine.queryBindings(query, podBaseUrl);\n\n for await (const binding of bindingsStream) {\n const apiKey = binding.get('apiKey');\n const baseUrl = binding.get('baseUrl');\n const provider = binding.get('provider');\n const proxyUrl = binding.get('proxyUrl');\n\n if (apiKey) {\n const providerName = normalizeAIConfigProviderId(provider?.value || 'google') || 'google';\n\n return {\n apiKey: apiKey.value,\n baseUrl: baseUrl?.value,\n provider: providerName,\n proxyUrl: proxyUrl?.value,\n };\n }\n }\n\n return null;\n } catch (error) {\n this.logger.error(`Failed to query AI credential: ${error}`);\n return null;\n }\n }\n\n /**\n * 将向量 ID 转换回 subject URI\n * 注意:这是一个简化实现,实际需要维护 ID -> URI 的映射\n */\n private vectorIdToSubject(id: number, baseUrl: string): string {\n // TODO: 实现 ID -> URI 映射查询\n // 目前返回占位符\n return `${baseUrl}#vector-${id}`;\n }\n\n // ============================================\n // 辅助方法\n // ============================================\n\n private handleError(response: HttpResponse, error: unknown): void {\n if (error instanceof SearchApiError) {\n this.logger.error(`Search API error [${error.code}]: ${error.message}`);\n this.sendErrorResponse(response, error.statusCode, error.code, error.message);\n return;\n }\n\n if (error instanceof HttpError) {\n const errorMsg = error.message || error.name || `HTTP ${error.statusCode}`;\n this.logger.error(`HTTP error ${error.statusCode}: ${errorMsg}`);\n this.sendErrorResponse(response, error.statusCode, 'HTTP_ERROR', errorMsg);\n return;\n }\n\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`Unexpected error: ${errorMsg}`);\n this.sendErrorResponse(response, 500, 'INTERNAL_ERROR', errorMsg || 'Internal server error');\n }\n\n private async authorizeFor(\n baseUrl: string,\n request: HttpRequest,\n permissions: typeof PERMISSIONS[keyof typeof PERMISSIONS][],\n ): Promise<void> {\n const credentials = await this.credentialsExtractor.handleSafe(request);\n const identifier: ResourceIdentifier = { path: baseUrl };\n const requestedModes = new IdentifierSetMultiMap([[identifier, permissions]] as any);\n\n const availablePermissions = await this.permissionReader.handleSafe({\n credentials,\n identifier,\n requestedModes,\n } as any);\n\n this.logger.debug(`authorizeFor: baseUrl=${baseUrl}, webId=${credentials.agent?.webId}`);\n\n await this.authorizer.handleSafe({\n credentials,\n identifier,\n requestedModes,\n availablePermissions,\n } as any);\n }\n\n private parseUrl(request: HttpRequest): URL {\n const protocol = request.headers['x-forwarded-proto'] || 'http';\n const host = request.headers['x-forwarded-host'] || request.headers.host || 'localhost';\n return new URL(request.url!, `${protocol}://${host}`);\n }\n\n private async readJsonBody<T>(request: HttpRequest): Promise<T> {\n const chunks: Buffer[] = [];\n for await (const chunk of request) {\n chunks.push(chunk);\n }\n const body = Buffer.concat(chunks).toString('utf8');\n try {\n return JSON.parse(body) as T;\n } catch {\n throw SearchApiError.invalidRequest('Invalid JSON body');\n }\n }\n\n private sendJsonResponse(response: HttpResponse, data: unknown, status = 200): void {\n response.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache',\n });\n response.end(JSON.stringify(data));\n }\n\n private sendErrorResponse(\n response: HttpResponse,\n status: number,\n code: string,\n message: string,\n ): void {\n response.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache',\n });\n response.end(\n JSON.stringify({\n error: true,\n code,\n message,\n }),\n );\n }\n\n private writeOptions(response: HttpResponse): void {\n response.writeHead(204, {\n 'Access-Control-Allow-Methods': ALLOWED_METHODS.join(', '),\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n response.end();\n }\n}\n"]}
1
+ {"version":3,"file":"SearchHttpHandler.js","sourceRoot":"","sources":["../../../src/http/search/SearchHttpHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SearchHttpHandler - 语义搜索 HTTP 处理器\n *\n * 提供 /-/search 端点,支持基于向量的语义搜索。\n *\n * 端点:\n * - GET {path}/-/search?q=... 简单搜索\n * - POST {path}/-/search 复杂搜索(支持 filter 等)\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n NotImplementedHttpError,\n MethodNotAllowedHttpError,\n HttpError,\n IdentifierSetMultiMap,\n} from '@solid/community-server';\nimport { PERMISSIONS } from '@solidlab/policy-engine';\nimport type { CredentialsExtractor, PermissionReader, Authorizer, ResourceIdentifier } from '@solid/community-server';\nimport type { VectorStore } from '../../storage/vector/VectorStore';\nimport type { EmbeddingService } from '../../ai/service/EmbeddingService';\nimport type { SparqlEngine } from '../../storage/sparql/SubgraphQueryEngine';\nimport type { AiCredential } from '../../ai/service/types';\nimport type { VectorSearchOptions } from '../../storage/vector/types';\nimport { UDFS, normalizeAIConfigProviderId } from '@undefineds.co/models';\n\nconst ALLOWED_METHODS = ['GET', 'POST', 'OPTIONS'];\n\n// ============================================\n// 请求/响应类型\n// ============================================\n\ninterface SearchRequest {\n /** 查询文本 */\n query?: string;\n /** 预计算的查询向量 */\n vector?: number[];\n /** 返回结果数量,默认 10 */\n limit?: number;\n /** 相似度阈值 (0-1) */\n threshold?: number;\n /** 过滤条件 */\n filter?: {\n type?: string;\n graphPrefix?: string;\n subjectPrefix?: string;\n };\n /** embedding 模型 */\n model?: string;\n}\n\ninterface SearchResult {\n /** 资源 URI */\n subject: string;\n /** 相似度分数 (0-1) */\n score: number;\n /** 距离 */\n distance?: number;\n /** 文本片段 */\n snippet?: string;\n}\n\ninterface SearchResponse {\n results: SearchResult[];\n model: string;\n took_ms: number;\n}\n\n// ============================================\n// 错误处理\n// ============================================\n\ntype SearchErrorCode =\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'NO_CREDENTIAL'\n | 'EMBEDDING_ERROR'\n | 'SEARCH_ERROR';\n\nclass SearchApiError extends Error {\n constructor(\n public readonly code: SearchErrorCode,\n public readonly statusCode: number,\n message: string,\n ) {\n super(message);\n this.name = 'SearchApiError';\n }\n\n static invalidRequest(message: string): SearchApiError {\n return new SearchApiError('INVALID_REQUEST', 400, message);\n }\n\n static noCredential(): SearchApiError {\n return new SearchApiError('NO_CREDENTIAL', 400, 'No AI credential found. Please configure AI credentials in your Pod settings.');\n }\n\n static embeddingError(message: string): SearchApiError {\n return new SearchApiError('EMBEDDING_ERROR', 502, `Embedding generation failed: ${message}`);\n }\n\n static searchError(message: string): SearchApiError {\n return new SearchApiError('SEARCH_ERROR', 500, `Search failed: ${message}`);\n }\n}\n\n// ============================================\n// Handler\n// ============================================\n\nexport interface SearchHttpHandlerOptions {\n sidecarPath?: string;\n defaultModel?: string;\n defaultLimit?: number;\n}\n\nexport class SearchHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n\n private readonly vectorStore: VectorStore;\n private readonly embeddingService: EmbeddingService;\n private readonly sparqlEngine: SparqlEngine;\n private readonly credentialsExtractor: CredentialsExtractor;\n private readonly permissionReader: PermissionReader;\n private readonly authorizer: Authorizer;\n private readonly sidecarPath: string;\n private readonly defaultModel: string;\n private readonly defaultLimit: number;\n\n public constructor(\n vectorStore: VectorStore,\n embeddingService: EmbeddingService,\n sparqlEngine: SparqlEngine,\n credentialsExtractor: CredentialsExtractor,\n permissionReader: PermissionReader,\n authorizer: Authorizer,\n options: SearchHttpHandlerOptions = {},\n ) {\n super();\n this.vectorStore = vectorStore;\n this.embeddingService = embeddingService;\n this.sparqlEngine = sparqlEngine;\n this.credentialsExtractor = credentialsExtractor;\n this.permissionReader = permissionReader;\n this.authorizer = authorizer;\n this.sidecarPath = options.sidecarPath ?? '/-/search';\n this.defaultModel = options.defaultModel ?? 'text-embedding-004';\n this.defaultLimit = options.defaultLimit ?? 10;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.parseUrl(request).pathname;\n if (!path.includes(this.sidecarPath)) {\n throw new NotImplementedHttpError('Request is not targeting a search endpoint.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (!ALLOWED_METHODS.includes(method)) {\n throw new MethodNotAllowedHttpError(ALLOWED_METHODS);\n }\n\n try {\n const url = this.parseUrl(request);\n const path = decodeURIComponent(url.pathname);\n\n const sidecarIndex = path.indexOf(this.sidecarPath);\n if (sidecarIndex === -1) {\n throw new NotImplementedHttpError('Request is not targeting a search endpoint.');\n }\n\n // 提取 base path(sidecar 之前的路径)\n let basePath = path.slice(0, sidecarIndex);\n if (!basePath.endsWith('/')) {\n basePath = `${basePath}/`;\n }\n\n const origin = `${url.protocol}//${url.host}`;\n const baseUrl = `${origin}${basePath}`;\n\n this.logger.debug(`Search request: ${method} ${path}, baseUrl=${baseUrl}`);\n\n // 鉴权\n await this.authorizeFor(baseUrl, request, [PERMISSIONS.Read]);\n\n // 解析请求\n const searchRequest = await this.parseSearchRequest(request, url);\n\n // 执行搜索\n const result = await this.executeSearch(searchRequest, baseUrl);\n\n this.sendJsonResponse(response, result);\n } catch (error: unknown) {\n this.handleError(response, error);\n }\n }\n\n /**\n * 解析搜索请求\n */\n private async parseSearchRequest(request: HttpRequest, url: URL): Promise<SearchRequest> {\n const method = (request.method ?? 'GET').toUpperCase();\n\n if (method === 'GET') {\n // GET 请求从 query string 解析\n const query = url.searchParams.get('q') || url.searchParams.get('query');\n const limit = url.searchParams.get('limit');\n const threshold = url.searchParams.get('threshold');\n const model = url.searchParams.get('model');\n\n if (!query) {\n throw SearchApiError.invalidRequest('Missing query parameter \"q\"');\n }\n\n return {\n query,\n limit: limit ? parseInt(limit, 10) : undefined,\n threshold: threshold ? parseFloat(threshold) : undefined,\n model: model || undefined,\n };\n }\n\n // POST 请求从 body 解析\n const body = await this.readJsonBody<SearchRequest>(request);\n\n if (!body.query && !body.vector) {\n throw SearchApiError.invalidRequest('Either \"query\" or \"vector\" is required');\n }\n\n return body;\n }\n\n /**\n * 执行搜索\n */\n private async executeSearch(request: SearchRequest, baseUrl: string): Promise<SearchResponse> {\n const startTime = Date.now();\n const model = request.model || this.defaultModel;\n\n let queryVector = request.vector;\n\n // 如果提供了 query 文本,需要生成 embedding\n if (request.query && !queryVector) {\n // 获取 AI 凭据\n const credential = await this.getAiCredential(baseUrl);\n if (!credential) {\n throw SearchApiError.noCredential();\n }\n\n try {\n queryVector = await this.embeddingService.embed(request.query, credential, model);\n } catch (error) {\n throw SearchApiError.embeddingError(error instanceof Error ? error.message : String(error));\n }\n }\n\n if (!queryVector) {\n throw SearchApiError.invalidRequest('Failed to generate query vector');\n }\n\n // 执行向量搜索\n const searchOptions: VectorSearchOptions = {\n limit: request.limit ?? this.defaultLimit,\n threshold: request.threshold,\n };\n\n try {\n const vectorResults = await this.vectorStore.search(model, queryVector, searchOptions);\n\n // 转换结果\n const results: SearchResult[] = vectorResults.map((r) => ({\n subject: this.vectorIdToSubject(r.id, baseUrl),\n score: r.score,\n distance: r.distance,\n }));\n\n return {\n results,\n model,\n took_ms: Date.now() - startTime,\n };\n } catch (error) {\n throw SearchApiError.searchError(error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * 获取 AI 凭据\n */\n private async getAiCredential(podBaseUrl: string): Promise<AiCredential | null> {\n try {\n const query = `\n PREFIX cred: <${UDFS.NAMESPACE}>\n PREFIX ai: <${UDFS.NAMESPACE}>\n SELECT ?apiKey ?baseUrl ?provider ?proxyUrl WHERE {\n ?cred a cred:Credential ;\n cred:service \"ai\" ;\n cred:status \"active\" ;\n cred:apiKey ?apiKey .\n OPTIONAL { ?cred cred:provider ?provider }\n OPTIONAL {\n ?cred cred:provider ?provider .\n ?provider ai:baseUrl ?baseUrl .\n }\n OPTIONAL {\n ?cred cred:provider ?provider .\n ?provider ai:proxyUrl ?proxyUrl .\n }\n } LIMIT 1\n `;\n\n const bindingsStream = await this.sparqlEngine.queryBindings(query, podBaseUrl);\n\n for await (const binding of bindingsStream) {\n const apiKey = binding.get('apiKey');\n const baseUrl = binding.get('baseUrl');\n const provider = binding.get('provider');\n const proxyUrl = binding.get('proxyUrl');\n\n if (apiKey) {\n const providerName = normalizeAIConfigProviderId(provider?.value || 'google') || 'google';\n\n return {\n apiKey: apiKey.value,\n baseUrl: baseUrl?.value,\n provider: providerName,\n proxyUrl: proxyUrl?.value,\n };\n }\n }\n\n return null;\n } catch (error) {\n this.logger.error(`Failed to query AI credential: ${error}`);\n return null;\n }\n }\n\n /**\n * 将向量 ID 转换回 subject URI\n * 注意:这是一个简化实现,实际需要维护 ID -> URI 的映射\n */\n private vectorIdToSubject(id: number, baseUrl: string): string {\n // TODO: 实现 ID -> URI 映射查询\n // 目前返回占位符\n return `${baseUrl}#vector-${id}`;\n }\n\n // ============================================\n // 辅助方法\n // ============================================\n\n private handleError(response: HttpResponse, error: unknown): void {\n if (error instanceof SearchApiError) {\n this.logger.error(`Search API error [${error.code}]: ${error.message}`);\n this.sendErrorResponse(response, error.statusCode, error.code, error.message);\n return;\n }\n\n if (error instanceof HttpError) {\n const errorMsg = error.message || error.name || `HTTP ${error.statusCode}`;\n this.logger.error(`HTTP error ${error.statusCode}: ${errorMsg}`);\n this.sendErrorResponse(response, error.statusCode, 'HTTP_ERROR', errorMsg);\n return;\n }\n\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`Unexpected error: ${errorMsg}`);\n this.sendErrorResponse(response, 500, 'INTERNAL_ERROR', errorMsg || 'Internal server error');\n }\n\n private async authorizeFor(\n baseUrl: string,\n request: HttpRequest,\n permissions: typeof PERMISSIONS[keyof typeof PERMISSIONS][],\n ): Promise<void> {\n const credentials = await this.credentialsExtractor.handleSafe(request);\n const identifier: ResourceIdentifier = { path: baseUrl };\n const requestedModes = new IdentifierSetMultiMap([[identifier, permissions]] as any);\n\n const availablePermissions = await this.permissionReader.handleSafe({\n credentials,\n identifier,\n requestedModes,\n } as any);\n\n this.logger.debug(`authorizeFor: baseUrl=${baseUrl}, webId=${credentials.agent?.webId}`);\n\n await this.authorizer.handleSafe({\n credentials,\n identifier,\n requestedModes,\n availablePermissions,\n } as any);\n }\n\n private parseUrl(request: HttpRequest): URL {\n const protocol = request.headers['x-forwarded-proto'] || 'http';\n const host = request.headers['x-forwarded-host'] || request.headers.host || 'localhost';\n return new URL(request.url!, `${protocol}://${host}`);\n }\n\n private async readJsonBody<T>(request: HttpRequest): Promise<T> {\n const chunks: Buffer[] = [];\n for await (const chunk of request) {\n chunks.push(chunk);\n }\n const body = Buffer.concat(chunks).toString('utf8');\n try {\n return JSON.parse(body) as T;\n } catch {\n throw SearchApiError.invalidRequest('Invalid JSON body');\n }\n }\n\n private sendJsonResponse(response: HttpResponse, data: unknown, status = 200): void {\n response.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache',\n });\n response.end(JSON.stringify(data));\n }\n\n private sendErrorResponse(\n response: HttpResponse,\n status: number,\n code: string,\n message: string,\n ): void {\n response.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache',\n });\n response.end(\n JSON.stringify({\n error: true,\n code,\n message,\n }),\n );\n }\n\n private writeOptions(response: HttpResponse): void {\n response.writeHead(204, {\n 'Access-Control-Allow-Methods': ALLOWED_METHODS.join(', '),\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n response.end();\n }\n}\n"]}
@@ -1,31 +1,13 @@
1
- import { type IdentityDatabase } from './db';
2
- export interface PodQuotaContext {
3
- accountId: string;
4
- podId: string;
5
- baseUrl?: string;
6
- podQuota?: number;
7
- accountQuota?: number;
8
- }
1
+ import type { IdentityDatabase } from './db';
9
2
  /**
10
- * Repository for account and pod quota operations.
11
- *
12
- * Reads account/pod data from CSS's internal_kv table.
13
- * Quota limits are stored in identity_account_usage / identity_pod_usage tables.
3
+ * Reads account/pod ownership data from the CSS identity facts.
4
+ * Quota values live in identity_usage and are managed by UsageRepository.
14
5
  */
15
6
  export declare class AccountRepository {
16
- private readonly db;
17
- private readonly kvTableName;
18
- private readonly accountUsageTable;
19
- private readonly podUsageTable;
7
+ private readonly podLookupRepo;
20
8
  constructor(db: IdentityDatabase, kvTableName?: string);
21
- getAccountQuota(accountId: string): Promise<number | undefined>;
22
9
  getPodInfo(podId: string): Promise<{
23
10
  accountId: string;
24
- podQuota?: number;
25
11
  baseUrl?: string;
26
12
  } | undefined>;
27
- private getPodQuota;
28
- getQuotaContext(accountId: string, podId: string): Promise<PodQuotaContext | undefined>;
29
- setAccountQuota(accountId: string, quota?: number): Promise<void>;
30
- setPodQuota(podId: string, quota?: number): Promise<void>;
31
13
  }
@@ -1,130 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AccountRepository = void 0;
4
- const drizzle_orm_1 = require("drizzle-orm");
5
- const db_1 = require("./db");
4
+ const PodLookupRepository_1 = require("./PodLookupRepository");
6
5
  /**
7
- * Repository for account and pod quota operations.
8
- *
9
- * Reads account/pod data from CSS's internal_kv table.
10
- * Quota limits are stored in identity_account_usage / identity_pod_usage tables.
6
+ * Reads account/pod ownership data from the CSS identity facts.
7
+ * Quota values live in identity_usage and are managed by UsageRepository.
11
8
  */
12
9
  class AccountRepository {
13
10
  constructor(db, kvTableName) {
14
- this.db = db;
15
- this.kvTableName = kvTableName ?? 'internal_kv';
16
- this.accountUsageTable = 'identity_account_usage';
17
- this.podUsageTable = 'identity_pod_usage';
18
- }
19
- async getAccountQuota(accountId) {
20
- try {
21
- const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
22
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE account_id = ${accountId} LIMIT 1`);
23
- if (result.rows.length === 0) {
24
- return undefined;
25
- }
26
- const limit = result.rows[0].storage_limit_bytes;
27
- return limit != null ? limit : undefined;
28
- }
29
- catch {
30
- // Table might not exist
31
- return undefined;
32
- }
11
+ this.podLookupRepo = new PodLookupRepository_1.PodLookupRepository(db, kvTableName);
33
12
  }
34
13
  async getPodInfo(podId) {
35
- // Get pod info from CSS's internal_kv
36
- const kvTableId = drizzle_orm_1.sql.identifier([this.kvTableName]);
37
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
38
- SELECT key, value FROM ${kvTableId}
39
- WHERE key LIKE 'accounts/data/%'
40
- `);
41
- for (const row of result.rows) {
42
- try {
43
- const accountId = row.key.replace('accounts/data/', '');
44
- const data = typeof row.value === 'string' ? JSON.parse(row.value) : row.value;
45
- const podMap = data['**pod**'] || data.pod || {};
46
- if (podMap[podId]) {
47
- const pod = podMap[podId];
48
- const podQuota = await this.getPodQuota(podId);
49
- return {
50
- accountId,
51
- baseUrl: typeof pod.baseUrl === 'string' ? pod.baseUrl : undefined,
52
- podQuota,
53
- };
54
- }
55
- }
56
- catch {
57
- // Skip malformed entries
58
- }
59
- }
60
- return undefined;
61
- }
62
- async getPodQuota(podId) {
63
- try {
64
- const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
65
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE pod_id = ${podId} LIMIT 1`);
66
- if (result.rows.length === 0) {
67
- return undefined;
68
- }
69
- const limit = result.rows[0].storage_limit_bytes;
70
- return limit != null ? limit : undefined;
71
- }
72
- catch {
73
- // Table might not exist
74
- return undefined;
75
- }
76
- }
77
- async getQuotaContext(accountId, podId) {
78
- const podInfo = await this.getPodInfo(podId);
79
- if (!podInfo) {
80
- return undefined;
81
- }
82
- if (podInfo.accountId !== accountId) {
14
+ const pod = await this.podLookupRepo.findById(podId)
15
+ ?? await this.podLookupRepo.findByResourceIdentifier(podId);
16
+ if (!pod) {
83
17
  return undefined;
84
18
  }
85
- const accountQuota = await this.getAccountQuota(accountId);
86
19
  return {
87
- accountId,
88
- podId,
89
- baseUrl: podInfo.baseUrl,
90
- podQuota: podInfo.podQuota,
91
- accountQuota,
20
+ accountId: pod.accountId,
21
+ baseUrl: pod.baseUrl,
92
22
  };
93
23
  }
94
- async setAccountQuota(accountId, quota) {
95
- const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
96
- if ((0, db_1.isDatabaseSqlite)(this.db)) {
97
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
98
- INSERT INTO ${tableId} (account_id, storage_limit_bytes)
99
- VALUES (${accountId}, ${quota ?? null})
100
- ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
101
- `);
102
- }
103
- else {
104
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
105
- INSERT INTO ${tableId} (account_id, storage_limit_bytes)
106
- VALUES (${accountId}, ${quota ?? null})
107
- ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
108
- `);
109
- }
110
- }
111
- async setPodQuota(podId, quota) {
112
- const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
113
- if ((0, db_1.isDatabaseSqlite)(this.db)) {
114
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
115
- INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
116
- VALUES (${podId}, '', ${quota ?? null})
117
- ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
118
- `);
119
- }
120
- else {
121
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
122
- INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
123
- VALUES (${podId}, '', ${quota ?? null})
124
- ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
125
- `);
126
- }
127
- }
128
24
  }
129
25
  exports.AccountRepository = AccountRepository;
130
26
  //# sourceMappingURL=AccountRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from 'drizzle-orm';\nimport { type IdentityDatabase, executeQuery, isDatabaseSqlite } from './db';\n\nexport interface PodQuotaContext {\n accountId: string;\n podId: string;\n baseUrl?: string;\n podQuota?: number;\n accountQuota?: number;\n}\n\ninterface InternalKvRow {\n key: string;\n value: string;\n}\n\n/**\n * Repository for account and pod quota operations.\n *\n * Reads account/pod data from CSS's internal_kv table.\n * Quota limits are stored in identity_account_usage / identity_pod_usage tables.\n */\nexport class AccountRepository {\n private readonly kvTableName: string;\n private readonly accountUsageTable: string;\n private readonly podUsageTable: string;\n\n public constructor(\n private readonly db: IdentityDatabase,\n kvTableName?: string,\n ) {\n this.kvTableName = kvTableName ?? 'internal_kv';\n this.accountUsageTable = 'identity_account_usage';\n this.podUsageTable = 'identity_pod_usage';\n }\n\n public async getAccountQuota(accountId: string): Promise<number | undefined> {\n try {\n const tableId = sql.identifier([this.accountUsageTable]);\n const result = await executeQuery<{ storage_limit_bytes: number | null }>(\n this.db,\n sql`SELECT storage_limit_bytes FROM ${tableId} WHERE account_id = ${accountId} LIMIT 1`,\n );\n if (result.rows.length === 0) {\n return undefined;\n }\n const limit = result.rows[0].storage_limit_bytes;\n return limit != null ? limit : undefined;\n } catch {\n // Table might not exist\n return undefined;\n }\n }\n\n public async getPodInfo(podId: string): Promise<{ accountId: string; podQuota?: number; baseUrl?: string } | undefined> {\n // Get pod info from CSS's internal_kv\n const kvTableId = sql.identifier([this.kvTableName]);\n const result = await executeQuery<InternalKvRow>(this.db, sql`\n SELECT key, value FROM ${kvTableId}\n WHERE key LIKE 'accounts/data/%'\n `);\n\n for (const row of result.rows) {\n try {\n const accountId = row.key.replace('accounts/data/', '');\n const data = typeof row.value === 'string' ? JSON.parse(row.value) : row.value;\n const podMap = data['**pod**'] || data.pod || {};\n\n if (podMap[podId]) {\n const pod = podMap[podId] as Record<string, unknown>;\n const podQuota = await this.getPodQuota(podId);\n return {\n accountId,\n baseUrl: typeof pod.baseUrl === 'string' ? pod.baseUrl : undefined,\n podQuota,\n };\n }\n } catch {\n // Skip malformed entries\n }\n }\n\n return undefined;\n }\n\n private async getPodQuota(podId: string): Promise<number | undefined> {\n try {\n const tableId = sql.identifier([this.podUsageTable]);\n const result = await executeQuery<{ storage_limit_bytes: number | null }>(\n this.db,\n sql`SELECT storage_limit_bytes FROM ${tableId} WHERE pod_id = ${podId} LIMIT 1`,\n );\n if (result.rows.length === 0) {\n return undefined;\n }\n const limit = result.rows[0].storage_limit_bytes;\n return limit != null ? limit : undefined;\n } catch {\n // Table might not exist\n return undefined;\n }\n }\n\n public async getQuotaContext(accountId: string, podId: string): Promise<PodQuotaContext | undefined> {\n const podInfo = await this.getPodInfo(podId);\n if (!podInfo) {\n return undefined;\n }\n if (podInfo.accountId !== accountId) {\n return undefined;\n }\n const accountQuota = await this.getAccountQuota(accountId);\n return {\n accountId,\n podId,\n baseUrl: podInfo.baseUrl,\n podQuota: podInfo.podQuota,\n accountQuota,\n };\n }\n\n public async setAccountQuota(accountId: string, quota?: number): Promise<void> {\n const tableId = sql.identifier([this.accountUsageTable]);\n if (isDatabaseSqlite(this.db)) {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (account_id, storage_limit_bytes)\n VALUES (${accountId}, ${quota ?? null})\n ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}\n `);\n } else {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (account_id, storage_limit_bytes)\n VALUES (${accountId}, ${quota ?? null})\n ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes\n `);\n }\n }\n\n public async setPodQuota(podId: string, quota?: number): Promise<void> {\n const tableId = sql.identifier([this.podUsageTable]);\n if (isDatabaseSqlite(this.db)) {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)\n VALUES (${podId}, '', ${quota ?? null})\n ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}\n `);\n } else {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)\n VALUES (${podId}, '', ${quota ?? null})\n ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes\n `);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":";;;AACA,+DAA4D;AAE5D;;;GAGG;AACH,MAAa,iBAAiB;IAG5B,YACE,EAAoB,EACpB,WAAoB;QAEpB,IAAI,CAAC,aAAa,GAAG,IAAI,yCAAmB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,KAAa;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;eAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC;IACJ,CAAC;CACF;AArBD,8CAqBC","sourcesContent":["import type { IdentityDatabase } from './db';\nimport { PodLookupRepository } from './PodLookupRepository';\n\n/**\n * Reads account/pod ownership data from the CSS identity facts.\n * Quota values live in identity_usage and are managed by UsageRepository.\n */\nexport class AccountRepository {\n private readonly podLookupRepo: PodLookupRepository;\n\n public constructor(\n db: IdentityDatabase,\n kvTableName?: string,\n ) {\n this.podLookupRepo = new PodLookupRepository(db, kvTableName);\n }\n\n public async getPodInfo(podId: string): Promise<{ accountId: string; baseUrl?: string } | undefined> {\n const pod = await this.podLookupRepo.findById(podId)\n ?? await this.podLookupRepo.findByResourceIdentifier(podId);\n if (!pod) {\n return undefined;\n }\n return {\n accountId: pod.accountId,\n baseUrl: pod.baseUrl,\n };\n }\n}\n"]}
@@ -6,18 +6,18 @@ export interface AccountRoleContext {
6
6
  }
7
7
  export declare class AccountRoleRepository {
8
8
  private readonly db;
9
- private readonly ready;
10
9
  private readonly logger;
11
10
  constructor(db: IdentityDatabase);
12
11
  findByAccountId(accountId: string): Promise<AccountRoleContext | undefined>;
13
12
  findByWebId(webId: string): Promise<AccountRoleContext | undefined>;
14
13
  findByWebIdLoose(webId: string): Promise<AccountRoleContext | undefined>;
15
14
  addRoles(accountId: string, roles: string[]): Promise<void>;
16
- private ensureSchema;
17
- private fetchRoles;
18
- private getAccountPayloadById;
15
+ private getAccountById;
19
16
  private loadAllAccounts;
17
+ private loadIdentityStoreAccounts;
18
+ private loadInternalKvAccounts;
20
19
  private loadFileAccountMap;
20
+ private updateAccountRecord;
21
+ private toJsonSql;
21
22
  private isTableMissing;
22
- private isDuplicateDefinitionError;
23
23
  }