@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
@@ -33,22 +33,6 @@
33
33
  {
34
34
  "@id": "undefineds:dist/quota/QuotaService.jsonld#QuotaService__member_clearPodQuota",
35
35
  "memberFieldName": "clearPodQuota"
36
- },
37
- {
38
- "@id": "undefineds:dist/quota/QuotaService.jsonld#QuotaService__member_getAccountLimit",
39
- "memberFieldName": "getAccountLimit"
40
- },
41
- {
42
- "@id": "undefineds:dist/quota/QuotaService.jsonld#QuotaService__member_getPodLimit",
43
- "memberFieldName": "getPodLimit"
44
- },
45
- {
46
- "@id": "undefineds:dist/quota/QuotaService.jsonld#QuotaService__member_setAccountLimit",
47
- "memberFieldName": "setAccountLimit"
48
- },
49
- {
50
- "@id": "undefineds:dist/quota/QuotaService.jsonld#QuotaService__member_setPodLimit",
51
- "memberFieldName": "setPodLimit"
52
36
  }
53
37
  ],
54
38
  "constructorArguments": []
@@ -4,7 +4,6 @@ export interface EdgeNodeSignalClientOptions {
4
4
  nodeId?: string;
5
5
  nodeToken?: string;
6
6
  baseUrl?: string;
7
- publicAddress?: string;
8
7
  ipv4?: string;
9
8
  ipv6?: string;
10
9
  pods?: string | string[];
@@ -35,7 +34,6 @@ export declare class EdgeNodeSignalClient {
35
34
  private readonly baseNodeId?;
36
35
  private readonly baseToken?;
37
36
  private readonly baseUrl?;
38
- private readonly publicAddress?;
39
37
  private readonly baseIpv4?;
40
38
  private readonly baseIpv6?;
41
39
  private readonly basePods?;
@@ -28,7 +28,6 @@ class EdgeNodeSignalClient {
28
28
  this.baseNodeId = nodeId;
29
29
  this.baseToken = nodeToken;
30
30
  this.baseUrl = this.normalizeString(options.baseUrl);
31
- this.publicAddress = this.normalizeString(options.publicAddress);
32
31
  this.baseIpv4 = this.normalizeString(options.ipv4);
33
32
  this.baseIpv6 = this.normalizeString(options.ipv6);
34
33
  this.basePods = this.normalizePods(options.pods);
@@ -82,9 +81,6 @@ class EdgeNodeSignalClient {
82
81
  if (this.baseUrl) {
83
82
  payload.baseUrl = this.baseUrl;
84
83
  }
85
- if (this.publicAddress) {
86
- payload.publicAddress = this.publicAddress;
87
- }
88
84
  // 获取网络地址(支持动态检测)
89
85
  let ipv4 = this.baseIpv4;
90
86
  let ipv6 = this.baseIpv6;
@@ -1 +1 @@
1
- {"version":3,"file":"EdgeNodeSignalClient.js","sourceRoot":"","sources":["../../src/service/EdgeNodeSignalClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLoggerFor } from 'global-logger-factory';\n\nexport interface EdgeNodeSignalClientOptions {\n edgeNodesEnabled?: string | boolean;\n signalEndpoint?: string;\n nodeId?: string;\n nodeToken?: string;\n baseUrl?: string;\n publicAddress?: string;\n ipv4?: string;\n ipv6?: string;\n pods?: string | string[];\n capabilities?: string | string[];\n reachability?: string;\n directCandidates?: string | string[];\n tunnel?: string;\n certificate?: string;\n metrics?: string;\n metadata?: string;\n intervalMs?: number | string;\n onHeartbeatResponse?: (data: unknown) => void;\n metadataSupplier?: () => Record<string, unknown> | undefined;\n metricsSupplier?: () => Record<string, unknown> | undefined;\n tunnelSupplier?: () => Record<string, unknown> | undefined;\n networkSupplier?: () => Promise<{ ipv4?: string; ipv6?: string }> | { ipv4?: string; ipv6?: string };\n}\n\ntype HeartbeatPayload = {\n nodeId: string;\n token: string;\n baseUrl?: string;\n publicAddress?: string;\n ipv4?: string;\n ipv6?: string;\n pods?: string[];\n capabilities?: string[];\n reachability?: Record<string, unknown>;\n directCandidates?: string[];\n tunnel?: Record<string, unknown>;\n certificate?: Record<string, unknown>;\n metrics?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport class EdgeNodeSignalClient {\n private readonly logger = getLoggerFor(this);\n private readonly interval?: NodeJS.Timeout;\n private readonly endpoint?: string;\n private readonly baseNodeId?: string;\n private readonly baseToken?: string;\n private readonly baseUrl?: string;\n private readonly publicAddress?: string;\n private readonly baseIpv4?: string;\n private readonly baseIpv6?: string;\n private readonly basePods?: string[];\n private readonly baseCapabilities?: string[];\n private readonly baseReachability?: Record<string, unknown>;\n private readonly baseDirectCandidates?: string[];\n private readonly baseTunnel?: Record<string, unknown>;\n private readonly baseCertificate?: Record<string, unknown>;\n private readonly baseMetrics?: Record<string, unknown>;\n private readonly baseMetadata?: Record<string, unknown>;\n private readonly tunnelSupplier?: () => Record<string, unknown> | undefined;\n private readonly metricsSupplier?: () => Record<string, unknown> | undefined;\n private readonly metadataSupplier?: () => Record<string, unknown> | undefined;\n private readonly networkSupplier?: () => Promise<{ ipv4?: string; ipv6?: string }> | { ipv4?: string; ipv6?: string };\n private readonly intervalMs: number = 30_000;\n private readonly onHeartbeatResponse?: (data: unknown) => void;\n\n public constructor(options: EdgeNodeSignalClientOptions) {\n const enabled = this.normalizeBoolean(options.edgeNodesEnabled);\n const endpoint = this.normalizeString(options.signalEndpoint);\n const nodeId = this.normalizeString(options.nodeId);\n const nodeToken = this.normalizeString(options.nodeToken);\n\n if (!enabled) {\n this.logger.debug('Edge node heartbeat service disabled.');\n return;\n }\n\n if (!endpoint || !nodeId || !nodeToken) {\n this.logger.warn('Edge node heartbeat service missing configuration (signal endpoint, nodeId, nodeToken).');\n return;\n }\n\n this.intervalMs = this.normalizeInterval(options.intervalMs) ?? this.intervalMs;\n this.endpoint = endpoint;\n this.onHeartbeatResponse = options.onHeartbeatResponse;\n this.metadataSupplier = options.metadataSupplier;\n this.metricsSupplier = options.metricsSupplier;\n this.tunnelSupplier = options.tunnelSupplier;\n this.networkSupplier = options.networkSupplier;\n\n this.baseNodeId = nodeId;\n this.baseToken = nodeToken;\n this.baseUrl = this.normalizeString(options.baseUrl);\n this.publicAddress = this.normalizeString(options.publicAddress);\n this.baseIpv4 = this.normalizeString(options.ipv4);\n this.baseIpv6 = this.normalizeString(options.ipv6);\n this.basePods = this.normalizePods(options.pods);\n this.baseCapabilities = this.normalizeStringArray(options.capabilities);\n this.baseReachability = this.normalizeJsonRecord(options.reachability, 'reachability');\n this.baseDirectCandidates = this.normalizeCandidates(options.directCandidates);\n this.baseTunnel = this.normalizeJsonRecord(options.tunnel, 'tunnel');\n this.baseCertificate = this.normalizeJsonRecord(options.certificate, 'certificate');\n this.baseMetrics = this.normalizeJsonRecord(options.metrics, 'metrics');\n this.baseMetadata = this.normalizeJsonRecord(options.metadata, 'metadata');\n\n void this.sendHeartbeat();\n if (this.intervalMs > 0) {\n this.interval = setInterval(() => {\n void this.sendHeartbeat();\n }, this.intervalMs);\n }\n }\n\n public dispose(): void {\n if (this.interval) {\n clearInterval(this.interval);\n }\n }\n\n private async sendHeartbeat(): Promise<void> {\n if (!this.endpoint || !this.baseNodeId || !this.baseToken) {\n return;\n }\n\n const payload: Record<string, unknown> = await this.buildPayload();\n\n try {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n this.logger.warn(`Edge node heartbeat failed: ${response.status} ${response.statusText}`);\n } else {\n this.logger.debug('Edge node heartbeat sent successfully.');\n await this.handleHeartbeatResponse(response);\n }\n } catch (error: unknown) {\n this.logger.error(`Edge node heartbeat error: ${(error as Error).message}`);\n }\n }\n\n private async buildPayload(): Promise<HeartbeatPayload> {\n const payload: HeartbeatPayload = {\n nodeId: this.baseNodeId!,\n token: this.baseToken!,\n };\n\n if (this.baseUrl) {\n payload.baseUrl = this.baseUrl;\n }\n if (this.publicAddress) {\n payload.publicAddress = this.publicAddress;\n }\n \n // 获取网络地址(支持动态检测)\n let ipv4 = this.baseIpv4;\n let ipv6 = this.baseIpv6;\n if (this.networkSupplier) {\n try {\n const networkInfo = await Promise.resolve(this.networkSupplier());\n ipv4 = networkInfo.ipv4 ?? ipv4;\n ipv6 = networkInfo.ipv6 ?? ipv6;\n } catch (error: unknown) {\n this.logger.debug(`Network detection failed: ${(error as Error).message}`);\n }\n }\n if (ipv4) {\n payload.ipv4 = ipv4;\n }\n if (ipv6) {\n payload.ipv6 = ipv6;\n }\n \n if (this.basePods && this.basePods.length > 0) {\n payload.pods = [ ...this.basePods ];\n }\n if (this.baseCapabilities && this.baseCapabilities.length > 0) {\n payload.capabilities = [ ...this.baseCapabilities ];\n }\n const reachability = this.mergeRecords(this.baseReachability, undefined);\n if (reachability && Object.keys(reachability).length > 0) {\n payload.reachability = reachability;\n }\n const directCandidates = this.baseDirectCandidates;\n if (directCandidates && directCandidates.length > 0) {\n payload.directCandidates = [ ...directCandidates ];\n }\n const tunnel = this.mergeRecords(this.baseTunnel, this.tunnelSupplier?.());\n if (tunnel && Object.keys(tunnel).length > 0) {\n payload.tunnel = tunnel;\n }\n const certificate = this.mergeRecords(this.baseCertificate, undefined);\n if (certificate && Object.keys(certificate).length > 0) {\n payload.certificate = certificate;\n }\n const metrics = this.mergeRecords(this.baseMetrics, this.metricsSupplier?.());\n if (metrics && Object.keys(metrics).length > 0) {\n payload.metrics = metrics;\n }\n const metadata = this.mergeRecords(this.baseMetadata, this.metadataSupplier?.());\n if (metadata && Object.keys(metadata).length > 0) {\n payload.metadata = metadata;\n }\n return payload;\n }\n\n private async handleHeartbeatResponse(response: Response): Promise<void> {\n if (!this.onHeartbeatResponse) {\n return;\n }\n const contentType = response.headers.get('content-type') ?? '';\n if (!contentType.includes('application/json')) {\n return;\n }\n try {\n const data = await response.json();\n this.onHeartbeatResponse(data);\n } catch (error: unknown) {\n this.logger.warn(`解析心跳响应 JSON 失败: ${(error as Error).message}`);\n }\n }\n\n private mergeRecords(base?: Record<string, unknown>, extra?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!base && !extra) {\n return undefined;\n }\n return { ...(base ?? {}), ...(extra ?? {}) };\n }\n\n private normalizeBoolean(value?: string | boolean): boolean {\n if (typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase();\n return normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on';\n }\n return false;\n }\n\n private normalizeString(value?: string): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n private normalizeInterval(value?: number | string): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value) && value > 0) {\n return value;\n }\n if (typeof value === 'string') {\n const parsed = Number(value);\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed;\n }\n }\n return undefined;\n }\n\n private normalizePods(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const pods = source\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n .map((entry) => {\n try {\n return new URL(entry).toString();\n } catch {\n this.logger.warn(`忽略无效的 Pod 基址: ${entry}`);\n return undefined;\n }\n })\n .filter((entry): entry is string => typeof entry === 'string');\n return pods.length > 0 ? pods : undefined;\n }\n\n private normalizeStringArray(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const items = source\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n return items.length > 0 ? Array.from(new Set(items)) : undefined;\n }\n\n private normalizeJsonRecord(value: string | undefined, field: string): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n try {\n const parsed = JSON.parse(value);\n if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n this.logger.warn(`忽略 ${field}:需要 JSON 对象。`);\n return undefined;\n }\n return parsed as Record<string, unknown>;\n } catch (error: unknown) {\n this.logger.warn(`无法解析 ${field} JSON:${(error as Error).message}`);\n return undefined;\n }\n }\n\n private normalizeCandidates(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const result: string[] = [];\n for (const entry of source) {\n const trimmed = entry.trim();\n if (trimmed.length === 0) {\n continue;\n }\n try {\n const normalized = new URL(trimmed).toString();\n if (!result.includes(normalized)) {\n result.push(normalized);\n }\n } catch {\n this.logger.warn(`忽略无效的候选地址: ${trimmed}`);\n }\n }\n return result.length > 0 ? result : undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"EdgeNodeSignalClient.js","sourceRoot":"","sources":["../../src/service/EdgeNodeSignalClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLoggerFor } from 'global-logger-factory';\n\nexport interface EdgeNodeSignalClientOptions {\n edgeNodesEnabled?: string | boolean;\n signalEndpoint?: string;\n nodeId?: string;\n nodeToken?: string;\n baseUrl?: string;\n ipv4?: string;\n ipv6?: string;\n pods?: string | string[];\n capabilities?: string | string[];\n reachability?: string;\n directCandidates?: string | string[];\n tunnel?: string;\n certificate?: string;\n metrics?: string;\n metadata?: string;\n intervalMs?: number | string;\n onHeartbeatResponse?: (data: unknown) => void;\n metadataSupplier?: () => Record<string, unknown> | undefined;\n metricsSupplier?: () => Record<string, unknown> | undefined;\n tunnelSupplier?: () => Record<string, unknown> | undefined;\n networkSupplier?: () => Promise<{ ipv4?: string; ipv6?: string }> | { ipv4?: string; ipv6?: string };\n}\n\ntype HeartbeatPayload = {\n nodeId: string;\n token: string;\n baseUrl?: string;\n ipv4?: string;\n ipv6?: string;\n pods?: string[];\n capabilities?: string[];\n reachability?: Record<string, unknown>;\n directCandidates?: string[];\n tunnel?: Record<string, unknown>;\n certificate?: Record<string, unknown>;\n metrics?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n};\n\nexport class EdgeNodeSignalClient {\n private readonly logger = getLoggerFor(this);\n private readonly interval?: NodeJS.Timeout;\n private readonly endpoint?: string;\n private readonly baseNodeId?: string;\n private readonly baseToken?: string;\n private readonly baseUrl?: string;\n private readonly baseIpv4?: string;\n private readonly baseIpv6?: string;\n private readonly basePods?: string[];\n private readonly baseCapabilities?: string[];\n private readonly baseReachability?: Record<string, unknown>;\n private readonly baseDirectCandidates?: string[];\n private readonly baseTunnel?: Record<string, unknown>;\n private readonly baseCertificate?: Record<string, unknown>;\n private readonly baseMetrics?: Record<string, unknown>;\n private readonly baseMetadata?: Record<string, unknown>;\n private readonly tunnelSupplier?: () => Record<string, unknown> | undefined;\n private readonly metricsSupplier?: () => Record<string, unknown> | undefined;\n private readonly metadataSupplier?: () => Record<string, unknown> | undefined;\n private readonly networkSupplier?: () => Promise<{ ipv4?: string; ipv6?: string }> | { ipv4?: string; ipv6?: string };\n private readonly intervalMs: number = 30_000;\n private readonly onHeartbeatResponse?: (data: unknown) => void;\n\n public constructor(options: EdgeNodeSignalClientOptions) {\n const enabled = this.normalizeBoolean(options.edgeNodesEnabled);\n const endpoint = this.normalizeString(options.signalEndpoint);\n const nodeId = this.normalizeString(options.nodeId);\n const nodeToken = this.normalizeString(options.nodeToken);\n\n if (!enabled) {\n this.logger.debug('Edge node heartbeat service disabled.');\n return;\n }\n\n if (!endpoint || !nodeId || !nodeToken) {\n this.logger.warn('Edge node heartbeat service missing configuration (signal endpoint, nodeId, nodeToken).');\n return;\n }\n\n this.intervalMs = this.normalizeInterval(options.intervalMs) ?? this.intervalMs;\n this.endpoint = endpoint;\n this.onHeartbeatResponse = options.onHeartbeatResponse;\n this.metadataSupplier = options.metadataSupplier;\n this.metricsSupplier = options.metricsSupplier;\n this.tunnelSupplier = options.tunnelSupplier;\n this.networkSupplier = options.networkSupplier;\n\n this.baseNodeId = nodeId;\n this.baseToken = nodeToken;\n this.baseUrl = this.normalizeString(options.baseUrl);\n this.baseIpv4 = this.normalizeString(options.ipv4);\n this.baseIpv6 = this.normalizeString(options.ipv6);\n this.basePods = this.normalizePods(options.pods);\n this.baseCapabilities = this.normalizeStringArray(options.capabilities);\n this.baseReachability = this.normalizeJsonRecord(options.reachability, 'reachability');\n this.baseDirectCandidates = this.normalizeCandidates(options.directCandidates);\n this.baseTunnel = this.normalizeJsonRecord(options.tunnel, 'tunnel');\n this.baseCertificate = this.normalizeJsonRecord(options.certificate, 'certificate');\n this.baseMetrics = this.normalizeJsonRecord(options.metrics, 'metrics');\n this.baseMetadata = this.normalizeJsonRecord(options.metadata, 'metadata');\n\n void this.sendHeartbeat();\n if (this.intervalMs > 0) {\n this.interval = setInterval(() => {\n void this.sendHeartbeat();\n }, this.intervalMs);\n }\n }\n\n public dispose(): void {\n if (this.interval) {\n clearInterval(this.interval);\n }\n }\n\n private async sendHeartbeat(): Promise<void> {\n if (!this.endpoint || !this.baseNodeId || !this.baseToken) {\n return;\n }\n\n const payload: Record<string, unknown> = await this.buildPayload();\n\n try {\n const response = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n this.logger.warn(`Edge node heartbeat failed: ${response.status} ${response.statusText}`);\n } else {\n this.logger.debug('Edge node heartbeat sent successfully.');\n await this.handleHeartbeatResponse(response);\n }\n } catch (error: unknown) {\n this.logger.error(`Edge node heartbeat error: ${(error as Error).message}`);\n }\n }\n\n private async buildPayload(): Promise<HeartbeatPayload> {\n const payload: HeartbeatPayload = {\n nodeId: this.baseNodeId!,\n token: this.baseToken!,\n };\n\n if (this.baseUrl) {\n payload.baseUrl = this.baseUrl;\n }\n \n // 获取网络地址(支持动态检测)\n let ipv4 = this.baseIpv4;\n let ipv6 = this.baseIpv6;\n if (this.networkSupplier) {\n try {\n const networkInfo = await Promise.resolve(this.networkSupplier());\n ipv4 = networkInfo.ipv4 ?? ipv4;\n ipv6 = networkInfo.ipv6 ?? ipv6;\n } catch (error: unknown) {\n this.logger.debug(`Network detection failed: ${(error as Error).message}`);\n }\n }\n if (ipv4) {\n payload.ipv4 = ipv4;\n }\n if (ipv6) {\n payload.ipv6 = ipv6;\n }\n \n if (this.basePods && this.basePods.length > 0) {\n payload.pods = [ ...this.basePods ];\n }\n if (this.baseCapabilities && this.baseCapabilities.length > 0) {\n payload.capabilities = [ ...this.baseCapabilities ];\n }\n const reachability = this.mergeRecords(this.baseReachability, undefined);\n if (reachability && Object.keys(reachability).length > 0) {\n payload.reachability = reachability;\n }\n const directCandidates = this.baseDirectCandidates;\n if (directCandidates && directCandidates.length > 0) {\n payload.directCandidates = [ ...directCandidates ];\n }\n const tunnel = this.mergeRecords(this.baseTunnel, this.tunnelSupplier?.());\n if (tunnel && Object.keys(tunnel).length > 0) {\n payload.tunnel = tunnel;\n }\n const certificate = this.mergeRecords(this.baseCertificate, undefined);\n if (certificate && Object.keys(certificate).length > 0) {\n payload.certificate = certificate;\n }\n const metrics = this.mergeRecords(this.baseMetrics, this.metricsSupplier?.());\n if (metrics && Object.keys(metrics).length > 0) {\n payload.metrics = metrics;\n }\n const metadata = this.mergeRecords(this.baseMetadata, this.metadataSupplier?.());\n if (metadata && Object.keys(metadata).length > 0) {\n payload.metadata = metadata;\n }\n return payload;\n }\n\n private async handleHeartbeatResponse(response: Response): Promise<void> {\n if (!this.onHeartbeatResponse) {\n return;\n }\n const contentType = response.headers.get('content-type') ?? '';\n if (!contentType.includes('application/json')) {\n return;\n }\n try {\n const data = await response.json();\n this.onHeartbeatResponse(data);\n } catch (error: unknown) {\n this.logger.warn(`解析心跳响应 JSON 失败: ${(error as Error).message}`);\n }\n }\n\n private mergeRecords(base?: Record<string, unknown>, extra?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!base && !extra) {\n return undefined;\n }\n return { ...(base ?? {}), ...(extra ?? {}) };\n }\n\n private normalizeBoolean(value?: string | boolean): boolean {\n if (typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase();\n return normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on';\n }\n return false;\n }\n\n private normalizeString(value?: string): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n private normalizeInterval(value?: number | string): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value) && value > 0) {\n return value;\n }\n if (typeof value === 'string') {\n const parsed = Number(value);\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed;\n }\n }\n return undefined;\n }\n\n private normalizePods(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const pods = source\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n .map((entry) => {\n try {\n return new URL(entry).toString();\n } catch {\n this.logger.warn(`忽略无效的 Pod 基址: ${entry}`);\n return undefined;\n }\n })\n .filter((entry): entry is string => typeof entry === 'string');\n return pods.length > 0 ? pods : undefined;\n }\n\n private normalizeStringArray(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const items = source\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n return items.length > 0 ? Array.from(new Set(items)) : undefined;\n }\n\n private normalizeJsonRecord(value: string | undefined, field: string): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n try {\n const parsed = JSON.parse(value);\n if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n this.logger.warn(`忽略 ${field}:需要 JSON 对象。`);\n return undefined;\n }\n return parsed as Record<string, unknown>;\n } catch (error: unknown) {\n this.logger.warn(`无法解析 ${field} JSON:${(error as Error).message}`);\n return undefined;\n }\n }\n\n private normalizeCandidates(value?: string | string[]): string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n const source = Array.isArray(value) ? value : value.split(/[\\n,]+/u);\n const result: string[] = [];\n for (const entry of source) {\n const trimmed = entry.trim();\n if (trimmed.length === 0) {\n continue;\n }\n try {\n const normalized = new URL(trimmed).toString();\n if (!result.includes(normalized)) {\n result.push(normalized);\n }\n } catch {\n this.logger.warn(`忽略无效的候选地址: ${trimmed}`);\n }\n }\n return result.length > 0 ? result : undefined;\n }\n}\n"]}
@@ -13,7 +13,7 @@ export interface MigrationResult {
13
13
  *
14
14
  * Simplified migration process:
15
15
  * 1. Validate pod and target node exist
16
- * 2. Update nodeId to target node (atomic update)
16
+ * 2. Update the Pod routing assignment to the target node
17
17
  *
18
18
  * Data does NOT need to be copied upfront:
19
19
  * - Metadata is in shared PostgreSQL (Quadstore), already accessible from all nodes
@@ -30,7 +30,7 @@ export declare class PodMigrationService {
30
30
  /**
31
31
  * Migrate a pod to a different node.
32
32
  *
33
- * This is instant - only updates the nodeId in database.
33
+ * This is instant - only updates the routing assignment in the database.
34
34
  * Subsequent requests will be routed to the new node.
35
35
  * Binary files are read via cross-region fallback if not present locally.
36
36
  */
@@ -10,7 +10,7 @@ const EdgeNodeRepository_1 = require("../identity/drizzle/EdgeNodeRepository");
10
10
  *
11
11
  * Simplified migration process:
12
12
  * 1. Validate pod and target node exist
13
- * 2. Update nodeId to target node (atomic update)
13
+ * 2. Update the Pod routing assignment to the target node
14
14
  *
15
15
  * Data does NOT need to be copied upfront:
16
16
  * - Metadata is in shared PostgreSQL (Quadstore), already accessible from all nodes
@@ -29,7 +29,7 @@ class PodMigrationService {
29
29
  /**
30
30
  * Migrate a pod to a different node.
31
31
  *
32
- * This is instant - only updates the nodeId in database.
32
+ * This is instant - only updates the routing assignment in the database.
33
33
  * Subsequent requests will be routed to the new node.
34
34
  * Binary files are read via cross-region fallback if not present locally.
35
35
  */
@@ -49,8 +49,8 @@ class PodMigrationService {
49
49
  if (sourceNodeId === targetNodeId) {
50
50
  throw new Error(`Pod ${podId} is already on node ${targetNodeId}`);
51
51
  }
52
- // Update nodeId - this is the only thing we need to do!
53
- await this.podLookupRepository.setNodeId(podId, targetNodeId);
52
+ // Update routing ownership; Pod usage/quota tables must not carry placement state.
53
+ await this.edgeNodeRepository.assignPodToNode(targetNodeId, pod.storageUrl ?? pod.baseUrl);
54
54
  this.logger.info(`Pod migrated: pod=${podId}, source=${sourceNodeId}, target=${targetNodeId}`);
55
55
  return {
56
56
  podId,
@@ -1 +1 @@
1
- {"version":3,"file":"PodMigrationService.js","sourceRoot":"","sources":["../../src/service/PodMigrationService.ts"],"names":[],"mappings":";;;AAAA,iEAAqD;AACrD,+CAA6D;AAC7D,iFAA8E;AAC9E,+EAA4E;AAc5E;;;;;;;;;;;;GAYG;AACH,MAAa,mBAAmB;IAO9B,YAAmB,MAAiC;QANjC,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAO7C,MAAM,EAAE,GAAG,IAAA,wBAAmB,EAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACrD,IAAI,CAAC,mBAAmB,GAAG,IAAI,yCAAmB,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,kBAAkB,GAAG,IAAI,uCAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,YAAoB;QACzD,eAAe;QACf,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;QAC5C,CAAC;QAED,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QAC7E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,eAAe,YAAY,YAAY,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC;QAEtD,6BAA6B;QAC7B,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,uBAAuB,YAAY,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,wDAAwD;QACxD,MAAM,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAE9D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,KAAK,YAAY,YAAY,YAAY,YAAY,EAAE,CAAC,CAAC;QAE/F,OAAO;YACL,KAAK;YACL,YAAY;YACZ,YAAY;YACZ,UAAU,EAAE,IAAI,IAAI,EAAE;SACvB,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,UAAU,CAAC,KAAa;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3D,OAAO,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC;IAC7B,CAAC;CACF;AA7DD,kDA6DC","sourcesContent":["import { getLoggerFor } from 'global-logger-factory';\nimport { getIdentityDatabase } from '../identity/drizzle/db';\nimport { PodLookupRepository } from '../identity/drizzle/PodLookupRepository';\nimport { EdgeNodeRepository } from '../identity/drizzle/EdgeNodeRepository';\n\nexport interface PodMigrationServiceConfig {\n identityDbUrl: string;\n currentNodeId: string;\n}\n\nexport interface MigrationResult {\n podId: string;\n sourceNodeId: string;\n targetNodeId: string;\n migratedAt: Date;\n}\n\n/**\n * Service for managing Pod migrations between Center nodes.\n * \n * Simplified migration process:\n * 1. Validate pod and target node exist\n * 2. Update nodeId to target node (atomic update)\n * \n * Data does NOT need to be copied upfront:\n * - Metadata is in shared PostgreSQL (Quadstore), already accessible from all nodes\n * - Binary files use presigned URL redirect (302) from object storage\n * \n * This provides instant, user-transparent migration.\n */\nexport class PodMigrationService {\n protected readonly logger = getLoggerFor(this);\n\n private readonly podLookupRepository: PodLookupRepository;\n private readonly edgeNodeRepository: EdgeNodeRepository;\n private readonly currentNodeId: string;\n\n public constructor(config: PodMigrationServiceConfig) {\n const db = getIdentityDatabase(config.identityDbUrl);\n this.podLookupRepository = new PodLookupRepository(db);\n this.edgeNodeRepository = new EdgeNodeRepository(db);\n this.currentNodeId = config.currentNodeId;\n }\n\n /**\n * Migrate a pod to a different node.\n * \n * This is instant - only updates the nodeId in database.\n * Subsequent requests will be routed to the new node.\n * Binary files are read via cross-region fallback if not present locally.\n */\n public async migratePod(podId: string, targetNodeId: string): Promise<MigrationResult> {\n // Get pod info\n const pod = await this.podLookupRepository.findById(podId);\n if (!pod) {\n throw new Error(`Pod ${podId} not found`);\n }\n\n // Get target node info\n const targetNode = await this.edgeNodeRepository.getCenterNode(targetNodeId);\n if (!targetNode) {\n throw new Error(`Target node ${targetNodeId} not found`);\n }\n\n const sourceNodeId = pod.nodeId ?? this.currentNodeId;\n\n // Check if already on target\n if (sourceNodeId === targetNodeId) {\n throw new Error(`Pod ${podId} is already on node ${targetNodeId}`);\n }\n\n // Update nodeId - this is the only thing we need to do!\n await this.podLookupRepository.setNodeId(podId, targetNodeId);\n\n this.logger.info(`Pod migrated: pod=${podId}, source=${sourceNodeId}, target=${targetNodeId}`);\n\n return {\n podId,\n sourceNodeId,\n targetNodeId,\n migratedAt: new Date(),\n };\n }\n\n /**\n * Get which node a pod is currently on.\n */\n public async getPodNode(podId: string): Promise<string | null> {\n const pod = await this.podLookupRepository.findById(podId);\n return pod?.nodeId ?? null;\n }\n}\n"]}
1
+ {"version":3,"file":"PodMigrationService.js","sourceRoot":"","sources":["../../src/service/PodMigrationService.ts"],"names":[],"mappings":";;;AAAA,iEAAqD;AACrD,+CAA6D;AAC7D,iFAA8E;AAC9E,+EAA4E;AAc5E;;;;;;;;;;;;GAYG;AACH,MAAa,mBAAmB;IAO9B,YAAmB,MAAiC;QANjC,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAO7C,MAAM,EAAE,GAAG,IAAA,wBAAmB,EAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACrD,IAAI,CAAC,mBAAmB,GAAG,IAAI,yCAAmB,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,kBAAkB,GAAG,IAAI,uCAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,YAAoB;QACzD,eAAe;QACf,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;QAC5C,CAAC;QAED,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QAC7E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,eAAe,YAAY,YAAY,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC;QAEtD,6BAA6B;QAC7B,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,uBAAuB,YAAY,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,mFAAmF;QACnF,MAAM,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,YAAY,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAE3F,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,KAAK,YAAY,YAAY,YAAY,YAAY,EAAE,CAAC,CAAC;QAE/F,OAAO;YACL,KAAK;YACL,YAAY;YACZ,YAAY;YACZ,UAAU,EAAE,IAAI,IAAI,EAAE;SACvB,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,UAAU,CAAC,KAAa;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3D,OAAO,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC;IAC7B,CAAC;CACF;AA7DD,kDA6DC","sourcesContent":["import { getLoggerFor } from 'global-logger-factory';\nimport { getIdentityDatabase } from '../identity/drizzle/db';\nimport { PodLookupRepository } from '../identity/drizzle/PodLookupRepository';\nimport { EdgeNodeRepository } from '../identity/drizzle/EdgeNodeRepository';\n\nexport interface PodMigrationServiceConfig {\n identityDbUrl: string;\n currentNodeId: string;\n}\n\nexport interface MigrationResult {\n podId: string;\n sourceNodeId: string;\n targetNodeId: string;\n migratedAt: Date;\n}\n\n/**\n * Service for managing Pod migrations between Center nodes.\n * \n * Simplified migration process:\n * 1. Validate pod and target node exist\n * 2. Update the Pod routing assignment to the target node\n * \n * Data does NOT need to be copied upfront:\n * - Metadata is in shared PostgreSQL (Quadstore), already accessible from all nodes\n * - Binary files use presigned URL redirect (302) from object storage\n * \n * This provides instant, user-transparent migration.\n */\nexport class PodMigrationService {\n protected readonly logger = getLoggerFor(this);\n\n private readonly podLookupRepository: PodLookupRepository;\n private readonly edgeNodeRepository: EdgeNodeRepository;\n private readonly currentNodeId: string;\n\n public constructor(config: PodMigrationServiceConfig) {\n const db = getIdentityDatabase(config.identityDbUrl);\n this.podLookupRepository = new PodLookupRepository(db);\n this.edgeNodeRepository = new EdgeNodeRepository(db);\n this.currentNodeId = config.currentNodeId;\n }\n\n /**\n * Migrate a pod to a different node.\n * \n * This is instant - only updates the routing assignment in the database.\n * Subsequent requests will be routed to the new node.\n * Binary files are read via cross-region fallback if not present locally.\n */\n public async migratePod(podId: string, targetNodeId: string): Promise<MigrationResult> {\n // Get pod info\n const pod = await this.podLookupRepository.findById(podId);\n if (!pod) {\n throw new Error(`Pod ${podId} not found`);\n }\n\n // Get target node info\n const targetNode = await this.edgeNodeRepository.getCenterNode(targetNodeId);\n if (!targetNode) {\n throw new Error(`Target node ${targetNodeId} not found`);\n }\n\n const sourceNodeId = pod.nodeId ?? this.currentNodeId;\n\n // Check if already on target\n if (sourceNodeId === targetNodeId) {\n throw new Error(`Pod ${podId} is already on node ${targetNodeId}`);\n }\n\n // Update routing ownership; Pod usage/quota tables must not carry placement state.\n await this.edgeNodeRepository.assignPodToNode(targetNodeId, pod.storageUrl ?? pod.baseUrl);\n\n this.logger.info(`Pod migrated: pod=${podId}, source=${sourceNodeId}, target=${targetNodeId}`);\n\n return {\n podId,\n sourceNodeId,\n targetNodeId,\n migratedAt: new Date(),\n };\n }\n\n /**\n * Get which node a pod is currently on.\n */\n public async getPodNode(podId: string): Promise<string | null> {\n const pod = await this.podLookupRepository.findById(podId);\n return pod?.nodeId ?? null;\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import type { CreateServiceTokenOptions, ServiceTokenRecord, ServiceTokenRepositoryPort, ServiceType } from '../identity/drizzle/ServiceTokenRepository';
2
+ export interface LocalSetupServiceTokenRepositoryOptions {
3
+ token?: string;
4
+ serviceType: ServiceType;
5
+ serviceId: string;
6
+ scopes: string[];
7
+ }
8
+ export declare class LocalSetupServiceTokenRepository implements ServiceTokenRepositoryPort {
9
+ private record;
10
+ private tokenHash;
11
+ constructor(options: LocalSetupServiceTokenRepositoryOptions);
12
+ createToken(_options: CreateServiceTokenOptions): Promise<{
13
+ id: string;
14
+ token: string;
15
+ }>;
16
+ registerToken(token: string, options: CreateServiceTokenOptions): Promise<string>;
17
+ verifyToken(token: string): Promise<ServiceTokenRecord | undefined>;
18
+ findByService(serviceType: ServiceType, serviceId: string): Promise<ServiceTokenRecord | undefined>;
19
+ deleteToken(id: string): Promise<void>;
20
+ listTokens(): Promise<ServiceTokenRecord[]>;
21
+ private hashToken;
22
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalSetupServiceTokenRepository = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ class LocalSetupServiceTokenRepository {
6
+ constructor(options) {
7
+ if (!options.token) {
8
+ return;
9
+ }
10
+ this.tokenHash = this.hashToken(options.token);
11
+ this.record = {
12
+ id: `local-setup-${options.serviceType}-${options.serviceId}`,
13
+ serviceType: options.serviceType,
14
+ serviceId: options.serviceId,
15
+ scopes: options.scopes,
16
+ createdAt: new Date(),
17
+ expiresAt: null,
18
+ };
19
+ }
20
+ async createToken(_options) {
21
+ throw new Error('Local setup service tokens are supplied by setup, not generated by the API');
22
+ }
23
+ async registerToken(token, options) {
24
+ const id = this.record?.id ?? `local-setup-${(0, node_crypto_1.randomUUID)()}`;
25
+ this.tokenHash = this.hashToken(token);
26
+ this.record = {
27
+ id,
28
+ serviceType: options.serviceType,
29
+ serviceId: options.serviceId,
30
+ scopes: options.scopes,
31
+ createdAt: this.record?.createdAt ?? new Date(),
32
+ expiresAt: options.expiresAt ?? null,
33
+ };
34
+ return id;
35
+ }
36
+ async verifyToken(token) {
37
+ if (!this.record || !this.tokenHash) {
38
+ return undefined;
39
+ }
40
+ if (this.hashToken(token) !== this.tokenHash) {
41
+ return undefined;
42
+ }
43
+ if (this.record.expiresAt && this.record.expiresAt.getTime() < Date.now()) {
44
+ return undefined;
45
+ }
46
+ return this.record;
47
+ }
48
+ async findByService(serviceType, serviceId) {
49
+ if (this.record?.serviceType === serviceType && this.record.serviceId === serviceId) {
50
+ return this.record;
51
+ }
52
+ return undefined;
53
+ }
54
+ async deleteToken(id) {
55
+ if (this.record?.id === id) {
56
+ this.record = undefined;
57
+ this.tokenHash = undefined;
58
+ }
59
+ }
60
+ async listTokens() {
61
+ return this.record ? [this.record] : [];
62
+ }
63
+ hashToken(token) {
64
+ return (0, node_crypto_1.createHash)('sha256').update(token).digest('hex');
65
+ }
66
+ }
67
+ exports.LocalSetupServiceTokenRepository = LocalSetupServiceTokenRepository;
68
+ //# sourceMappingURL=LocalSetupServiceTokenRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalSetupServiceTokenRepository.js","sourceRoot":"","sources":["../../src/setup/LocalSetupServiceTokenRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport type {\n CreateServiceTokenOptions,\n ServiceTokenRecord,\n ServiceTokenRepositoryPort,\n ServiceType,\n} from '../identity/drizzle/ServiceTokenRepository';\n\nexport interface LocalSetupServiceTokenRepositoryOptions {\n token?: string;\n serviceType: ServiceType;\n serviceId: string;\n scopes: string[];\n}\n\nexport class LocalSetupServiceTokenRepository implements ServiceTokenRepositoryPort {\n private record: ServiceTokenRecord | undefined;\n private tokenHash: string | undefined;\n\n public constructor(options: LocalSetupServiceTokenRepositoryOptions) {\n if (!options.token) {\n return;\n }\n this.tokenHash = this.hashToken(options.token);\n this.record = {\n id: `local-setup-${options.serviceType}-${options.serviceId}`,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: options.scopes,\n createdAt: new Date(),\n expiresAt: null,\n };\n }\n\n public async createToken(_options: CreateServiceTokenOptions): Promise<{ id: string; token: string }> {\n throw new Error('Local setup service tokens are supplied by setup, not generated by the API');\n }\n\n public async registerToken(token: string, options: CreateServiceTokenOptions): Promise<string> {\n const id = this.record?.id ?? `local-setup-${randomUUID()}`;\n this.tokenHash = this.hashToken(token);\n this.record = {\n id,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: options.scopes,\n createdAt: this.record?.createdAt ?? new Date(),\n expiresAt: options.expiresAt ?? null,\n };\n return id;\n }\n\n public async verifyToken(token: string): Promise<ServiceTokenRecord | undefined> {\n if (!this.record || !this.tokenHash) {\n return undefined;\n }\n if (this.hashToken(token) !== this.tokenHash) {\n return undefined;\n }\n if (this.record.expiresAt && this.record.expiresAt.getTime() < Date.now()) {\n return undefined;\n }\n return this.record;\n }\n\n public async findByService(serviceType: ServiceType, serviceId: string): Promise<ServiceTokenRecord | undefined> {\n if (this.record?.serviceType === serviceType && this.record.serviceId === serviceId) {\n return this.record;\n }\n return undefined;\n }\n\n public async deleteToken(id: string): Promise<void> {\n if (this.record?.id === id) {\n this.record = undefined;\n this.tokenHash = undefined;\n }\n }\n\n public async listTokens(): Promise<ServiceTokenRecord[]> {\n return this.record ? [this.record] : [];\n }\n\n private hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n }\n}\n"]}
@@ -26,8 +26,8 @@ class PerAccountQuotaStrategy extends community_server_1.QuotaStrategy {
26
26
  if (!this.usageRepo) {
27
27
  return { amount: Number.MAX_SAFE_INTEGER, unit: community_server_1.UNIT_BYTES };
28
28
  }
29
- const limit = await this.quotaService.getAccountLimit(accountId);
30
- const accountLimit = (limit ?? this.defaultQuota);
29
+ const quota = await this.quotaService.getAccountQuota(accountId);
30
+ const accountLimit = quota.storageLimitBytes ?? this.defaultQuota;
31
31
  if (!Number.isFinite(accountLimit)) {
32
32
  return { amount: Number.MAX_SAFE_INTEGER, unit: community_server_1.UNIT_BYTES };
33
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PerAccountQuotaStrategy.js","sourceRoot":"","sources":["../../../src/storage/quota/PerAccountQuotaStrategy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n QuotaStrategy,\n UNIT_BYTES,\n} from '@solid/community-server';\nimport type {\n ResourceIdentifier,\n SizeReporter,\n Size,\n} from '@solid/community-server';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { PodLookupRepository } from '../../identity/drizzle/PodLookupRepository';\nimport { UsageRepository } from './UsageRepository';\n\ninterface PerAccountQuotaStrategyOptions {\n identityDbUrl?: string;\n defaultAccountQuotaBytes: number;\n quotaService: QuotaService;\n}\n\nexport class PerAccountQuotaStrategy extends QuotaStrategy {\n private readonly quotaService: QuotaService;\n private readonly usageRepo?: UsageRepository;\n private readonly podLookup?: PodLookupRepository;\n private readonly defaultQuota: number;\n\n public constructor(reporter: SizeReporter<unknown>, options: PerAccountQuotaStrategyOptions) {\n super(reporter, { amount: options.defaultAccountQuotaBytes, unit: UNIT_BYTES });\n this.defaultQuota = options.defaultAccountQuotaBytes;\n if (options.identityDbUrl) {\n const db = getIdentityDatabase(options.identityDbUrl);\n this.usageRepo = new UsageRepository(db);\n this.podLookup = new PodLookupRepository(db);\n }\n this.quotaService = options.quotaService;\n }\n\n public override async getAvailableSpace(identifier: ResourceIdentifier): Promise<Size> {\n const context = await this.resolveContext(identifier);\n if (!context) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n\n const { accountId } = context;\n const currentResource = (await this.reporter.getSize(identifier)).amount;\n if (!this.usageRepo) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n\n const limit = await this.quotaService.getAccountLimit(accountId);\n const accountLimit = (limit ?? this.defaultQuota);\n if (!Number.isFinite(accountLimit)) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n const accountRecord = await this.usageRepo.getAccountUsage(accountId);\n const totalUsed = accountRecord?.storageBytes ?? 0;\n const available = accountLimit - Math.max(0, totalUsed - currentResource);\n return { amount: available, unit: UNIT_BYTES };\n }\n\n protected override async getTotalSpaceUsed(identifier: ResourceIdentifier): Promise<Size> {\n const context = await this.resolveContext(identifier);\n if (!context) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n if (!this.usageRepo) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n const accountRecord = await this.usageRepo.getAccountUsage(context.accountId);\n const used = accountRecord?.storageBytes ?? 0;\n return { amount: used, unit: UNIT_BYTES };\n }\n\n private async resolveContext(identifier: ResourceIdentifier): Promise<{ accountId: string; podId: string } | undefined> {\n if (!this.podLookup) {\n return undefined;\n }\n const pod = await this.podLookup.findByResourceIdentifier(identifier.path);\n if (!pod) {\n return undefined;\n }\n return { accountId: pod.accountId, podId: pod.podId };\n }\n}\n"]}
1
+ {"version":3,"file":"PerAccountQuotaStrategy.js","sourceRoot":"","sources":["../../../src/storage/quota/PerAccountQuotaStrategy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n QuotaStrategy,\n UNIT_BYTES,\n} from '@solid/community-server';\nimport type {\n ResourceIdentifier,\n SizeReporter,\n Size,\n} from '@solid/community-server';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { PodLookupRepository } from '../../identity/drizzle/PodLookupRepository';\nimport { UsageRepository } from './UsageRepository';\n\ninterface PerAccountQuotaStrategyOptions {\n identityDbUrl?: string;\n defaultAccountQuotaBytes: number;\n quotaService: QuotaService;\n}\n\nexport class PerAccountQuotaStrategy extends QuotaStrategy {\n private readonly quotaService: QuotaService;\n private readonly usageRepo?: UsageRepository;\n private readonly podLookup?: PodLookupRepository;\n private readonly defaultQuota: number;\n\n public constructor(reporter: SizeReporter<unknown>, options: PerAccountQuotaStrategyOptions) {\n super(reporter, { amount: options.defaultAccountQuotaBytes, unit: UNIT_BYTES });\n this.defaultQuota = options.defaultAccountQuotaBytes;\n if (options.identityDbUrl) {\n const db = getIdentityDatabase(options.identityDbUrl);\n this.usageRepo = new UsageRepository(db);\n this.podLookup = new PodLookupRepository(db);\n }\n this.quotaService = options.quotaService;\n }\n\n public override async getAvailableSpace(identifier: ResourceIdentifier): Promise<Size> {\n const context = await this.resolveContext(identifier);\n if (!context) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n\n const { accountId } = context;\n const currentResource = (await this.reporter.getSize(identifier)).amount;\n if (!this.usageRepo) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n\n const quota = await this.quotaService.getAccountQuota(accountId);\n const accountLimit = quota.storageLimitBytes ?? this.defaultQuota;\n if (!Number.isFinite(accountLimit)) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n const accountRecord = await this.usageRepo.getAccountUsage(accountId);\n const totalUsed = accountRecord?.storageBytes ?? 0;\n const available = accountLimit - Math.max(0, totalUsed - currentResource);\n return { amount: available, unit: UNIT_BYTES };\n }\n\n protected override async getTotalSpaceUsed(identifier: ResourceIdentifier): Promise<Size> {\n const context = await this.resolveContext(identifier);\n if (!context) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n if (!this.usageRepo) {\n return { amount: Number.MAX_SAFE_INTEGER, unit: UNIT_BYTES };\n }\n const accountRecord = await this.usageRepo.getAccountUsage(context.accountId);\n const used = accountRecord?.storageBytes ?? 0;\n return { amount: used, unit: UNIT_BYTES };\n }\n\n private async resolveContext(identifier: ResourceIdentifier): Promise<{ accountId: string; podId: string } | undefined> {\n if (!this.podLookup) {\n return undefined;\n }\n const pod = await this.podLookup.findByResourceIdentifier(identifier.path);\n if (!pod) {\n return undefined;\n }\n return { accountId: pod.accountId, podId: pod.podId };\n }\n}\n"]}
@@ -16,8 +16,8 @@ export interface PodUsageRecord extends AccountUsageRecord {
16
16
  podId: string;
17
17
  }
18
18
  /**
19
- * Repository for tracking pod and account usage metrics.
20
- * Supports both PostgreSQL and SQLite through unified schema abstraction.
19
+ * Tracks account and pod usage in one table. Account/pod are scopes of the same
20
+ * metric record, not separate data models.
21
21
  */
22
22
  export declare class UsageRepository {
23
23
  private readonly db;
@@ -37,43 +37,21 @@ export declare class UsageRepository {
37
37
  setAccountTokenLimit(accountId: string, limit: number | null): Promise<void>;
38
38
  setPodComputeLimit(podId: string, accountId: string, limit: number | null): Promise<void>;
39
39
  setPodTokenLimit(podId: string, accountId: string, limit: number | null): Promise<void>;
40
- /**
41
- * Increment token usage for an account and pod.
42
- */
43
40
  incrementTokenUsage(accountId: string, podId: string, tokensDelta: number): Promise<void>;
44
- /**
45
- * Increment compute usage for an account and pod.
46
- */
47
41
  incrementComputeUsage(accountId: string, podId: string, secondsDelta: number): Promise<void>;
48
- private incrementAccountTokensWith;
49
- private incrementPodTokensWith;
50
- private incrementAccountComputeWith;
51
- private incrementPodComputeWith;
52
- private incrementAccountUsageWith;
53
- private incrementPodUsageWith;
54
- private upsertAccountUsage;
55
- private upsertPodUsage;
56
- /**
57
- * Generic account limit setter for compute/token limits.
58
- */
59
- private upsertAccountLimit;
60
- /**
61
- * Generic pod limit setter for compute/token limits.
62
- */
63
- private upsertPodLimit;
64
42
  private getPodUsageWith;
43
+ private getUsageRow;
44
+ private incrementTokensWith;
45
+ private incrementComputeWith;
46
+ private incrementUsageWith;
47
+ private upsertUsage;
48
+ private toAccountUsage;
49
+ private toPodUsage;
50
+ private toUsageMetrics;
65
51
  private normalizeDelta;
66
52
  private normalizeValue;
67
53
  private coerceNumber;
68
54
  private coerceNullable;
69
- /**
70
- * Coerce timestamp value to Unix timestamp (seconds).
71
- * Handles Date objects (from PG) and numbers (from SQLite).
72
- */
73
55
  private coerceTimestamp;
74
- /**
75
- * Get the current timestamp in the format expected by the database.
76
- * PG expects Date objects, SQLite expects Unix timestamps (seconds).
77
- */
78
56
  private now;
79
57
  }