@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":"ProvisionHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/ProvisionHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provision Handler\n *\n * Cloud 端的 SP 注册 API\n *\n * POST /provision/nodes - SP 注册(公开,无需认证)\n * 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)\n *\n * provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。\n * CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。\n *\n * GET /provision/status - Local 端 SP 状态查询(公开)\n * 返回 SP 配置状态,供 Linx 查询\n */\n\nimport type { ServerResponse, IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider, TunnelConfig } from '../../tunnel/TunnelProvider';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\nexport interface ProvisionHandlerOptions {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n /** Cloud baseUrl,用于派生 provisionCode 签名密钥 */\n baseUrl: string;\n /** 节点域名根域名,如 \"undefineds.site\" */\n baseStorageDomain?: string;\n /** provisionCode 有效期(秒),默认 24 小时 */\n provisionCodeTtl?: number;\n}\n\n/** 默认 24 小时 */\nconst DEFAULT_TTL = 24 * 60 * 60;\n\nexport function registerProvisionRoutes(\n server: ApiServer,\n options: ProvisionHandlerOptions,\n): void {\n const logger = getLoggerFor('ProvisionHandler');\n const { repository, baseUrl, baseStorageDomain } = options;\n const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;\n const codec = new ProvisionCodeCodec(baseUrl);\n\n /**\n * POST /provision/nodes\n *\n * SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)\n *\n * Request:\n * {\n * publicUrl: string,\n * nodeId?: string,\n * displayName?: string,\n * ipv4?: string,\n * serviceToken?: string,\n * domainMode?: 'managed' | 'self-managed',\n * spDomain?: string,\n * localPort?: number,\n * tunnelToken?: string\n * }\n *\n * Response 201:\n * { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }\n */\n server.post('/provision/nodes', async (request, response) => {\n let body: {\n publicUrl?: string;\n nodeId?: string;\n nodeToken?: string;\n displayName?: string;\n ipv4?: string;\n serviceToken?: string;\n localPort?: number;\n tunnelToken?: string;\n tunnelMode?: 'client';\n domainMode?: 'managed' | 'self-managed';\n spDomain?: string;\n };\n try {\n body = await readJsonBody(request) as any ?? {};\n } catch {\n sendJson(response, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!body.publicUrl) {\n sendJson(response, 400, { error: 'publicUrl is required' });\n return;\n }\n\n try {\n new URL(body.publicUrl);\n } catch {\n sendJson(response, 400, { error: 'Invalid publicUrl format' });\n return;\n }\n\n try {\n const result = await repository.registerSpNode({\n publicUrl: body.publicUrl,\n displayName: body.displayName,\n nodeId: body.nodeId,\n nodeToken: body.nodeToken,\n serviceToken: body.serviceToken,\n });\n\n const domainMode = body.domainMode === 'self-managed' ? 'self-managed' : 'managed';\n const requestedManagedDomain = normalizeRequestedManagedDomain(body.spDomain, baseStorageDomain);\n const subdomainPrefix = resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: result.nodeId,\n });\n const spDomain = subdomainPrefix\n ? `${subdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const tunnelState = await ensureManagedTunnelState({\n repository,\n nodeId: result.nodeId,\n subdomainPrefix,\n publicUrl: body.publicUrl,\n localPort: body.localPort,\n ipv4: body.ipv4,\n tunnelToken: body.tunnelToken,\n ddnsRepo: options.ddnsRepo,\n dnsProvider: options.dnsProvider,\n tunnelProvider: options.tunnelProvider,\n baseStorageDomain,\n });\n\n if (body.ipv4 || subdomainPrefix) {\n await repository.updateNodeMode(result.nodeId, {\n accessMode: tunnelState?.mode === 'tunnel' ? 'proxy' : 'direct',\n ipv4: body.ipv4,\n subdomain: subdomainPrefix,\n });\n }\n\n // 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)\n const provisionCode = codec.encode({\n spUrl: body.publicUrl,\n serviceToken: result.serviceToken,\n nodeId: result.nodeId,\n spDomain,\n exp: Math.floor(Date.now() / 1000) + ttl,\n });\n\n logger.info(`Registered SP node ${result.nodeId} at ${body.publicUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);\n\n const responseBody: Record<string, unknown> = {\n nodeId: result.nodeId,\n nodeToken: result.nodeToken,\n serviceToken: result.serviceToken,\n provisionCode,\n };\n if (spDomain) {\n responseBody.spDomain = spDomain;\n }\n if (tunnelState?.tunnelConfig?.tunnelToken) {\n responseBody.tunnelToken = tunnelState.tunnelConfig.tunnelToken;\n }\n if (tunnelState?.tunnelConfig?.provider) {\n responseBody.tunnelProvider = tunnelState.tunnelConfig.provider;\n }\n if (tunnelState?.tunnelConfig?.endpoint) {\n responseBody.tunnelEndpoint = tunnelState.tunnelConfig.endpoint;\n }\n\n sendJson(response, 201, responseBody);\n } catch (error) {\n if (error instanceof InvalidTunnelTokenError) {\n sendJson(response, 400, { error: error.message });\n return;\n }\n logger.error(`Failed to register SP node: ${error}`);\n sendJson(response, 500, { error: 'Failed to register SP node' });\n }\n }, { public: true });\n\n logger.info('Provision routes registered');\n}\n\ninterface ManagedTunnelState {\n mode: 'direct' | 'tunnel';\n tunnelConfig?: TunnelConfig;\n}\n\nclass InvalidTunnelTokenError extends Error {}\n\nasync function ensureManagedTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n nodeId: string;\n subdomainPrefix?: string;\n baseStorageDomain?: string;\n publicUrl: string;\n localPort?: number;\n ipv4?: string;\n tunnelToken?: string;\n}): Promise<ManagedTunnelState | undefined> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n ipv4,\n tunnelToken,\n } = options;\n\n if (!subdomainPrefix || !baseStorageDomain) {\n return undefined;\n }\n\n const mode: 'direct' | 'tunnel' = ipv4 ? 'direct' : 'tunnel';\n\n if (mode === 'direct') {\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: ipv4,\n });\n }\n }\n\n return { mode };\n }\n\n if (tunnelToken) {\n if (!localPort || localPort <= 0) {\n throw new InvalidTunnelTokenError('localPort is required when tunnelToken is provided');\n }\n\n return {\n mode,\n tunnelConfig: await ensureManagedTokenTunnelState({\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n }),\n };\n }\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n });\n }\n }\n\n if (!tunnelProvider || !localPort || localPort <= 0) {\n return { mode };\n }\n\n const metadataRecord = await repository.getNodeMetadata(nodeId);\n const metadata = metadataRecord?.metadata as Record<string, unknown> | null;\n const existingTunnel = readManagedTunnelConfig(metadata);\n if (existingTunnel && existingTunnel.subdomain === subdomainPrefix && existingTunnel.localPort === localPort) {\n return {\n mode,\n tunnelConfig: existingTunnel.config,\n };\n }\n\n const tunnelConfig = await tunnelProvider.setup({\n subdomain: subdomainPrefix,\n localPort,\n });\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: tunnelConfig.provider,\n tunnelId: tunnelConfig.tunnelId,\n tunnelToken: tunnelConfig.tunnelToken,\n endpoint: tunnelConfig.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n },\n publicAddress: tunnelConfig.endpoint || publicUrl,\n });\n\n return {\n mode,\n tunnelConfig,\n };\n}\n\nasync function ensureManagedTokenTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n nodeId: string;\n subdomainPrefix: string;\n baseStorageDomain: string;\n publicUrl: string;\n localPort: number;\n tunnelToken: string;\n}): Promise<TunnelConfig> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n } = options;\n\n const parsed = parseCloudflareTunnelToken(tunnelToken);\n if (!parsed?.tunnelId) {\n throw new InvalidTunnelTokenError('Invalid Cloudflare tunnel token');\n }\n\n const endpoint = `https://${subdomainPrefix}.${baseStorageDomain}`;\n const cnameTarget = `${parsed.tunnelId}.cfargotunnel.com`;\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: cnameTarget,\n recordType: 'CNAME',\n });\n } else if (\n existing.recordType !== 'CNAME'\n || existing.ipAddress !== cnameTarget\n || existing.ipv6Address\n ) {\n await ddnsRepo.updateRecordIp(subdomainPrefix, {\n ipAddress: cnameTarget,\n ipv6Address: null,\n recordType: 'CNAME',\n });\n }\n }\n\n if (dnsProvider) {\n await dnsProvider.upsertRecord({\n domain: baseStorageDomain,\n subdomain: subdomainPrefix,\n type: 'CNAME',\n value: cnameTarget,\n ttl: 60,\n });\n }\n\n const config: TunnelConfig = {\n provider: 'cloudflare',\n subdomain: subdomainPrefix,\n endpoint,\n tunnelId: parsed.tunnelId,\n tunnelToken,\n };\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: config.provider,\n tunnelId: config.tunnelId,\n tunnelToken: config.tunnelToken,\n endpoint: config.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n source: 'client-token',\n },\n publicAddress: endpoint || publicUrl,\n });\n\n return config;\n}\n\nfunction parseCloudflareTunnelToken(token: string): { accountId?: string; tunnelId?: string } | undefined {\n const decoded = decodeJsonBase64UrlSegment(token) ?? decodeJsonBase64UrlSegment(token.split('.')[0] ?? '');\n if (!decoded || typeof decoded !== 'object') {\n return undefined;\n }\n\n const value = decoded as Record<string, unknown>;\n return {\n accountId: typeof value.a === 'string' ? value.a : undefined,\n tunnelId: typeof value.t === 'string' ? value.t : undefined,\n };\n}\n\nfunction decodeJsonBase64UrlSegment(segment: string): unknown {\n if (!segment) {\n return undefined;\n }\n\n try {\n const normalized = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n const json = Buffer.from(`${normalized}${padding}`, 'base64').toString('utf8');\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction readManagedTunnelConfig(metadata: Record<string, unknown> | null): { subdomain?: string; localPort?: number; config: TunnelConfig } | undefined {\n const raw = metadata?.managedTunnel;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n const value = raw as Record<string, unknown>;\n const provider = value.provider;\n const endpoint = value.endpoint;\n const tunnelToken = value.tunnelToken;\n const tunnelId = value.tunnelId;\n const subdomain = typeof value.subdomain === 'string' ? value.subdomain : undefined;\n const localPort = typeof value.localPort === 'number' ? value.localPort : undefined;\n\n if (\n (provider !== 'cloudflare' && provider !== 'frp' && provider !== 'sakura-frp')\n || typeof endpoint !== 'string'\n ) {\n return undefined;\n }\n\n return {\n subdomain,\n localPort,\n config: {\n provider,\n subdomain: subdomain ?? 'local',\n endpoint,\n tunnelId: typeof tunnelId === 'string' ? tunnelId : undefined,\n tunnelToken: typeof tunnelToken === 'string' ? tunnelToken : undefined,\n },\n };\n}\n\n/**\n * Local 端 SP 状态查询路由\n */\nexport interface ProvisionStatusOptions {\n /** Cloud API 端点 */\n cloudUrl?: string;\n /** 节点 ID */\n nodeId?: string;\n /** SP 子域名 */\n spDomain?: string;\n /** Cloud baseUrl,用于拼 provisionUrl */\n cloudBaseUrl?: string;\n /** provisionCode(可选,由环境变量传入) */\n provisionCode?: string;\n}\n\nexport function registerProvisionStatusRoute(\n server: ApiServer,\n options: ProvisionStatusOptions,\n): void {\n const logger = getLoggerFor('ProvisionStatusHandler');\n\n server.get('/provision/status', async (_request, response) => {\n const registered = Boolean(options.nodeId && options.cloudUrl);\n\n const body: Record<string, unknown> = {\n registered,\n };\n\n if (registered) {\n body.cloudUrl = options.cloudUrl;\n body.nodeId = options.nodeId;\n if (options.spDomain) {\n body.spDomain = options.spDomain;\n }\n if (options.cloudBaseUrl) {\n const provisionUrl = options.provisionCode\n ? `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/?provisionCode=${encodeURIComponent(options.provisionCode)}`\n : `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/`;\n body.provisionUrl = provisionUrl;\n }\n }\n\n sendJson(response, 200, body);\n }, { public: true });\n\n logger.info('Provision status route registered');\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\nfunction normalizeRequestedManagedDomain(value: string | undefined, baseStorageDomain: string | undefined): string | undefined {\n if (!value || !baseStorageDomain) {\n return undefined;\n }\n\n const domain = value.trim().toLowerCase().replace(/^https?:\\/\\//u, '').replace(/\\/.*$/u, '').replace(/\\.$/u, '');\n const suffix = `.${baseStorageDomain.toLowerCase()}`;\n if (!domain.endsWith(suffix)) {\n return undefined;\n }\n\n const prefix = domain.slice(0, -suffix.length).replace(/[^a-z0-9-]/giu, '').slice(0, 63);\n if (!prefix) {\n return undefined;\n }\n\n return `${prefix}.${baseStorageDomain}`;\n}\n\nfunction resolveManagedSubdomainPrefix(options: {\n domainMode: 'managed' | 'self-managed';\n baseStorageDomain?: string;\n requestedManagedDomain?: string;\n nodeId: string;\n}): string | undefined {\n if (options.domainMode !== 'managed' || !options.baseStorageDomain) {\n return undefined;\n }\n\n if (options.requestedManagedDomain) {\n const suffix = `.${options.baseStorageDomain}`;\n return options.requestedManagedDomain.slice(0, -suffix.length);\n }\n\n return options.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || options.nodeId.split('-')[0];\n}\n"]}
1
+ {"version":3,"file":"ProvisionHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/ProvisionHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provision Handler\n *\n * Cloud 端的 SP 注册 API\n *\n * POST /provision/nodes - SP 注册(公开,无需认证)\n * 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)\n *\n * provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。\n * CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。\n *\n * GET /provision/status - Local 端 SP 状态查询(公开)\n * 返回 SP 配置状态,供 Linx 查询\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ServerResponse, IncomingMessage } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider, TunnelConfig } from '../../tunnel/TunnelProvider';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\nexport interface ProvisionHandlerOptions {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n /** Cloud baseUrl,用于派生 provisionCode 签名密钥 */\n baseUrl: string;\n /** 节点域名根域名,如 \"undefineds.site\" */\n baseStorageDomain?: string;\n /** provisionCode 有效期(秒),默认 24 小时 */\n provisionCodeTtl?: number;\n}\n\n/** 默认 24 小时 */\nconst DEFAULT_TTL = 24 * 60 * 60;\nconst PROVISION_STATUS_REFRESH_GRACE_SECONDS = 5 * 60;\n\nexport function registerProvisionRoutes(\n server: ApiServer,\n options: ProvisionHandlerOptions,\n): void {\n const logger = getLoggerFor('ProvisionHandler');\n const { repository, baseUrl, baseStorageDomain } = options;\n const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;\n const codec = new ProvisionCodeCodec(baseUrl);\n\n /**\n * POST /provision/nodes\n *\n * SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)\n *\n * Request:\n * {\n * publicUrl?: string,\n * nodeId?: string,\n * displayName?: string,\n * ipv4?: string,\n * serviceToken?: string,\n * domainMode?: 'managed' | 'self-managed',\n * spDomain?: string,\n * localPort?: number,\n * tunnelToken?: string\n * }\n *\n * Response 201:\n * { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }\n */\n server.post('/provision/nodes', async (request, response) => {\n let body: {\n publicUrl?: string;\n nodeId?: string;\n nodeToken?: string;\n displayName?: string;\n ipv4?: string;\n serviceToken?: string;\n localPort?: number;\n tunnelToken?: string;\n tunnelMode?: 'client';\n domainMode?: 'managed' | 'self-managed';\n spDomain?: string;\n };\n try {\n body = await readJsonBody(request) as any ?? {};\n } catch {\n sendJson(response, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n try {\n const domainMode = body.domainMode === 'self-managed' ? 'self-managed' : 'managed';\n const requestedManagedDomain = normalizeRequestedManagedDomain(body.spDomain, baseStorageDomain);\n const shouldAllocateManagedPublicUrl = !body.publicUrl && domainMode === 'managed' && Boolean(baseStorageDomain);\n const preallocatedNodeId = shouldAllocateManagedPublicUrl\n ? (body.nodeId ?? randomUUID())\n : undefined;\n const preallocatedSubdomainPrefix = preallocatedNodeId\n ? resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: preallocatedNodeId,\n })\n : undefined;\n const preallocatedSpDomain = preallocatedSubdomainPrefix\n ? `${preallocatedSubdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const effectivePublicUrl = body.publicUrl ?? derivePublicUrlFromSpDomain(preallocatedSpDomain);\n\n if (!effectivePublicUrl) {\n sendJson(response, 400, { error: 'publicUrl is required' });\n return;\n }\n\n if (preallocatedSubdomainPrefix && baseStorageDomain && options.ddnsRepo) {\n const existing = await options.ddnsRepo.getRecord(preallocatedSubdomainPrefix);\n if (existing?.nodeId && existing.nodeId !== preallocatedNodeId) {\n sendJson(response, 409, {\n error: 'spDomain already allocated',\n spDomain: preallocatedSpDomain,\n });\n return;\n }\n }\n\n try {\n new URL(effectivePublicUrl);\n } catch {\n sendJson(response, 400, { error: 'Invalid publicUrl format' });\n return;\n }\n\n const result = await repository.registerSpNode({\n publicUrl: effectivePublicUrl,\n displayName: body.displayName,\n nodeId: preallocatedNodeId ?? body.nodeId,\n nodeToken: body.nodeToken,\n serviceToken: body.serviceToken,\n });\n\n const subdomainPrefix = preallocatedSubdomainPrefix\n ?? resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: result.nodeId,\n });\n const spDomain = subdomainPrefix\n ? `${subdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const managedPublicUrl = derivePublicUrlFromSpDomain(spDomain);\n const provisionSpUrl = body.publicUrl ?? managedPublicUrl ?? effectivePublicUrl;\n const tunnelState = await ensureManagedTunnelState({\n repository,\n nodeId: result.nodeId,\n subdomainPrefix,\n publicUrl: provisionSpUrl,\n localPort: body.localPort,\n ipv4: body.ipv4,\n tunnelToken: body.tunnelToken,\n ddnsRepo: options.ddnsRepo,\n dnsProvider: options.dnsProvider,\n tunnelProvider: options.tunnelProvider,\n baseStorageDomain,\n });\n\n if (body.ipv4 || subdomainPrefix) {\n await repository.updateNodeMode(result.nodeId, {\n accessMode: tunnelState?.mode === 'tunnel' ? 'proxy' : 'direct',\n ipv4: body.ipv4,\n subdomain: subdomainPrefix,\n });\n }\n\n // 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)\n const provisionCode = codec.encode({\n spUrl: provisionSpUrl,\n serviceToken: result.serviceToken,\n nodeId: result.nodeId,\n spDomain,\n exp: Math.floor(Date.now() / 1000) + ttl,\n });\n\n logger.info(`Registered SP node ${result.nodeId} at ${provisionSpUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);\n\n const responseBody: Record<string, unknown> = {\n nodeId: result.nodeId,\n nodeToken: result.nodeToken,\n serviceToken: result.serviceToken,\n provisionCode,\n };\n if (managedPublicUrl) {\n responseBody.publicUrl = managedPublicUrl;\n }\n if (spDomain) {\n responseBody.spDomain = spDomain;\n }\n if (tunnelState?.tunnelConfig?.tunnelToken) {\n responseBody.tunnelToken = tunnelState.tunnelConfig.tunnelToken;\n }\n if (tunnelState?.tunnelConfig?.provider) {\n responseBody.tunnelProvider = tunnelState.tunnelConfig.provider;\n }\n if (tunnelState?.tunnelConfig?.endpoint) {\n responseBody.tunnelEndpoint = tunnelState.tunnelConfig.endpoint;\n }\n\n sendJson(response, 201, responseBody);\n } catch (error) {\n if (error instanceof InvalidTunnelTokenError) {\n sendJson(response, 400, { error: error.message });\n return;\n }\n logger.error(`Failed to register SP node: ${error}`);\n sendJson(response, 500, { error: 'Failed to register SP node' });\n }\n }, { public: true });\n\n logger.info('Provision routes registered');\n}\n\ninterface ManagedTunnelState {\n mode: 'direct' | 'tunnel';\n tunnelConfig?: TunnelConfig;\n}\n\nclass InvalidTunnelTokenError extends Error {}\n\nasync function ensureManagedTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n nodeId: string;\n subdomainPrefix?: string;\n baseStorageDomain?: string;\n publicUrl: string;\n localPort?: number;\n ipv4?: string;\n tunnelToken?: string;\n}): Promise<ManagedTunnelState | undefined> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n ipv4,\n tunnelToken,\n } = options;\n\n if (!subdomainPrefix || !baseStorageDomain) {\n return undefined;\n }\n\n const mode: 'direct' | 'tunnel' = ipv4 ? 'direct' : 'tunnel';\n\n if (mode === 'direct') {\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: ipv4,\n });\n }\n }\n\n return { mode };\n }\n\n if (tunnelToken) {\n if (!localPort || localPort <= 0) {\n throw new InvalidTunnelTokenError('localPort is required when tunnelToken is provided');\n }\n\n return {\n mode,\n tunnelConfig: await ensureManagedTokenTunnelState({\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n }),\n };\n }\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n });\n }\n }\n\n if (!tunnelProvider || !localPort || localPort <= 0) {\n return { mode };\n }\n\n const metadataRecord = await repository.getNodeMetadata(nodeId);\n const metadata = metadataRecord?.metadata as Record<string, unknown> | null;\n const existingTunnel = readManagedTunnelConfig(metadata);\n if (existingTunnel && existingTunnel.subdomain === subdomainPrefix && existingTunnel.localPort === localPort) {\n return {\n mode,\n tunnelConfig: existingTunnel.config,\n };\n }\n\n const tunnelConfig = await tunnelProvider.setup({\n subdomain: subdomainPrefix,\n localPort,\n });\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: tunnelConfig.provider,\n tunnelId: tunnelConfig.tunnelId,\n tunnelToken: tunnelConfig.tunnelToken,\n endpoint: tunnelConfig.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n },\n });\n\n return {\n mode,\n tunnelConfig,\n };\n}\n\nasync function ensureManagedTokenTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n nodeId: string;\n subdomainPrefix: string;\n baseStorageDomain: string;\n publicUrl: string;\n localPort: number;\n tunnelToken: string;\n}): Promise<TunnelConfig> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n } = options;\n\n const parsed = parseCloudflareTunnelToken(tunnelToken);\n if (!parsed?.tunnelId) {\n throw new InvalidTunnelTokenError('Invalid Cloudflare tunnel token');\n }\n\n const endpoint = `https://${subdomainPrefix}.${baseStorageDomain}`;\n const cnameTarget = `${parsed.tunnelId}.cfargotunnel.com`;\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: cnameTarget,\n recordType: 'CNAME',\n });\n } else if (\n existing.recordType !== 'CNAME'\n || existing.ipAddress !== cnameTarget\n || existing.ipv6Address\n ) {\n await ddnsRepo.updateRecordIp(subdomainPrefix, {\n ipAddress: cnameTarget,\n ipv6Address: null,\n recordType: 'CNAME',\n });\n }\n }\n\n if (dnsProvider) {\n await dnsProvider.upsertRecord({\n domain: baseStorageDomain,\n subdomain: subdomainPrefix,\n type: 'CNAME',\n value: cnameTarget,\n ttl: 60,\n });\n }\n\n const config: TunnelConfig = {\n provider: 'cloudflare',\n subdomain: subdomainPrefix,\n endpoint,\n tunnelId: parsed.tunnelId,\n tunnelToken,\n };\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: config.provider,\n tunnelId: config.tunnelId,\n tunnelToken: config.tunnelToken,\n endpoint: config.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n source: 'client-token',\n },\n });\n\n return config;\n}\n\nfunction parseCloudflareTunnelToken(token: string): { accountId?: string; tunnelId?: string } | undefined {\n const decoded = decodeJsonBase64UrlSegment(token) ?? decodeJsonBase64UrlSegment(token.split('.')[0] ?? '');\n if (!decoded || typeof decoded !== 'object') {\n return undefined;\n }\n\n const value = decoded as Record<string, unknown>;\n return {\n accountId: typeof value.a === 'string' ? value.a : undefined,\n tunnelId: typeof value.t === 'string' ? value.t : undefined,\n };\n}\n\nfunction decodeJsonBase64UrlSegment(segment: string): unknown {\n if (!segment) {\n return undefined;\n }\n\n try {\n const normalized = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n const json = Buffer.from(`${normalized}${padding}`, 'base64').toString('utf8');\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction readManagedTunnelConfig(metadata: Record<string, unknown> | null): { subdomain?: string; localPort?: number; config: TunnelConfig } | undefined {\n const raw = metadata?.managedTunnel;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n const value = raw as Record<string, unknown>;\n const provider = value.provider;\n const endpoint = value.endpoint;\n const tunnelToken = value.tunnelToken;\n const tunnelId = value.tunnelId;\n const subdomain = typeof value.subdomain === 'string' ? value.subdomain : undefined;\n const localPort = typeof value.localPort === 'number' ? value.localPort : undefined;\n\n if (\n (provider !== 'cloudflare' && provider !== 'frp' && provider !== 'sakura-frp')\n || typeof endpoint !== 'string'\n ) {\n return undefined;\n }\n\n return {\n subdomain,\n localPort,\n config: {\n provider,\n subdomain: subdomain ?? 'local',\n endpoint,\n tunnelId: typeof tunnelId === 'string' ? tunnelId : undefined,\n tunnelToken: typeof tunnelToken === 'string' ? tunnelToken : undefined,\n },\n };\n}\n\n/**\n * Local 端 SP 状态查询路由\n */\nexport interface ProvisionStatusOptions {\n /** Cloud API 端点 */\n cloudUrl?: string;\n /** 节点 ID */\n nodeId?: string;\n /** 节点 Token */\n nodeToken?: string;\n /** SP service token,刷新 provisionCode 时回传给 Cloud */\n serviceToken?: string;\n /** 当前 SP canonical public URL */\n publicUrl?: string;\n /** SP 子域名 */\n spDomain?: string;\n /** 本地端口,供 Cloud 管理 tunnel 元数据 */\n localPort?: number;\n /** tunnel token,供 Cloud 维护托管域名连通性 */\n tunnelToken?: string;\n /** Cloud baseUrl,用于拼 provisionUrl */\n cloudBaseUrl?: string;\n /** provisionCode(可选,由环境变量传入) */\n provisionCode?: string;\n /** Persist refreshed local-only setup state to the single local setup file. */\n persistState?: (state: ProvisionStatusStateUpdate) => Promise<void> | void;\n /** 测试/调试注入 */\n fetchImpl?: typeof fetch;\n now?: () => number;\n refreshGraceSeconds?: number;\n}\n\nexport interface ProvisionStatusStateUpdate {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n provisionCode: string;\n publicUrl?: string;\n spDomain?: string;\n cloudUrl?: string;\n cloudBaseUrl?: string;\n}\n\nexport function registerProvisionStatusRoute(\n server: ApiServer,\n options: ProvisionStatusOptions,\n): void {\n const logger = getLoggerFor('ProvisionStatusHandler');\n const fetchImpl = options.fetchImpl ?? fetch;\n const now = options.now ?? (() => Date.now());\n const refreshGraceSeconds = options.refreshGraceSeconds ?? PROVISION_STATUS_REFRESH_GRACE_SECONDS;\n const state: ProvisionStatusState = {\n provisionCode: options.provisionCode,\n nodeId: options.nodeId,\n nodeToken: options.nodeToken,\n serviceToken: options.serviceToken,\n publicUrl: normalizeUrl(options.publicUrl),\n spDomain: options.spDomain,\n };\n let refreshPromise: Promise<void> | undefined;\n\n server.get('/provision/status', async (_request, response) => {\n const registered = Boolean(options.nodeId && options.cloudUrl);\n\n const body: Record<string, unknown> = {\n registered,\n };\n\n if (registered) {\n const canRefresh = canRefreshProvisionStatus(options, state);\n const currentNow = now();\n const fresh = isProvisionCodeFresh(state.provisionCode, currentNow, refreshGraceSeconds);\n const codeState = inspectProvisionCodeExpiration(state.provisionCode);\n if (!canRefresh && codeState.kind !== 'missing' && !isProvisionCodeUsable(state.provisionCode, currentNow)) {\n sendJson(response, 503, {\n registered: true,\n error: 'provision_refresh_unavailable',\n message: 'Local provision state is expired and cannot be refreshed. Please restart Local or try again.',\n });\n return;\n }\n\n if (canRefresh && !fresh) {\n let didRefresh = false;\n refreshPromise ??= refreshProvisionStatus({\n options,\n state,\n fetchImpl,\n logger,\n }).finally(() => {\n refreshPromise = undefined;\n });\n try {\n await refreshPromise;\n didRefresh = true;\n } catch (error) {\n logger.warn(`Failed to refresh provisionCode for ${state.nodeId}: ${error}`);\n if (!isProvisionCodeUsable(state.provisionCode, now())) {\n sendJson(response, 503, {\n registered: true,\n error: 'provision_refresh_failed',\n message: 'Local provision state could not be refreshed. Please restart Local or try again.',\n });\n return;\n }\n }\n if (didRefresh) {\n await persistProvisionStatusState(options, state, logger);\n }\n }\n\n body.cloudUrl = options.cloudUrl;\n body.nodeId = state.nodeId ?? options.nodeId;\n if (state.spDomain) {\n body.spDomain = state.spDomain;\n }\n if (state.publicUrl) {\n body.publicUrl = state.publicUrl;\n }\n if (state.provisionCode) {\n body.provisionCode = state.provisionCode;\n }\n if (options.cloudBaseUrl) {\n const provisionUrl = state.provisionCode\n ? `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`\n : `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/`;\n body.provisionUrl = provisionUrl;\n }\n }\n\n sendJson(response, 200, body);\n }, { public: true });\n\n logger.info('Provision status route registered');\n}\n\nexport function createLocalSetupProvisionStateWriter(\n setupPath: string | undefined,\n providerId: string | undefined,\n): ProvisionStatusOptions['persistState'] | undefined {\n if (!setupPath?.trim() || !providerId?.trim()) {\n return undefined;\n }\n\n const targetPath = path.resolve(setupPath);\n const targetProviderId = providerId.trim();\n return async (state): Promise<void> => {\n upsertLocalSetupFile(targetPath, targetProviderId, state);\n };\n}\n\nasync function persistProvisionStatusState(\n options: ProvisionStatusOptions,\n state: ProvisionStatusState,\n logger: ReturnType<typeof getLoggerFor>,\n): Promise<void> {\n if (!options.persistState || !state.nodeId || !state.nodeToken || !state.serviceToken || !state.provisionCode) {\n return;\n }\n\n try {\n await options.persistState({\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n provisionCode: state.provisionCode,\n publicUrl: state.publicUrl,\n spDomain: state.spDomain,\n cloudUrl: options.cloudUrl,\n cloudBaseUrl: options.cloudBaseUrl,\n });\n } catch (error) {\n logger.warn(`Failed to persist refreshed local provision state: ${error}`);\n }\n}\n\nfunction upsertLocalSetupFile(\n filePath: string,\n providerId: string,\n state: ProvisionStatusStateUpdate,\n): void {\n const existing = readJsonObjectFile(filePath);\n const previous = readJsonObject(existing[providerId]);\n const cloudIdentityUrl = normalizeUrl(state.cloudBaseUrl);\n const cloudApiUrl = normalizeUrl(state.cloudUrl);\n const provisionUrl = cloudIdentityUrl\n ? `${cloudIdentityUrl.replace(/\\/+$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`\n : readString(previous.provisionUrl);\n\n existing[providerId] = {\n ...previous,\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n provisionCode: state.provisionCode,\n publicUrl: normalizeUrl(state.publicUrl),\n spDomain: readString(state.spDomain),\n provisionUrl,\n cloudIdentityUrl,\n cloudApiUrl,\n registeredAt: typeof previous.registeredAt === 'number' && Number.isFinite(previous.registeredAt)\n ? previous.registeredAt\n : Date.now(),\n };\n\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, `${JSON.stringify(existing, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // Some filesystems do not support chmod; the local runtime can still proceed.\n }\n}\n\nfunction readJsonObjectFile(filePath: string): Record<string, unknown> {\n try {\n if (!fs.existsSync(filePath)) {\n return {};\n }\n\n return readJsonObject(JSON.parse(fs.readFileSync(filePath, 'utf8')));\n } catch {\n return {};\n }\n}\n\nfunction readJsonObject(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\ninterface ProvisionStatusState {\n provisionCode?: string;\n nodeId?: string;\n nodeToken?: string;\n serviceToken?: string;\n publicUrl?: string;\n spDomain?: string;\n}\n\ninterface ProvisionNodeRefreshResponse {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n provisionCode: string;\n publicUrl?: string;\n spDomain?: string;\n}\n\nfunction canRefreshProvisionStatus(options: ProvisionStatusOptions, state: ProvisionStatusState): boolean {\n return Boolean(\n options.cloudUrl\n && state.nodeId\n && state.nodeToken\n && state.serviceToken\n && state.publicUrl,\n );\n}\n\nasync function refreshProvisionStatus(options: {\n options: ProvisionStatusOptions;\n state: ProvisionStatusState;\n fetchImpl: typeof fetch;\n logger: ReturnType<typeof getLoggerFor>;\n}): Promise<void> {\n const { options: statusOptions, state, fetchImpl, logger } = options;\n const endpoint = new URL('/provision/nodes', ensureTrailingSlash(statusOptions.cloudUrl!)).toString();\n const requestBody: Record<string, unknown> = {\n publicUrl: state.publicUrl,\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n domainMode: state.spDomain ? 'managed' : 'self-managed',\n spDomain: state.spDomain,\n };\n\n if (statusOptions.localPort && statusOptions.localPort > 0) {\n requestBody.localPort = statusOptions.localPort;\n }\n if (statusOptions.tunnelToken) {\n requestBody.tunnelToken = statusOptions.tunnelToken;\n requestBody.tunnelMode = 'client';\n }\n\n const result = await fetchImpl(endpoint, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!result.ok) {\n const detail = await result.text().catch(() => '');\n throw new Error(detail || `HTTP ${result.status}`);\n }\n\n const payload = await result.json().catch(() => undefined) as Partial<ProvisionNodeRefreshResponse> | undefined;\n if (\n !payload\n || typeof payload.nodeId !== 'string'\n || typeof payload.nodeToken !== 'string'\n || typeof payload.serviceToken !== 'string'\n || typeof payload.provisionCode !== 'string'\n ) {\n throw new Error('Cloud returned an incomplete provision refresh response.');\n }\n\n state.nodeId = payload.nodeId;\n state.nodeToken = payload.nodeToken;\n state.serviceToken = payload.serviceToken;\n state.provisionCode = payload.provisionCode;\n state.publicUrl = normalizeUrl(payload.publicUrl) ?? state.publicUrl;\n state.spDomain = typeof payload.spDomain === 'string' ? payload.spDomain : state.spDomain;\n\n process.env.XPOD_NODE_ID = state.nodeId;\n process.env.XPOD_NODE_TOKEN = state.nodeToken;\n process.env.XPOD_SERVICE_TOKEN = state.serviceToken;\n process.env.XPOD_PROVISION_CODE = state.provisionCode;\n if (statusOptions.cloudBaseUrl) {\n process.env.XPOD_PROVISION_URL = `${statusOptions.cloudBaseUrl.replace(/\\/$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`;\n }\n if (state.spDomain) {\n process.env.XPOD_SP_DOMAIN = state.spDomain;\n }\n\n logger.info(`Refreshed provisionCode for ${state.nodeId}`);\n}\n\nfunction isProvisionCodeFresh(code: string | undefined, nowMs: number, graceSeconds: number): boolean {\n const state = inspectProvisionCodeExpiration(code);\n return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000) + graceSeconds;\n}\n\nfunction isProvisionCodeUsable(code: string | undefined, nowMs: number): boolean {\n const state = inspectProvisionCodeExpiration(code);\n if (state.kind === 'legacy') {\n return true;\n }\n return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000);\n}\n\nfunction inspectProvisionCodeExpiration(code: string | undefined): { kind: 'missing' | 'legacy' | 'invalid' } | { kind: 'self-contained'; expiresAt: number } {\n if (!code) {\n return { kind: 'missing' };\n }\n const dotIndex = code.indexOf('.');\n if (dotIndex <= 0) {\n return { kind: 'legacy' };\n }\n\n try {\n const payload = JSON.parse(Buffer.from(code.slice(0, dotIndex), 'base64url').toString('utf8')) as { exp?: unknown };\n return typeof payload.exp === 'number' && Number.isFinite(payload.exp)\n ? { kind: 'self-contained', expiresAt: payload.exp }\n : { kind: 'invalid' };\n } catch {\n return { kind: 'invalid' };\n }\n}\n\nfunction ensureTrailingSlash(value: string): string {\n return value.endsWith('/') ? value : `${value}/`;\n}\n\nfunction normalizeUrl(value: string | undefined): string | undefined {\n if (!value?.trim()) {\n return undefined;\n }\n\n try {\n return new URL(value.trim()).toString().replace(/\\/+$/u, '') + '/';\n } catch {\n return value.trim().replace(/\\/+$/u, '') + '/';\n }\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\nfunction derivePublicUrlFromSpDomain(spDomain: string | undefined): string | undefined {\n return spDomain ? `https://${spDomain}/` : undefined;\n}\n\nfunction normalizeRequestedManagedDomain(value: string | undefined, baseStorageDomain: string | undefined): string | undefined {\n if (!value || !baseStorageDomain) {\n return undefined;\n }\n\n const domain = value.trim().toLowerCase().replace(/^https?:\\/\\//u, '').replace(/\\/.*$/u, '').replace(/\\.$/u, '');\n const suffix = `.${baseStorageDomain.toLowerCase()}`;\n if (!domain.endsWith(suffix)) {\n return undefined;\n }\n\n const prefix = domain.slice(0, -suffix.length).replace(/[^a-z0-9-]/giu, '').slice(0, 63);\n if (!prefix) {\n return undefined;\n }\n\n return `${prefix}.${baseStorageDomain}`;\n}\n\nfunction resolveManagedSubdomainPrefix(options: {\n domainMode: 'managed' | 'self-managed';\n baseStorageDomain?: string;\n requestedManagedDomain?: string;\n nodeId: string;\n}): string | undefined {\n if (options.domainMode !== 'managed' || !options.baseStorageDomain) {\n return undefined;\n }\n\n if (options.requestedManagedDomain) {\n const suffix = `.${options.baseStorageDomain}`;\n return options.requestedManagedDomain.slice(0, -suffix.length);\n }\n\n return options.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || options.nodeId.split('-')[0];\n}\n"]}
@@ -226,18 +226,6 @@ function extractQuotaFields(payload) {
226
226
  }
227
227
  }
228
228
  }
229
- // Backward compat: support legacy 'quotaLimit' field
230
- if (!hasField && Object.prototype.hasOwnProperty.call(payload, 'quotaLimit')) {
231
- const value = payload.quotaLimit;
232
- if (value === null) {
233
- result.storageLimitBytes = null;
234
- hasField = true;
235
- }
236
- else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {
237
- result.storageLimitBytes = value;
238
- hasField = true;
239
- }
240
- }
241
229
  return hasField ? result : undefined;
242
230
  }
243
231
  function hasCustomQuota(usage) {
@@ -1 +1 @@
1
- {"version":3,"file":"QuotaHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/QuotaHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport type { ApiServer } from '../ApiServer';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport type { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { hasScope } from '../auth/AuthContext';\n\nexport interface QuotaHandlerOptions {\n quotaService: QuotaService;\n usageRepo: UsageRepository;\n}\n\n/**\n * Handler for quota management API\n *\n * Supports four resource types: storage, bandwidth, compute, token.\n * Requires ServiceAuthContext with 'quota:write' scope for mutations.\n *\n * GET /v1/quota/accounts/:accountId - Get account quota + usage\n * PUT /v1/quota/accounts/:accountId - Set account quota\n * DELETE /v1/quota/accounts/:accountId - Clear account quota (revert to defaults)\n * GET /v1/quota/pods/:podId - Get pod quota + usage\n * PUT /v1/quota/pods/:podId - Set pod quota\n * DELETE /v1/quota/pods/:podId - Clear pod quota\n */\nexport function registerQuotaRoutes(server: ApiServer, options: QuotaHandlerOptions): void {\n const logger = getLoggerFor('QuotaHandler');\n const { quotaService, usageRepo } = options;\n\n // GET /v1/quota/accounts/:accountId\n server.get('/v1/quota/accounts/:accountId', async (request, response, params) => {\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n const quota = await quotaService.getAccountQuota(accountId);\n const usage = await usageRepo.getAccountUsage(accountId);\n\n sendJson(response, 200, {\n accountId,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/accounts/:accountId\n server.put('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field (storageLimitBytes, bandwidthLimitBps, computeLimitSeconds, tokenLimitMonthly)' });\n return;\n }\n\n try {\n await quotaService.setAccountQuota(accountId, partial);\n const latest = await quotaService.getAccountQuota(accountId);\n\n logger.info(`Set account ${accountId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n accountId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/accounts/:accountId\n server.delete('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n await quotaService.clearAccountQuota(accountId);\n\n logger.info(`Cleared account ${accountId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n accountId,\n });\n } catch (error) {\n logger.error(`Failed to clear account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n\n // GET /v1/quota/pods/:podId\n server.get('/v1/quota/pods/:podId', async (request, response, params) => {\n const podId = decodeURIComponent(params.podId);\n\n try {\n const quota = await quotaService.getPodQuota(podId);\n const usage = await usageRepo.getPodUsage(podId);\n\n sendJson(response, 200, {\n podId,\n accountId: usage?.accountId ?? null,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/pods/:podId\n server.put('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field' });\n return;\n }\n\n try {\n await quotaService.setPodQuota(podId, partial);\n const latest = await quotaService.getPodQuota(podId);\n\n logger.info(`Set pod ${podId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n podId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/pods/:podId\n server.delete('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n\n try {\n await quotaService.clearPodQuota(podId);\n\n logger.info(`Cleared pod ${podId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n podId,\n });\n } catch (error) {\n logger.error(`Failed to clear pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n}\n\n/**\n * Check if the request has the required scope. Sends 403 if not.\n */\nfunction requireScope(request: AuthenticatedRequest, response: ServerResponse, scope: string): boolean {\n if (!request.auth) {\n sendJson(response, 401, { error: 'Authentication required' });\n return false;\n }\n // Service tokens need explicit scope; Solid users with admin role can also access\n if (request.auth.type === 'service') {\n if (!hasScope(request.auth, scope)) {\n sendJson(response, 403, { error: `Missing required scope: ${scope}` });\n return false;\n }\n return true;\n }\n // Allow Solid auth (for admin users) - actual admin check can be added later\n if (request.auth.type === 'solid') {\n return true;\n }\n sendJson(response, 403, { error: 'Insufficient permissions' });\n return false;\n}\n\nconst QUOTA_FIELDS = ['storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly'] as const;\n\nfunction extractQuotaFields(payload: Record<string, unknown>): Record<string, number | null> | undefined {\n const result: Record<string, number | null> = {};\n let hasField = false;\n\n for (const field of QUOTA_FIELDS) {\n if (Object.prototype.hasOwnProperty.call(payload, field)) {\n const value = payload[field];\n if (value === null) {\n result[field] = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result[field] = value;\n hasField = true;\n } else {\n return undefined; // Invalid value\n }\n }\n }\n\n // Backward compat: support legacy 'quotaLimit' field\n if (!hasField && Object.prototype.hasOwnProperty.call(payload, 'quotaLimit')) {\n const value = payload.quotaLimit;\n if (value === null) {\n result.storageLimitBytes = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result.storageLimitBytes = value;\n hasField = true;\n }\n }\n\n return hasField ? result : undefined;\n}\n\nfunction hasCustomQuota(usage: { storageLimitBytes?: number | null; bandwidthLimitBps?: number | null; computeLimitSeconds?: number | null; tokenLimitMonthly?: number | null } | undefined): boolean {\n if (!usage) {\n return false;\n }\n return typeof usage.storageLimitBytes === 'number'\n || typeof usage.bandwidthLimitBps === 'number'\n || typeof usage.computeLimitSeconds === 'number'\n || typeof usage.tokenLimitMonthly === 'number';\n}\n\nasync function readJsonBody(request: AuthenticatedRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
1
+ {"version":3,"file":"QuotaHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/QuotaHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport type { ApiServer } from '../ApiServer';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport type { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { hasScope } from '../auth/AuthContext';\n\nexport interface QuotaHandlerOptions {\n quotaService: QuotaService;\n usageRepo: UsageRepository;\n}\n\n/**\n * Handler for quota management API\n *\n * Supports four resource types: storage, bandwidth, compute, token.\n * Requires ServiceAuthContext with 'quota:write' scope for mutations.\n *\n * GET /v1/quota/accounts/:accountId - Get account quota + usage\n * PUT /v1/quota/accounts/:accountId - Set account quota\n * DELETE /v1/quota/accounts/:accountId - Clear account quota (revert to defaults)\n * GET /v1/quota/pods/:podId - Get pod quota + usage\n * PUT /v1/quota/pods/:podId - Set pod quota\n * DELETE /v1/quota/pods/:podId - Clear pod quota\n */\nexport function registerQuotaRoutes(server: ApiServer, options: QuotaHandlerOptions): void {\n const logger = getLoggerFor('QuotaHandler');\n const { quotaService, usageRepo } = options;\n\n // GET /v1/quota/accounts/:accountId\n server.get('/v1/quota/accounts/:accountId', async (request, response, params) => {\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n const quota = await quotaService.getAccountQuota(accountId);\n const usage = await usageRepo.getAccountUsage(accountId);\n\n sendJson(response, 200, {\n accountId,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/accounts/:accountId\n server.put('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field (storageLimitBytes, bandwidthLimitBps, computeLimitSeconds, tokenLimitMonthly)' });\n return;\n }\n\n try {\n await quotaService.setAccountQuota(accountId, partial);\n const latest = await quotaService.getAccountQuota(accountId);\n\n logger.info(`Set account ${accountId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n accountId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/accounts/:accountId\n server.delete('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n await quotaService.clearAccountQuota(accountId);\n\n logger.info(`Cleared account ${accountId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n accountId,\n });\n } catch (error) {\n logger.error(`Failed to clear account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n\n // GET /v1/quota/pods/:podId\n server.get('/v1/quota/pods/:podId', async (request, response, params) => {\n const podId = decodeURIComponent(params.podId);\n\n try {\n const quota = await quotaService.getPodQuota(podId);\n const usage = await usageRepo.getPodUsage(podId);\n\n sendJson(response, 200, {\n podId,\n accountId: usage?.accountId ?? null,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/pods/:podId\n server.put('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field' });\n return;\n }\n\n try {\n await quotaService.setPodQuota(podId, partial);\n const latest = await quotaService.getPodQuota(podId);\n\n logger.info(`Set pod ${podId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n podId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/pods/:podId\n server.delete('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n\n try {\n await quotaService.clearPodQuota(podId);\n\n logger.info(`Cleared pod ${podId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n podId,\n });\n } catch (error) {\n logger.error(`Failed to clear pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n}\n\n/**\n * Check if the request has the required scope. Sends 403 if not.\n */\nfunction requireScope(request: AuthenticatedRequest, response: ServerResponse, scope: string): boolean {\n if (!request.auth) {\n sendJson(response, 401, { error: 'Authentication required' });\n return false;\n }\n // Service tokens need explicit scope; Solid users with admin role can also access\n if (request.auth.type === 'service') {\n if (!hasScope(request.auth, scope)) {\n sendJson(response, 403, { error: `Missing required scope: ${scope}` });\n return false;\n }\n return true;\n }\n // Allow Solid auth (for admin users) - actual admin check can be added later\n if (request.auth.type === 'solid') {\n return true;\n }\n sendJson(response, 403, { error: 'Insufficient permissions' });\n return false;\n}\n\nconst QUOTA_FIELDS = ['storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly'] as const;\n\nfunction extractQuotaFields(payload: Record<string, unknown>): Record<string, number | null> | undefined {\n const result: Record<string, number | null> = {};\n let hasField = false;\n\n for (const field of QUOTA_FIELDS) {\n if (Object.prototype.hasOwnProperty.call(payload, field)) {\n const value = payload[field];\n if (value === null) {\n result[field] = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result[field] = value;\n hasField = true;\n } else {\n return undefined; // Invalid value\n }\n }\n }\n\n return hasField ? result : undefined;\n}\n\nfunction hasCustomQuota(usage: { storageLimitBytes?: number | null; bandwidthLimitBps?: number | null; computeLimitSeconds?: number | null; tokenLimitMonthly?: number | null } | undefined): boolean {\n if (!usage) {\n return false;\n }\n return typeof usage.storageLimitBytes === 'number'\n || typeof usage.bandwidthLimitBps === 'number'\n || typeof usage.computeLimitSeconds === 'number'\n || typeof usage.tokenLimitMonthly === 'number';\n}\n\nasync function readJsonBody(request: AuthenticatedRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
@@ -5,7 +5,6 @@ export * from './ChatHandler';
5
5
  export * from './VectorHandler';
6
6
  export * from './VectorStoreHandler';
7
7
  export * from './VectorStoreWebhookHandler';
8
- export * from './ApiKeyHandler';
9
8
  export * from './SubdomainHandler';
10
9
  export * from './SubdomainClientHandler';
11
10
  export * from './ChatKitHandler';
@@ -21,7 +21,6 @@ __exportStar(require("./ChatHandler"), exports);
21
21
  __exportStar(require("./VectorHandler"), exports);
22
22
  __exportStar(require("./VectorStoreHandler"), exports);
23
23
  __exportStar(require("./VectorStoreWebhookHandler"), exports);
24
- __exportStar(require("./ApiKeyHandler"), exports);
25
24
  __exportStar(require("./SubdomainHandler"), exports);
26
25
  __exportStar(require("./SubdomainClientHandler"), exports);
27
26
  __exportStar(require("./ChatKitHandler"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/handlers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,iDAA+B;AAC/B,gDAA8B;AAC9B,gDAA8B;AAC9B,kDAAgC;AAChC,uDAAqC;AACrC,8DAA4C;AAC5C,kDAAgC;AAChC,qDAAmC;AACnC,2DAAyC;AACzC,mDAAiC;AACjC,kDAAgC;AAChC,+CAA6B;AAC7B,qDAAmC;AACnC,yDAAuC","sourcesContent":["export * from './EdgeNodeSignalHandler';\nexport * from './QuotaHandler';\nexport * from './NodeHandler';\nexport * from './ChatHandler';\nexport * from './VectorHandler';\nexport * from './VectorStoreHandler';\nexport * from './VectorStoreWebhookHandler';\nexport * from './ApiKeyHandler';\nexport * from './SubdomainHandler';\nexport * from './SubdomainClientHandler';\nexport * from './ChatKitHandler';\nexport * from './MatrixHandler';\nexport * from './RunHandler';\nexport * from './ProvisionHandler';\nexport * from './PodManagementHandler';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/handlers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,iDAA+B;AAC/B,gDAA8B;AAC9B,gDAA8B;AAC9B,kDAAgC;AAChC,uDAAqC;AACrC,8DAA4C;AAC5C,qDAAmC;AACnC,2DAAyC;AACzC,mDAAiC;AACjC,kDAAgC;AAChC,+CAA6B;AAC7B,qDAAmC;AACnC,yDAAuC","sourcesContent":["export * from './EdgeNodeSignalHandler';\nexport * from './QuotaHandler';\nexport * from './NodeHandler';\nexport * from './ChatHandler';\nexport * from './VectorHandler';\nexport * from './VectorStoreHandler';\nexport * from './VectorStoreWebhookHandler';\nexport * from './SubdomainHandler';\nexport * from './SubdomainClientHandler';\nexport * from './ChatKitHandler';\nexport * from './MatrixHandler';\nexport * from './RunHandler';\nexport * from './ProvisionHandler';\nexport * from './PodManagementHandler';\n"]}
@@ -45,12 +45,16 @@ class PodMatrixStore {
45
45
  });
46
46
  await db.insert(models_1.threadResource).values({
47
47
  id: threadId,
48
- commandKind: 'chat',
49
- surfaceId: this.surfaceIdFromRoomId(roomId),
50
48
  chat: chatId,
51
49
  title: input.name ?? roomId,
52
50
  status: 'active',
53
- metadata: { protocol: 'matrix', roomId },
51
+ metadata: {
52
+ protocol: 'matrix',
53
+ roomId,
54
+ commandKind: 'chat',
55
+ surface_id: this.surfaceIdFromRoomId(roomId),
56
+ chat_id: this.surfaceIdFromRoomId(roomId),
57
+ },
54
58
  createdAt: new Date(now).toISOString(),
55
59
  updatedAt: new Date(now).toISOString(),
56
60
  });
@@ -119,7 +123,7 @@ class PodMatrixStore {
119
123
  async sendEvent(roomId, eventType, txnId, content, context) {
120
124
  const db = await this.getDb(context);
121
125
  await this.ensureRoomExists(db, roomId);
122
- const existing = await this.findEventByTxnId(db, roomId, txnId);
126
+ const existing = await this.findEventByTxnId(db, roomId, txnId, context);
123
127
  if (existing) {
124
128
  return existing;
125
129
  }
@@ -141,7 +145,7 @@ class PodMatrixStore {
141
145
  const limit = options.limit && options.limit > 0 ? options.limit : 50;
142
146
  const join = {};
143
147
  for (const room of rooms) {
144
- const events = await this.listEvents(db, room.roomId, {
148
+ const events = await this.listEvents(db, room.roomId, context, {
145
149
  sinceTs,
146
150
  limit,
147
151
  });
@@ -166,7 +170,7 @@ class PodMatrixStore {
166
170
  const limit = options.limit && options.limit > 0 ? options.limit : 50;
167
171
  const fromTs = this.parseSyncToken(options.from);
168
172
  const forward = options.dir === 'f';
169
- const events = await this.listEvents(db, roomId, {
173
+ const events = await this.listEvents(db, roomId, context, {
170
174
  sinceTs: forward && fromTs > 0 ? fromTs : undefined,
171
175
  beforeOrAtTs: !forward && fromTs > 0 ? fromTs : undefined,
172
176
  limit,
@@ -181,7 +185,7 @@ class PodMatrixStore {
181
185
  }
182
186
  async getEvent(roomId, eventId, context) {
183
187
  const db = await this.getDb(context);
184
- const event = await this.findEventById(db, roomId, eventId);
188
+ const event = await this.findEventById(db, roomId, eventId, context);
185
189
  if (!event) {
186
190
  throw new Error(`Matrix event not found: ${eventId}`);
187
191
  }
@@ -189,7 +193,7 @@ class PodMatrixStore {
189
193
  }
190
194
  async getState(roomId, eventType, stateKey, context) {
191
195
  const db = await this.getDb(context);
192
- const event = await this.findLatestStateEvent(db, roomId, eventType, stateKey);
196
+ const event = await this.findLatestStateEvent(db, roomId, eventType, stateKey, context);
193
197
  if (!event) {
194
198
  throw new Error(`Matrix state not found: ${eventType}/${stateKey}`);
195
199
  }
@@ -229,7 +233,7 @@ class PodMatrixStore {
229
233
  }
230
234
  async appendEvent(db, input, context) {
231
235
  const eventId = this.generateEventId(context);
232
- const depth = await this.nextEventDepth(db, input.roomId);
236
+ const depth = await this.nextEventDepth(db, input.roomId, context);
233
237
  const originIso = new Date(input.originServerTs).toISOString();
234
238
  const record = {
235
239
  eventId,
@@ -246,8 +250,6 @@ class PodMatrixStore {
246
250
  };
247
251
  await db.insert(models_1.messageResource).values({
248
252
  id: this.messageResourceIdFromEvent(input.roomId, eventId, input.originServerTs),
249
- commandKind: 'chat',
250
- surfaceId: this.surfaceIdFromRoomId(input.roomId),
251
253
  chat: this.chatResourceIdFromRoomId(input.roomId),
252
254
  thread: this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(input.roomId), context),
253
255
  maker: context.userId,
@@ -266,6 +268,9 @@ class PodMatrixStore {
266
268
  txnId: input.txnId ?? null,
267
269
  stateKey: input.stateKey ?? null,
268
270
  content: input.content,
271
+ commandKind: 'chat',
272
+ surface_id: this.surfaceIdFromRoomId(input.roomId),
273
+ chat_id: this.surfaceIdFromRoomId(input.roomId),
269
274
  },
270
275
  createdAt: originIso,
271
276
  updatedAt: originIso,
@@ -278,9 +283,9 @@ class PodMatrixStore {
278
283
  .map((room) => this.chatSourceToRoomRecord(room))
279
284
  .filter((room) => room !== undefined);
280
285
  }
281
- async listEvents(db, roomId, options = {}) {
286
+ async listEvents(db, roomId, context, options = {}) {
282
287
  const conditions = [
283
- (0, drizzle_solid_1.eq)(models_1.messageResource.surfaceId, this.surfaceIdFromRoomId(roomId)),
288
+ (0, drizzle_solid_1.eq)(models_1.messageResource.thread, this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(roomId), context)),
284
289
  options.sinceTs !== undefined ? (0, drizzle_solid_1.gt)(models_1.messageResource.createdAt, new Date(options.sinceTs).toISOString()) : undefined,
285
290
  options.beforeOrAtTs !== undefined ? (0, drizzle_solid_1.lte)(models_1.messageResource.createdAt, new Date(options.beforeOrAtTs).toISOString()) : undefined,
286
291
  ];
@@ -294,20 +299,20 @@ class PodMatrixStore {
294
299
  const events = await query;
295
300
  return events.map((event) => this.eventSourceToRecord(event));
296
301
  }
297
- async findEventByTxnId(db, roomId, txnId) {
298
- const records = await this.listEvents(db, roomId);
302
+ async findEventByTxnId(db, roomId, txnId, context) {
303
+ const records = await this.listEvents(db, roomId, context);
299
304
  return records.find((record) => record.txnId === txnId);
300
305
  }
301
- async findEventById(db, roomId, eventId) {
302
- const records = await this.listEvents(db, roomId);
306
+ async findEventById(db, roomId, eventId, context) {
307
+ const records = await this.listEvents(db, roomId, context);
303
308
  return records.find((record) => record.eventId === eventId);
304
309
  }
305
- async nextEventDepth(db, roomId) {
306
- const records = await this.listEvents(db, roomId);
310
+ async nextEventDepth(db, roomId, context) {
311
+ const records = await this.listEvents(db, roomId, context);
307
312
  return records.reduce((max, record) => Math.max(max, record.depth ?? 0), 0) + 1;
308
313
  }
309
- async findLatestStateEvent(db, roomId, eventType, stateKey) {
310
- const records = await this.listEvents(db, roomId, { newestFirst: true });
314
+ async findLatestStateEvent(db, roomId, eventType, stateKey, context) {
315
+ const records = await this.listEvents(db, roomId, context, { newestFirst: true });
311
316
  return records.find((record) => record.type === eventType && (record.stateKey ?? '') === stateKey);
312
317
  }
313
318
  eventSourceToRecord(source) {