@undefineds.co/xpod 0.1.7 → 0.2.0-preview.2

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 (305) hide show
  1. package/README.md +141 -2
  2. package/config/cli.json +9 -71
  3. package/config/cloud.json +34 -7
  4. package/config/local.json +6 -2
  5. package/config/resolver.json +11 -49
  6. package/config/runtime-open.json +22 -0
  7. package/config/xpod.base.json +32 -0
  8. package/config/xpod.cluster.json +2 -44
  9. package/config/xpod.json +5 -2
  10. package/dist/api/auth/AuthContext.d.ts +12 -1
  11. package/dist/api/auth/AuthContext.js +18 -1
  12. package/dist/api/auth/AuthContext.js.map +1 -1
  13. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
  14. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  15. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +18 -0
  16. package/dist/api/auth/ServiceTokenAuthenticator.js +50 -0
  17. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -0
  18. package/dist/api/auth/index.d.ts +1 -0
  19. package/dist/api/auth/index.js +1 -0
  20. package/dist/api/auth/index.js.map +1 -1
  21. package/dist/api/chatkit/ai-provider.d.ts +0 -10
  22. package/dist/api/chatkit/ai-provider.js +11 -120
  23. package/dist/api/chatkit/ai-provider.js.map +1 -1
  24. package/dist/api/chatkit/default-agent.js +11 -8
  25. package/dist/api/chatkit/default-agent.js.map +1 -1
  26. package/dist/api/chatkit/pod-store.js +19 -3
  27. package/dist/api/chatkit/pod-store.js.map +1 -1
  28. package/dist/api/chatkit/schema.d.ts +9 -3
  29. package/dist/api/chatkit/schema.js +14 -6
  30. package/dist/api/chatkit/schema.js.map +1 -1
  31. package/dist/api/container/business-token.d.ts +9 -0
  32. package/dist/api/container/business-token.js +32 -0
  33. package/dist/api/container/business-token.js.map +1 -0
  34. package/dist/api/container/cloud.js +36 -12
  35. package/dist/api/container/cloud.js.map +1 -1
  36. package/dist/api/container/common.js +12 -5
  37. package/dist/api/container/common.js.map +1 -1
  38. package/dist/api/container/index.js +94 -14
  39. package/dist/api/container/index.js.map +1 -1
  40. package/dist/api/container/local.js +2 -1
  41. package/dist/api/container/local.js.map +1 -1
  42. package/dist/api/container/routes.js +81 -9
  43. package/dist/api/container/routes.js.map +1 -1
  44. package/dist/api/container/types.d.ts +8 -6
  45. package/dist/api/container/types.js.map +1 -1
  46. package/dist/api/handlers/AdminHandler.js +9 -9
  47. package/dist/api/handlers/AdminHandler.js.map +1 -1
  48. package/dist/api/handlers/ApiKeyHandler.js +0 -6
  49. package/dist/api/handlers/ApiKeyHandler.js.map +1 -1
  50. package/dist/api/handlers/EdgeNodeSignalHandler.d.ts +17 -0
  51. package/dist/api/handlers/EdgeNodeSignalHandler.js +171 -0
  52. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -0
  53. package/dist/api/handlers/PodManagementHandler.d.ts +5 -4
  54. package/dist/api/handlers/PodManagementHandler.js +11 -10
  55. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  56. package/dist/api/handlers/ProvisionHandler.d.ts +42 -0
  57. package/dist/api/handlers/ProvisionHandler.js +161 -0
  58. package/dist/api/handlers/ProvisionHandler.js.map +1 -0
  59. package/dist/api/handlers/QuotaHandler.d.ts +7 -7
  60. package/dist/api/handlers/QuotaHandler.js +143 -73
  61. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  62. package/dist/api/handlers/SubdomainClientHandler.js +2 -2
  63. package/dist/api/handlers/SubdomainClientHandler.js.map +1 -1
  64. package/dist/api/handlers/SubdomainHandler.js +13 -8
  65. package/dist/api/handlers/SubdomainHandler.js.map +1 -1
  66. package/dist/api/handlers/UsageHandler.d.ts +14 -0
  67. package/dist/api/handlers/UsageHandler.js +123 -0
  68. package/dist/api/handlers/UsageHandler.js.map +1 -0
  69. package/dist/api/handlers/index.d.ts +3 -1
  70. package/dist/api/handlers/index.js +3 -1
  71. package/dist/api/handlers/index.js.map +1 -1
  72. package/dist/api/main.js +18 -0
  73. package/dist/api/main.js.map +1 -1
  74. package/dist/api/middleware/OpenAuthMiddleware.d.ts +12 -0
  75. package/dist/api/middleware/OpenAuthMiddleware.js +27 -0
  76. package/dist/api/middleware/OpenAuthMiddleware.js.map +1 -0
  77. package/dist/api/runtime.d.ts +15 -0
  78. package/dist/api/runtime.js +104 -0
  79. package/dist/api/runtime.js.map +1 -0
  80. package/dist/api/service/VercelChatService.d.ts +16 -7
  81. package/dist/api/service/VercelChatService.js +98 -178
  82. package/dist/api/service/VercelChatService.js.map +1 -1
  83. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +6 -11
  84. package/dist/api/store/DrizzleClientCredentialsStore.js +9 -39
  85. package/dist/api/store/DrizzleClientCredentialsStore.js.map +1 -1
  86. package/dist/authorization/AuthModeSelector.d.ts +10 -0
  87. package/dist/authorization/AuthModeSelector.js +27 -0
  88. package/dist/authorization/AuthModeSelector.js.map +1 -0
  89. package/dist/authorization/AuthModeSelector.jsonld +81 -0
  90. package/dist/cli/commands/account.d.ts +6 -0
  91. package/dist/cli/commands/account.js +119 -0
  92. package/dist/cli/commands/account.js.map +1 -0
  93. package/dist/cli/commands/auth.js +20 -29
  94. package/dist/cli/commands/auth.js.map +1 -1
  95. package/dist/cli/commands/backup.d.ts +15 -0
  96. package/dist/cli/commands/backup.js +286 -0
  97. package/dist/cli/commands/backup.js.map +1 -0
  98. package/dist/cli/commands/config.d.ts +34 -3
  99. package/dist/cli/commands/config.js +195 -258
  100. package/dist/cli/commands/config.js.map +1 -1
  101. package/dist/cli/commands/doctor.d.ts +6 -0
  102. package/dist/cli/commands/doctor.js +94 -0
  103. package/dist/cli/commands/doctor.js.map +1 -0
  104. package/dist/cli/commands/pod.d.ts +6 -0
  105. package/dist/cli/commands/pod.js +124 -0
  106. package/dist/cli/commands/pod.js.map +1 -0
  107. package/dist/cli/commands/start.js +28 -5
  108. package/dist/cli/commands/start.js.map +1 -1
  109. package/dist/cli/index.js +9 -0
  110. package/dist/cli/index.js.map +1 -1
  111. package/dist/cli/lib/credentials-store.d.ts +17 -0
  112. package/dist/cli/lib/credentials-store.js +73 -0
  113. package/dist/cli/lib/credentials-store.js.map +1 -0
  114. package/dist/cli/lib/css-account.d.ts +17 -0
  115. package/dist/cli/lib/css-account.js +56 -0
  116. package/dist/cli/lib/css-account.js.map +1 -1
  117. package/dist/cli/lib/pod-thread-store.d.ts +57 -0
  118. package/dist/cli/lib/pod-thread-store.js +310 -0
  119. package/dist/cli/lib/pod-thread-store.js.map +1 -0
  120. package/dist/cli/lib/solid-auth.d.ts +20 -0
  121. package/dist/cli/lib/solid-auth.js +70 -0
  122. package/dist/cli/lib/solid-auth.js.map +1 -0
  123. package/dist/components/components.jsonld +5 -8
  124. package/dist/components/context.jsonld +114 -244
  125. package/dist/edge/EdgeNodeAgent.js +2 -2
  126. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  127. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -7
  128. package/dist/edge/EdgeNodeDnsCoordinator.js +31 -41
  129. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  130. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +1 -27
  131. package/dist/edge/EdgeNodeModeDetector.d.ts +1 -1
  132. package/dist/edge/EdgeNodeModeDetector.js +9 -11
  133. package/dist/edge/EdgeNodeModeDetector.js.map +1 -1
  134. package/dist/http/ClusterIngressRouter.js +3 -3
  135. package/dist/http/ClusterIngressRouter.js.map +1 -1
  136. package/dist/http/ClusterWebSocketConfigurator.js +2 -2
  137. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  138. package/dist/http/PodRoutingHttpHandler.js +2 -2
  139. package/dist/http/PodRoutingHttpHandler.js.map +1 -1
  140. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +1 -1
  141. package/dist/http/cluster/PodMigrationHttpHandler.js +1 -1
  142. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  143. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +37 -4
  144. package/dist/identity/drizzle/EdgeNodeRepository.js +120 -128
  145. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  146. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +52 -0
  147. package/dist/identity/drizzle/ServiceTokenRepository.js +143 -0
  148. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -0
  149. package/dist/identity/drizzle/db.d.ts +9 -0
  150. package/dist/identity/drizzle/db.js +208 -1
  151. package/dist/identity/drizzle/db.js.map +1 -1
  152. package/dist/identity/drizzle/schema.pg.d.ts +5 -0
  153. package/dist/identity/drizzle/schema.pg.js +49 -20
  154. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  155. package/dist/identity/drizzle/schema.sqlite.d.ts +332 -57
  156. package/dist/identity/drizzle/schema.sqlite.js +48 -18
  157. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  158. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +6 -4
  159. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
  160. package/dist/index.d.ts +6 -9
  161. package/dist/index.js +12 -14
  162. package/dist/index.js.map +1 -1
  163. package/dist/main.js +25 -8
  164. package/dist/main.js.map +1 -1
  165. package/dist/provision/ProvisionCodeCodec.d.ts +39 -0
  166. package/dist/provision/ProvisionCodeCodec.js +65 -0
  167. package/dist/provision/ProvisionCodeCodec.js.map +1 -0
  168. package/dist/provision/ProvisionCodeCodec.jsonld +47 -0
  169. package/dist/provision/ProvisionPodCreator.d.ts +20 -0
  170. package/dist/provision/ProvisionPodCreator.js +84 -0
  171. package/dist/provision/ProvisionPodCreator.js.map +1 -0
  172. package/dist/provision/ProvisionPodCreator.jsonld +118 -0
  173. package/dist/quota/DrizzleQuotaService.d.ts +17 -3
  174. package/dist/quota/DrizzleQuotaService.js +108 -8
  175. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  176. package/dist/quota/DrizzleQuotaService.jsonld +33 -22
  177. package/dist/quota/NoopQuotaService.d.ts +7 -1
  178. package/dist/quota/NoopQuotaService.js +12 -0
  179. package/dist/quota/NoopQuotaService.js.map +1 -1
  180. package/dist/quota/NoopQuotaService.jsonld +24 -0
  181. package/dist/quota/QuotaService.d.ts +17 -0
  182. package/dist/quota/QuotaService.js +5 -0
  183. package/dist/quota/QuotaService.js.map +1 -1
  184. package/dist/quota/QuotaService.jsonld +50 -0
  185. package/dist/runtime/Proxy.d.ts +22 -4
  186. package/dist/runtime/Proxy.js +154 -35
  187. package/dist/runtime/Proxy.js.map +1 -1
  188. package/dist/runtime/XpodRuntime.d.ts +49 -0
  189. package/dist/runtime/XpodRuntime.js +374 -0
  190. package/dist/runtime/XpodRuntime.js.map +1 -0
  191. package/dist/runtime/env-utils.d.ts +2 -0
  192. package/dist/runtime/env-utils.js +55 -0
  193. package/dist/runtime/env-utils.js.map +1 -0
  194. package/dist/runtime/index.d.ts +4 -0
  195. package/dist/runtime/index.js +8 -1
  196. package/dist/runtime/index.js.map +1 -1
  197. package/dist/runtime/socket-fetch.d.ts +1 -0
  198. package/dist/runtime/socket-fetch.js +72 -0
  199. package/dist/runtime/socket-fetch.js.map +1 -0
  200. package/dist/runtime/socket-http.d.ts +1 -0
  201. package/dist/runtime/socket-http.js +142 -0
  202. package/dist/runtime/socket-http.js.map +1 -0
  203. package/dist/runtime/socket-utils.d.ts +2 -0
  204. package/dist/runtime/socket-utils.js +34 -0
  205. package/dist/runtime/socket-utils.js.map +1 -0
  206. package/dist/service/{EdgeNodeHeartbeatService.d.ts → EdgeNodeSignalClient.d.ts} +3 -3
  207. package/dist/service/{EdgeNodeHeartbeatService.js → EdgeNodeSignalClient.js} +4 -4
  208. package/dist/service/EdgeNodeSignalClient.js.map +1 -0
  209. package/dist/service/PodMigrationService.d.ts +1 -2
  210. package/dist/service/PodMigrationService.js +1 -2
  211. package/dist/service/PodMigrationService.js.map +1 -1
  212. package/dist/storage/SparqlUpdateResourceStore.js +1 -1
  213. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  214. package/dist/storage/accessors/MinioDataAccessor.d.ts +6 -0
  215. package/dist/storage/accessors/MinioDataAccessor.js +10 -0
  216. package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
  217. package/dist/storage/accessors/MinioDataAccessor.jsonld +4 -0
  218. package/dist/storage/accessors/MixDataAccessor.d.ts +2 -1
  219. package/dist/storage/accessors/MixDataAccessor.js +12 -1
  220. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  221. package/dist/storage/accessors/MixDataAccessor.jsonld +19 -0
  222. package/dist/storage/locking/UrlAwareRedisLocker.d.ts +18 -0
  223. package/dist/storage/locking/UrlAwareRedisLocker.js +60 -0
  224. package/dist/storage/locking/UrlAwareRedisLocker.js.map +1 -0
  225. package/dist/storage/locking/UrlAwareRedisLocker.jsonld +123 -0
  226. package/dist/storage/quota/UsageRepository.d.ts +41 -8
  227. package/dist/storage/quota/UsageRepository.js +252 -50
  228. package/dist/storage/quota/UsageRepository.js.map +1 -1
  229. package/dist/storage/sparql/ComunicaQuintEngine.d.ts +9 -0
  230. package/dist/storage/sparql/ComunicaQuintEngine.js +50 -9
  231. package/dist/storage/sparql/ComunicaQuintEngine.js.map +1 -1
  232. package/dist/storage/sparql/QueryOptimizer.js +13 -1
  233. package/dist/storage/sparql/QueryOptimizer.js.map +1 -1
  234. package/dist/storage/sparql/QuintQuerySource.d.ts +14 -0
  235. package/dist/storage/sparql/QuintQuerySource.js +152 -1
  236. package/dist/storage/sparql/QuintQuerySource.js.map +1 -1
  237. package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -0
  238. package/dist/storage/sparql/SubgraphQueryEngine.js +6 -2
  239. package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
  240. package/dist/storage/sparql/SubgraphQueryEngine.jsonld +4 -0
  241. package/dist/subdomain/SubdomainClient.d.ts +3 -3
  242. package/dist/subdomain/SubdomainClient.js +1 -1
  243. package/dist/subdomain/SubdomainClient.js.map +1 -1
  244. package/dist/subdomain/SubdomainService.d.ts +15 -16
  245. package/dist/subdomain/SubdomainService.js +80 -54
  246. package/dist/subdomain/SubdomainService.js.map +1 -1
  247. package/dist/subdomain/SubdomainService.jsonld +22 -26
  248. package/dist/supervisor/Supervisor.d.ts +7 -2
  249. package/dist/supervisor/Supervisor.js +33 -1
  250. package/dist/supervisor/Supervisor.js.map +1 -1
  251. package/dist/test-utils/index.d.ts +4 -0
  252. package/dist/test-utils/index.js +8 -0
  253. package/dist/test-utils/index.js.map +1 -0
  254. package/dist/test-utils/no-auth-xpod.d.ts +11 -0
  255. package/dist/test-utils/no-auth-xpod.js +25 -0
  256. package/dist/test-utils/no-auth-xpod.js.map +1 -0
  257. package/dist/test-utils/seed-pod.d.ts +5 -0
  258. package/dist/test-utils/seed-pod.js +61 -0
  259. package/dist/test-utils/seed-pod.js.map +1 -0
  260. package/package.json +23 -5
  261. package/templates/identity/account/create-pod.html.ejs +110 -0
  262. package/templates/main.html.ejs +10 -0
  263. package/dist/api/handlers/DevHandler.d.ts +0 -18
  264. package/dist/api/handlers/DevHandler.js +0 -276
  265. package/dist/api/handlers/DevHandler.js.map +0 -1
  266. package/dist/api/handlers/SignalHandler.d.ts +0 -13
  267. package/dist/api/handlers/SignalHandler.js +0 -122
  268. package/dist/api/handlers/SignalHandler.js.map +0 -1
  269. package/dist/gateway/Proxy.d.ts +0 -24
  270. package/dist/gateway/Proxy.js +0 -209
  271. package/dist/gateway/Proxy.js.map +0 -1
  272. package/dist/gateway/Supervisor.d.ts +0 -2
  273. package/dist/gateway/Supervisor.js +0 -7
  274. package/dist/gateway/Supervisor.js.map +0 -1
  275. package/dist/gateway/port-finder.d.ts +0 -4
  276. package/dist/gateway/port-finder.js +0 -15
  277. package/dist/gateway/port-finder.js.map +0 -1
  278. package/dist/gateway/types.d.ts +0 -1
  279. package/dist/gateway/types.js +0 -3
  280. package/dist/gateway/types.js.map +0 -1
  281. package/dist/http/SignalInterceptHttpHandler.d.ts +0 -24
  282. package/dist/http/SignalInterceptHttpHandler.js +0 -47
  283. package/dist/http/SignalInterceptHttpHandler.js.map +0 -1
  284. package/dist/http/SignalInterceptHttpHandler.jsonld +0 -103
  285. package/dist/http/admin/EdgeNodeSignalHttpHandler.d.ts +0 -71
  286. package/dist/http/admin/EdgeNodeSignalHttpHandler.js +0 -674
  287. package/dist/http/admin/EdgeNodeSignalHttpHandler.js.map +0 -1
  288. package/dist/http/admin/EdgeNodeSignalHttpHandler.jsonld +0 -406
  289. package/dist/http/cluster/PodMigrationHttpHandler.jsonld +0 -169
  290. package/dist/quota/DefaultQuotaService.d.ts +0 -16
  291. package/dist/quota/DefaultQuotaService.js +0 -37
  292. package/dist/quota/DefaultQuotaService.js.map +0 -1
  293. package/dist/quota/DefaultQuotaService.jsonld +0 -85
  294. package/dist/service/EdgeNodeHeartbeatService.js.map +0 -1
  295. package/dist/service/PodMigrationService.jsonld +0 -76
  296. package/dist/storage/MigratableDataAccessor.d.ts +0 -63
  297. package/dist/storage/MigratableDataAccessor.js +0 -11
  298. package/dist/storage/MigratableDataAccessor.js.map +0 -1
  299. package/dist/storage/MigratableDataAccessor.jsonld +0 -60
  300. package/dist/storage/accessors/TieredMinioDataAccessor.d.ts +0 -150
  301. package/dist/storage/accessors/TieredMinioDataAccessor.js +0 -582
  302. package/dist/storage/accessors/TieredMinioDataAccessor.js.map +0 -1
  303. package/dist/storage/accessors/TieredMinioDataAccessor.jsonld +0 -333
  304. package/static/app/assets/index.css +0 -1
  305. package/static/app/assets/main.js +0 -11
@@ -2,21 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UsageRepository = void 0;
4
4
  const drizzle_orm_1 = require("drizzle-orm");
5
- const schema_1 = require("../../identity/drizzle/schema");
5
+ const db_1 = require("../../identity/drizzle/db");
6
6
  /**
7
7
  * Repository for tracking pod and account usage metrics.
8
- * NOTE: This repository only supports PostgreSQL. SQLite is not supported.
9
- * For local/dev modes, usage tracking should be disabled.
10
- *
11
- * TODO: Make UsageRepository database-agnostic to support SQLite in local mode.
12
- * Required changes:
13
- * - Replace `sql\`now()\`` with cross-database compatible timestamp (e.g., new Date())
14
- * - Use Drizzle's database-agnostic transaction API or raw SQL compatible with both
15
- * - Test with both SQLite and PostgreSQL backends
8
+ * Supports both PostgreSQL and SQLite through unified schema abstraction.
16
9
  */
17
10
  class UsageRepository {
18
11
  constructor(db) {
19
12
  this.db = db;
13
+ this.schema = (0, db_1.getSchema)(db);
20
14
  }
21
15
  async incrementUsage(accountId, podId, storageDelta, ingressDelta, egressDelta) {
22
16
  const normalizedStorage = this.normalizeDelta(storageDelta);
@@ -56,13 +50,18 @@ class UsageRepository {
56
50
  }
57
51
  async getAccountUsage(accountId) {
58
52
  const result = await this.db.select({
59
- storage: schema_1.accountUsage.storageBytes,
60
- ingress: schema_1.accountUsage.ingressBytes,
61
- egress: schema_1.accountUsage.egressBytes,
62
- storageLimit: schema_1.accountUsage.storageLimitBytes,
63
- bandwidthLimit: schema_1.accountUsage.bandwidthLimitBps,
64
- }).from(schema_1.accountUsage)
65
- .where((0, drizzle_orm_1.eq)(schema_1.accountUsage.accountId, accountId));
53
+ storage: this.schema.accountUsage.storageBytes,
54
+ ingress: this.schema.accountUsage.ingressBytes,
55
+ egress: this.schema.accountUsage.egressBytes,
56
+ storageLimit: this.schema.accountUsage.storageLimitBytes,
57
+ bandwidthLimit: this.schema.accountUsage.bandwidthLimitBps,
58
+ computeSeconds: this.schema.accountUsage.computeSeconds,
59
+ tokensUsed: this.schema.accountUsage.tokensUsed,
60
+ computeLimitSeconds: this.schema.accountUsage.computeLimitSeconds,
61
+ tokenLimitMonthly: this.schema.accountUsage.tokenLimitMonthly,
62
+ periodStart: this.schema.accountUsage.periodStart,
63
+ }).from(this.schema.accountUsage)
64
+ .where((0, drizzle_orm_1.eq)(this.schema.accountUsage.accountId, accountId));
66
65
  if (!result || result.length === 0) {
67
66
  return undefined;
68
67
  }
@@ -74,18 +73,28 @@ class UsageRepository {
74
73
  egressBytes: this.coerceNumber(row.egress),
75
74
  storageLimitBytes: this.coerceNullable(row.storageLimit),
76
75
  bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),
76
+ computeSeconds: this.coerceNumber(row.computeSeconds),
77
+ tokensUsed: this.coerceNumber(row.tokensUsed),
78
+ computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),
79
+ tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),
80
+ periodStart: this.coerceTimestamp(row.periodStart),
77
81
  };
78
82
  }
79
83
  async getPodUsage(podId) {
80
84
  const result = await this.db.select({
81
- accountId: schema_1.podUsage.accountId,
82
- storage: schema_1.podUsage.storageBytes,
83
- ingress: schema_1.podUsage.ingressBytes,
84
- egress: schema_1.podUsage.egressBytes,
85
- storageLimit: schema_1.podUsage.storageLimitBytes,
86
- bandwidthLimit: schema_1.podUsage.bandwidthLimitBps,
87
- }).from(schema_1.podUsage)
88
- .where((0, drizzle_orm_1.eq)(schema_1.podUsage.podId, podId));
85
+ accountId: this.schema.podUsage.accountId,
86
+ storage: this.schema.podUsage.storageBytes,
87
+ ingress: this.schema.podUsage.ingressBytes,
88
+ egress: this.schema.podUsage.egressBytes,
89
+ storageLimit: this.schema.podUsage.storageLimitBytes,
90
+ bandwidthLimit: this.schema.podUsage.bandwidthLimitBps,
91
+ computeSeconds: this.schema.podUsage.computeSeconds,
92
+ tokensUsed: this.schema.podUsage.tokensUsed,
93
+ computeLimitSeconds: this.schema.podUsage.computeLimitSeconds,
94
+ tokenLimitMonthly: this.schema.podUsage.tokenLimitMonthly,
95
+ periodStart: this.schema.podUsage.periodStart,
96
+ }).from(this.schema.podUsage)
97
+ .where((0, drizzle_orm_1.eq)(this.schema.podUsage.podId, podId));
89
98
  if (!result || result.length === 0) {
90
99
  return undefined;
91
100
  }
@@ -99,6 +108,11 @@ class UsageRepository {
99
108
  egressBytes: this.coerceNumber(row.egress),
100
109
  storageLimitBytes: this.coerceNullable(row.storageLimit),
101
110
  bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),
111
+ computeSeconds: this.coerceNumber(row.computeSeconds),
112
+ tokensUsed: this.coerceNumber(row.tokensUsed),
113
+ computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),
114
+ tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),
115
+ periodStart: this.coerceTimestamp(row.periodStart),
102
116
  };
103
117
  }
104
118
  async setAccountStorageLimit(accountId, limit) {
@@ -113,8 +127,118 @@ class UsageRepository {
113
127
  async setPodBandwidthLimit(podId, accountId, limit) {
114
128
  await this.upsertPodUsage(this.db, accountId, podId, undefined, undefined, limit);
115
129
  }
130
+ async setAccountComputeLimit(accountId, limit) {
131
+ await this.upsertAccountLimit(this.db, accountId, 'computeLimitSeconds', limit);
132
+ }
133
+ async setAccountTokenLimit(accountId, limit) {
134
+ await this.upsertAccountLimit(this.db, accountId, 'tokenLimitMonthly', limit);
135
+ }
136
+ async setPodComputeLimit(podId, accountId, limit) {
137
+ await this.upsertPodLimit(this.db, accountId, podId, 'computeLimitSeconds', limit);
138
+ }
139
+ async setPodTokenLimit(podId, accountId, limit) {
140
+ await this.upsertPodLimit(this.db, accountId, podId, 'tokenLimitMonthly', limit);
141
+ }
142
+ /**
143
+ * Increment token usage for an account and pod.
144
+ */
145
+ async incrementTokenUsage(accountId, podId, tokensDelta) {
146
+ const normalized = this.normalizeDelta(tokensDelta);
147
+ if (normalized === 0) {
148
+ return;
149
+ }
150
+ await this.db.transaction(async (tx) => {
151
+ await this.incrementPodTokensWith(tx, accountId, podId, normalized);
152
+ await this.incrementAccountTokensWith(tx, accountId, normalized);
153
+ });
154
+ }
155
+ /**
156
+ * Increment compute usage for an account and pod.
157
+ */
158
+ async incrementComputeUsage(accountId, podId, secondsDelta) {
159
+ const normalized = this.normalizeDelta(secondsDelta);
160
+ if (normalized === 0) {
161
+ return;
162
+ }
163
+ await this.db.transaction(async (tx) => {
164
+ await this.incrementPodComputeWith(tx, accountId, podId, normalized);
165
+ await this.incrementAccountComputeWith(tx, accountId, normalized);
166
+ });
167
+ }
168
+ async incrementAccountTokensWith(client, accountId, tokensDelta) {
169
+ await client.insert(this.schema.accountUsage)
170
+ .values({
171
+ accountId,
172
+ storageBytes: 0,
173
+ ingressBytes: 0,
174
+ egressBytes: 0,
175
+ tokensUsed: tokensDelta,
176
+ })
177
+ .onConflictDoUpdate({
178
+ target: this.schema.accountUsage.accountId,
179
+ set: {
180
+ tokensUsed: (0, drizzle_orm_1.sql) `${this.schema.accountUsage.tokensUsed} + ${tokensDelta}`,
181
+ updatedAt: this.now(),
182
+ },
183
+ });
184
+ }
185
+ async incrementPodTokensWith(client, accountId, podId, tokensDelta) {
186
+ await client.insert(this.schema.podUsage)
187
+ .values({
188
+ podId,
189
+ accountId,
190
+ storageBytes: 0,
191
+ ingressBytes: 0,
192
+ egressBytes: 0,
193
+ tokensUsed: tokensDelta,
194
+ })
195
+ .onConflictDoUpdate({
196
+ target: this.schema.podUsage.podId,
197
+ set: {
198
+ tokensUsed: (0, drizzle_orm_1.sql) `${this.schema.podUsage.tokensUsed} + ${tokensDelta}`,
199
+ accountId,
200
+ updatedAt: this.now(),
201
+ },
202
+ });
203
+ }
204
+ async incrementAccountComputeWith(client, accountId, secondsDelta) {
205
+ await client.insert(this.schema.accountUsage)
206
+ .values({
207
+ accountId,
208
+ storageBytes: 0,
209
+ ingressBytes: 0,
210
+ egressBytes: 0,
211
+ computeSeconds: secondsDelta,
212
+ })
213
+ .onConflictDoUpdate({
214
+ target: this.schema.accountUsage.accountId,
215
+ set: {
216
+ computeSeconds: (0, drizzle_orm_1.sql) `${this.schema.accountUsage.computeSeconds} + ${secondsDelta}`,
217
+ updatedAt: this.now(),
218
+ },
219
+ });
220
+ }
221
+ async incrementPodComputeWith(client, accountId, podId, secondsDelta) {
222
+ await client.insert(this.schema.podUsage)
223
+ .values({
224
+ podId,
225
+ accountId,
226
+ storageBytes: 0,
227
+ ingressBytes: 0,
228
+ egressBytes: 0,
229
+ computeSeconds: secondsDelta,
230
+ })
231
+ .onConflictDoUpdate({
232
+ target: this.schema.podUsage.podId,
233
+ set: {
234
+ computeSeconds: (0, drizzle_orm_1.sql) `${this.schema.podUsage.computeSeconds} + ${secondsDelta}`,
235
+ accountId,
236
+ updatedAt: this.now(),
237
+ },
238
+ });
239
+ }
116
240
  async incrementAccountUsageWith(client, accountId, storageDelta, ingressDelta, egressDelta) {
117
- await client.insert(schema_1.accountUsage)
241
+ await client.insert(this.schema.accountUsage)
118
242
  .values({
119
243
  accountId,
120
244
  storageBytes: storageDelta,
@@ -122,17 +246,17 @@ class UsageRepository {
122
246
  egressBytes: egressDelta,
123
247
  })
124
248
  .onConflictDoUpdate({
125
- target: schema_1.accountUsage.accountId,
249
+ target: this.schema.accountUsage.accountId,
126
250
  set: {
127
- storageBytes: (0, drizzle_orm_1.sql) `${schema_1.accountUsage.storageBytes} + ${storageDelta}`,
128
- ingressBytes: (0, drizzle_orm_1.sql) `${schema_1.accountUsage.ingressBytes} + ${ingressDelta}`,
129
- egressBytes: (0, drizzle_orm_1.sql) `${schema_1.accountUsage.egressBytes} + ${egressDelta}`,
130
- updatedAt: (0, drizzle_orm_1.sql) `now()`,
251
+ storageBytes: (0, drizzle_orm_1.sql) `${this.schema.accountUsage.storageBytes} + ${storageDelta}`,
252
+ ingressBytes: (0, drizzle_orm_1.sql) `${this.schema.accountUsage.ingressBytes} + ${ingressDelta}`,
253
+ egressBytes: (0, drizzle_orm_1.sql) `${this.schema.accountUsage.egressBytes} + ${egressDelta}`,
254
+ updatedAt: this.now(),
131
255
  },
132
256
  });
133
257
  }
134
258
  async incrementPodUsageWith(client, accountId, podId, storageDelta, ingressDelta, egressDelta) {
135
- await client.insert(schema_1.podUsage)
259
+ await client.insert(this.schema.podUsage)
136
260
  .values({
137
261
  podId,
138
262
  accountId,
@@ -141,13 +265,13 @@ class UsageRepository {
141
265
  egressBytes: egressDelta,
142
266
  })
143
267
  .onConflictDoUpdate({
144
- target: schema_1.podUsage.podId,
268
+ target: this.schema.podUsage.podId,
145
269
  set: {
146
- storageBytes: (0, drizzle_orm_1.sql) `${schema_1.podUsage.storageBytes} + ${storageDelta}`,
147
- ingressBytes: (0, drizzle_orm_1.sql) `${schema_1.podUsage.ingressBytes} + ${ingressDelta}`,
148
- egressBytes: (0, drizzle_orm_1.sql) `${schema_1.podUsage.egressBytes} + ${egressDelta}`,
270
+ storageBytes: (0, drizzle_orm_1.sql) `${this.schema.podUsage.storageBytes} + ${storageDelta}`,
271
+ ingressBytes: (0, drizzle_orm_1.sql) `${this.schema.podUsage.ingressBytes} + ${ingressDelta}`,
272
+ egressBytes: (0, drizzle_orm_1.sql) `${this.schema.podUsage.egressBytes} + ${egressDelta}`,
149
273
  accountId,
150
- updatedAt: (0, drizzle_orm_1.sql) `now()`,
274
+ updatedAt: this.now(),
151
275
  },
152
276
  });
153
277
  }
@@ -166,7 +290,7 @@ class UsageRepository {
166
290
  insertValues.bandwidthLimitBps = bandwidthLimit;
167
291
  }
168
292
  const updateSet = {
169
- updatedAt: (0, drizzle_orm_1.sql) `now()`,
293
+ updatedAt: this.now(),
170
294
  };
171
295
  if (typeof storageValue === 'number') {
172
296
  updateSet.storageBytes = storageValue;
@@ -177,10 +301,10 @@ class UsageRepository {
177
301
  if (bandwidthLimit !== undefined) {
178
302
  updateSet.bandwidthLimitBps = bandwidthLimit;
179
303
  }
180
- await client.insert(schema_1.accountUsage)
304
+ await client.insert(this.schema.accountUsage)
181
305
  .values(insertValues)
182
306
  .onConflictDoUpdate({
183
- target: schema_1.accountUsage.accountId,
307
+ target: this.schema.accountUsage.accountId,
184
308
  set: updateSet,
185
309
  });
186
310
  }
@@ -201,7 +325,7 @@ class UsageRepository {
201
325
  }
202
326
  const updateSet = {
203
327
  accountId,
204
- updatedAt: (0, drizzle_orm_1.sql) `now()`,
328
+ updatedAt: this.now(),
205
329
  };
206
330
  if (typeof storageValue === 'number') {
207
331
  updateSet.storageBytes = storageValue;
@@ -212,23 +336,72 @@ class UsageRepository {
212
336
  if (bandwidthLimit !== undefined) {
213
337
  updateSet.bandwidthLimitBps = bandwidthLimit;
214
338
  }
215
- await client.insert(schema_1.podUsage)
339
+ await client.insert(this.schema.podUsage)
216
340
  .values(insertValues)
217
341
  .onConflictDoUpdate({
218
- target: schema_1.podUsage.podId,
342
+ target: this.schema.podUsage.podId,
219
343
  set: updateSet,
220
344
  });
221
345
  }
346
+ /**
347
+ * Generic account limit setter for compute/token limits.
348
+ */
349
+ async upsertAccountLimit(client, accountId, field, value) {
350
+ const insertValues = {
351
+ accountId,
352
+ storageBytes: 0,
353
+ ingressBytes: 0,
354
+ egressBytes: 0,
355
+ [field]: value,
356
+ };
357
+ await client.insert(this.schema.accountUsage)
358
+ .values(insertValues)
359
+ .onConflictDoUpdate({
360
+ target: this.schema.accountUsage.accountId,
361
+ set: {
362
+ [field]: value,
363
+ updatedAt: this.now(),
364
+ },
365
+ });
366
+ }
367
+ /**
368
+ * Generic pod limit setter for compute/token limits.
369
+ */
370
+ async upsertPodLimit(client, accountId, podId, field, value) {
371
+ const insertValues = {
372
+ podId,
373
+ accountId,
374
+ storageBytes: 0,
375
+ ingressBytes: 0,
376
+ egressBytes: 0,
377
+ [field]: value,
378
+ };
379
+ await client.insert(this.schema.podUsage)
380
+ .values(insertValues)
381
+ .onConflictDoUpdate({
382
+ target: this.schema.podUsage.podId,
383
+ set: {
384
+ accountId,
385
+ [field]: value,
386
+ updatedAt: this.now(),
387
+ },
388
+ });
389
+ }
222
390
  async getPodUsageWith(client, podId) {
223
391
  const result = await client.select({
224
- accountId: schema_1.podUsage.accountId,
225
- storage: schema_1.podUsage.storageBytes,
226
- ingress: schema_1.podUsage.ingressBytes,
227
- egress: schema_1.podUsage.egressBytes,
228
- storageLimit: schema_1.podUsage.storageLimitBytes,
229
- bandwidthLimit: schema_1.podUsage.bandwidthLimitBps,
230
- }).from(schema_1.podUsage)
231
- .where((0, drizzle_orm_1.eq)(schema_1.podUsage.podId, podId));
392
+ accountId: this.schema.podUsage.accountId,
393
+ storage: this.schema.podUsage.storageBytes,
394
+ ingress: this.schema.podUsage.ingressBytes,
395
+ egress: this.schema.podUsage.egressBytes,
396
+ storageLimit: this.schema.podUsage.storageLimitBytes,
397
+ bandwidthLimit: this.schema.podUsage.bandwidthLimitBps,
398
+ computeSeconds: this.schema.podUsage.computeSeconds,
399
+ tokensUsed: this.schema.podUsage.tokensUsed,
400
+ computeLimitSeconds: this.schema.podUsage.computeLimitSeconds,
401
+ tokenLimitMonthly: this.schema.podUsage.tokenLimitMonthly,
402
+ periodStart: this.schema.podUsage.periodStart,
403
+ }).from(this.schema.podUsage)
404
+ .where((0, drizzle_orm_1.eq)(this.schema.podUsage.podId, podId));
232
405
  if (!result || result.length === 0) {
233
406
  return undefined;
234
407
  }
@@ -242,6 +415,11 @@ class UsageRepository {
242
415
  egressBytes: this.coerceNumber(row.egress),
243
416
  storageLimitBytes: this.coerceNullable(row.storageLimit),
244
417
  bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),
418
+ computeSeconds: this.coerceNumber(row.computeSeconds),
419
+ tokensUsed: this.coerceNumber(row.tokensUsed),
420
+ computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),
421
+ tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),
422
+ periodStart: this.coerceTimestamp(row.periodStart),
245
423
  };
246
424
  }
247
425
  normalizeDelta(value) {
@@ -273,6 +451,30 @@ class UsageRepository {
273
451
  }
274
452
  return Math.trunc(numeric);
275
453
  }
454
+ /**
455
+ * Coerce timestamp value to Unix timestamp (seconds).
456
+ * Handles Date objects (from PG) and numbers (from SQLite).
457
+ */
458
+ coerceTimestamp(value) {
459
+ if (value === null || value === undefined) {
460
+ return null;
461
+ }
462
+ if (value instanceof Date) {
463
+ return Math.floor(value.getTime() / 1000);
464
+ }
465
+ if (typeof value === 'number') {
466
+ return value;
467
+ }
468
+ return null;
469
+ }
470
+ /**
471
+ * Get the current timestamp in the format expected by the database.
472
+ * PG expects Date objects, SQLite expects Unix timestamps (seconds).
473
+ */
474
+ now() {
475
+ const timestamp = new Date();
476
+ return (0, db_1.isDatabaseSqlite)(this.db) ? Math.floor(timestamp.getTime() / 1000) : timestamp;
477
+ }
276
478
  }
277
479
  exports.UsageRepository = UsageRepository;
278
480
  //# sourceMappingURL=UsageRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"UsageRepository.js","sourceRoot":"","sources":["../../../src/storage/quota/UsageRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql, eq } from 'drizzle-orm';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport type { NodePgTransaction } from 'drizzle-orm/node-postgres/session';\nimport { accountUsage, podUsage } from '../../identity/drizzle/schema';\n\ntype DbClient = IdentityDatabase | NodePgTransaction<any, any>;\n\nexport interface AccountUsageRecord {\n accountId: string;\n storageBytes: number;\n ingressBytes: number;\n egressBytes: number;\n storageLimitBytes?: number | null;\n bandwidthLimitBps?: number | null;\n}\n\nexport interface PodUsageRecord extends AccountUsageRecord {\n podId: string;\n}\n\n/**\n * Repository for tracking pod and account usage metrics.\n * NOTE: This repository only supports PostgreSQL. SQLite is not supported.\n * For local/dev modes, usage tracking should be disabled.\n *\n * TODO: Make UsageRepository database-agnostic to support SQLite in local mode.\n * Required changes:\n * - Replace `sql\\`now()\\`` with cross-database compatible timestamp (e.g., new Date())\n * - Use Drizzle's database-agnostic transaction API or raw SQL compatible with both\n * - Test with both SQLite and PostgreSQL backends\n */\nexport class UsageRepository {\n public constructor(private readonly db: IdentityDatabase) {}\n\n public async incrementUsage(accountId: string, podId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n const normalizedStorage = this.normalizeDelta(storageDelta);\n const normalizedIngress = this.normalizeDelta(ingressDelta);\n const normalizedEgress = this.normalizeDelta(egressDelta);\n if (normalizedStorage === 0 && normalizedIngress === 0 && normalizedEgress === 0) {\n return;\n }\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.incrementPodUsageWith(tx, accountId, podId, normalizedStorage, normalizedIngress, normalizedEgress);\n await this.incrementAccountUsageWith(tx, accountId, normalizedStorage, normalizedIngress, normalizedEgress);\n });\n }\n\n public async incrementBandwidth(accountId: string, podId: string, ingressDelta: number, egressDelta: number): Promise<void> {\n await this.incrementUsage(accountId, podId, 0, ingressDelta, egressDelta);\n }\n\n public async setPodStorage(accountId: string, podId: string, storageBytes: number): Promise<void> {\n const normalized = this.normalizeValue(storageBytes);\n await this.db.transaction(async (tx: IdentityDatabase) => {\n const current = await this.getPodUsageWith(tx, podId);\n const owningAccountId = current?.accountId ?? accountId;\n const previousStorage = current?.storageBytes ?? 0;\n const delta = normalized - previousStorage;\n\n await this.upsertPodUsage(tx, owningAccountId, podId, normalized);\n if (delta !== 0) {\n await this.incrementAccountUsageWith(tx, owningAccountId, delta, 0, 0);\n }\n });\n }\n\n public async setAccountStorage(accountId: string, storageBytes: number): Promise<void> {\n const normalized = this.normalizeValue(storageBytes);\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.upsertAccountUsage(tx, accountId, normalized);\n // Adjust pod rows proportionally is undefined behaviour here, so only account-level storage is updated.\n // Pods should be updated independently by their respective setters.\n });\n }\n\n public async getAccountUsage(accountId: string): Promise<AccountUsageRecord | undefined> {\n const result = await this.db.select({\n storage: accountUsage.storageBytes,\n ingress: accountUsage.ingressBytes,\n egress: accountUsage.egressBytes,\n storageLimit: accountUsage.storageLimitBytes,\n bandwidthLimit: accountUsage.bandwidthLimitBps,\n }).from(accountUsage)\n .where(eq(accountUsage.accountId, accountId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n return {\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n };\n }\n\n public async getPodUsage(podId: string): Promise<PodUsageRecord | undefined> {\n const result = await this.db.select({\n accountId: podUsage.accountId,\n storage: podUsage.storageBytes,\n ingress: podUsage.ingressBytes,\n egress: podUsage.egressBytes,\n storageLimit: podUsage.storageLimitBytes,\n bandwidthLimit: podUsage.bandwidthLimitBps,\n }).from(podUsage)\n .where(eq(podUsage.podId, podId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n const accountId = String(row.accountId);\n return {\n podId,\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n };\n }\n\n public async setAccountStorageLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountUsage(this.db, accountId, undefined, limit, undefined);\n }\n\n public async setPodStorageLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodUsage(this.db, accountId, podId, undefined, limit, undefined);\n }\n\n public async setAccountBandwidthLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountUsage(this.db, accountId, undefined, undefined, limit);\n }\n\n public async setPodBandwidthLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodUsage(this.db, accountId, podId, undefined, undefined, limit);\n }\n\n private async incrementAccountUsageWith(client: DbClient, accountId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n await client.insert(accountUsage)\n .values({\n accountId,\n storageBytes: storageDelta,\n ingressBytes: ingressDelta,\n egressBytes: egressDelta,\n })\n .onConflictDoUpdate({\n target: accountUsage.accountId,\n set: {\n storageBytes: sql`${accountUsage.storageBytes} + ${storageDelta}`,\n ingressBytes: sql`${accountUsage.ingressBytes} + ${ingressDelta}`,\n egressBytes: sql`${accountUsage.egressBytes} + ${egressDelta}`,\n updatedAt: sql`now()`,\n },\n });\n }\n\n private async incrementPodUsageWith(client: DbClient, accountId: string, podId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n await client.insert(podUsage)\n .values({\n podId,\n accountId,\n storageBytes: storageDelta,\n ingressBytes: ingressDelta,\n egressBytes: egressDelta,\n })\n .onConflictDoUpdate({\n target: podUsage.podId,\n set: {\n storageBytes: sql`${podUsage.storageBytes} + ${storageDelta}`,\n ingressBytes: sql`${podUsage.ingressBytes} + ${ingressDelta}`,\n egressBytes: sql`${podUsage.egressBytes} + ${egressDelta}`,\n accountId,\n updatedAt: sql`now()`,\n },\n });\n }\n\n private async upsertAccountUsage(client: DbClient, accountId: string, storageBytes?: number, storageLimit?: number | null, bandwidthLimit?: number | null): Promise<void> {\n const storageValue = typeof storageBytes === 'number' ? this.normalizeValue(storageBytes) : undefined;\n const insertValues: Record<string, unknown> = {\n accountId,\n storageBytes: storageValue ?? 0,\n ingressBytes: 0,\n egressBytes: 0,\n };\n if (storageLimit !== undefined) {\n insertValues.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n insertValues.bandwidthLimitBps = bandwidthLimit;\n }\n const updateSet: Record<string, unknown> = {\n updatedAt: sql`now()`,\n };\n if (typeof storageValue === 'number') {\n updateSet.storageBytes = storageValue;\n }\n if (storageLimit !== undefined) {\n updateSet.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n updateSet.bandwidthLimitBps = bandwidthLimit;\n }\n await client.insert(accountUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: accountUsage.accountId,\n set: updateSet,\n });\n }\n\n private async upsertPodUsage(client: DbClient, accountId: string, podId: string, storageBytes?: number, storageLimit?: number | null, bandwidthLimit?: number | null): Promise<void> {\n const storageValue = typeof storageBytes === 'number' ? this.normalizeValue(storageBytes) : undefined;\n const insertValues: Record<string, unknown> = {\n podId,\n accountId,\n storageBytes: storageValue ?? 0,\n ingressBytes: 0,\n egressBytes: 0,\n };\n if (storageLimit !== undefined) {\n insertValues.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n insertValues.bandwidthLimitBps = bandwidthLimit;\n }\n const updateSet: Record<string, unknown> = {\n accountId,\n updatedAt: sql`now()`,\n };\n if (typeof storageValue === 'number') {\n updateSet.storageBytes = storageValue;\n }\n if (storageLimit !== undefined) {\n updateSet.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n updateSet.bandwidthLimitBps = bandwidthLimit;\n }\n await client.insert(podUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: podUsage.podId,\n set: updateSet,\n });\n }\n\n private async getPodUsageWith(client: DbClient, podId: string): Promise<PodUsageRecord | undefined> {\n const result = await client.select({\n accountId: podUsage.accountId,\n storage: podUsage.storageBytes,\n ingress: podUsage.ingressBytes,\n egress: podUsage.egressBytes,\n storageLimit: podUsage.storageLimitBytes,\n bandwidthLimit: podUsage.bandwidthLimitBps,\n }).from(podUsage)\n .where(eq(podUsage.podId, podId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n const accountId = String(row.accountId);\n return {\n podId,\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n };\n }\n\n private normalizeDelta(value: number): number {\n if (!Number.isFinite(value) || value === 0) {\n return 0;\n }\n return Math.trunc(value);\n }\n\n private normalizeValue(value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n return 0;\n }\n return Math.max(0, Math.trunc(value));\n }\n\n private coerceNumber(value: unknown): number {\n const numeric = Number(value ?? 0);\n return Number.isFinite(numeric) ? numeric : 0;\n }\n\n private coerceNullable(value: unknown): number | null | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n const numeric = Number(value);\n if (!Number.isFinite(numeric)) {\n return null;\n }\n return Math.trunc(numeric);\n }\n}\n"]}
1
+ {"version":3,"file":"UsageRepository.js","sourceRoot":"","sources":["../../../src/storage/quota/UsageRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql, eq } from 'drizzle-orm';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport { getSchema, isDatabaseSqlite } from '../../identity/drizzle/db';\nimport type { NodePgTransaction } from 'drizzle-orm/node-postgres/session';\n\ntype DbClient = IdentityDatabase | NodePgTransaction<any, any>;\n\nexport interface AccountUsageRecord {\n accountId: string;\n storageBytes: number;\n ingressBytes: number;\n egressBytes: number;\n storageLimitBytes?: number | null;\n bandwidthLimitBps?: number | null;\n computeSeconds: number;\n tokensUsed: number;\n computeLimitSeconds?: number | null;\n tokenLimitMonthly?: number | null;\n periodStart?: number | null;\n}\n\nexport interface PodUsageRecord extends AccountUsageRecord {\n podId: string;\n}\n\n/**\n * Repository for tracking pod and account usage metrics.\n * Supports both PostgreSQL and SQLite through unified schema abstraction.\n */\nexport class UsageRepository {\n private readonly schema: ReturnType<typeof getSchema>;\n\n public constructor(private readonly db: IdentityDatabase) {\n this.schema = getSchema(db);\n }\n\n public async incrementUsage(accountId: string, podId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n const normalizedStorage = this.normalizeDelta(storageDelta);\n const normalizedIngress = this.normalizeDelta(ingressDelta);\n const normalizedEgress = this.normalizeDelta(egressDelta);\n if (normalizedStorage === 0 && normalizedIngress === 0 && normalizedEgress === 0) {\n return;\n }\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.incrementPodUsageWith(tx, accountId, podId, normalizedStorage, normalizedIngress, normalizedEgress);\n await this.incrementAccountUsageWith(tx, accountId, normalizedStorage, normalizedIngress, normalizedEgress);\n });\n }\n\n public async incrementBandwidth(accountId: string, podId: string, ingressDelta: number, egressDelta: number): Promise<void> {\n await this.incrementUsage(accountId, podId, 0, ingressDelta, egressDelta);\n }\n\n public async setPodStorage(accountId: string, podId: string, storageBytes: number): Promise<void> {\n const normalized = this.normalizeValue(storageBytes);\n await this.db.transaction(async (tx: IdentityDatabase) => {\n const current = await this.getPodUsageWith(tx, podId);\n const owningAccountId = current?.accountId ?? accountId;\n const previousStorage = current?.storageBytes ?? 0;\n const delta = normalized - previousStorage;\n\n await this.upsertPodUsage(tx, owningAccountId, podId, normalized);\n if (delta !== 0) {\n await this.incrementAccountUsageWith(tx, owningAccountId, delta, 0, 0);\n }\n });\n }\n\n public async setAccountStorage(accountId: string, storageBytes: number): Promise<void> {\n const normalized = this.normalizeValue(storageBytes);\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.upsertAccountUsage(tx, accountId, normalized);\n // Adjust pod rows proportionally is undefined behaviour here, so only account-level storage is updated.\n // Pods should be updated independently by their respective setters.\n });\n }\n\n public async getAccountUsage(accountId: string): Promise<AccountUsageRecord | undefined> {\n const result = await this.db.select({\n storage: this.schema.accountUsage.storageBytes,\n ingress: this.schema.accountUsage.ingressBytes,\n egress: this.schema.accountUsage.egressBytes,\n storageLimit: this.schema.accountUsage.storageLimitBytes,\n bandwidthLimit: this.schema.accountUsage.bandwidthLimitBps,\n computeSeconds: this.schema.accountUsage.computeSeconds,\n tokensUsed: this.schema.accountUsage.tokensUsed,\n computeLimitSeconds: this.schema.accountUsage.computeLimitSeconds,\n tokenLimitMonthly: this.schema.accountUsage.tokenLimitMonthly,\n periodStart: this.schema.accountUsage.periodStart,\n }).from(this.schema.accountUsage)\n .where(eq(this.schema.accountUsage.accountId, accountId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n return {\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n computeSeconds: this.coerceNumber(row.computeSeconds),\n tokensUsed: this.coerceNumber(row.tokensUsed),\n computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),\n tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),\n periodStart: this.coerceTimestamp(row.periodStart),\n };\n }\n\n public async getPodUsage(podId: string): Promise<PodUsageRecord | undefined> {\n const result = await this.db.select({\n accountId: this.schema.podUsage.accountId,\n storage: this.schema.podUsage.storageBytes,\n ingress: this.schema.podUsage.ingressBytes,\n egress: this.schema.podUsage.egressBytes,\n storageLimit: this.schema.podUsage.storageLimitBytes,\n bandwidthLimit: this.schema.podUsage.bandwidthLimitBps,\n computeSeconds: this.schema.podUsage.computeSeconds,\n tokensUsed: this.schema.podUsage.tokensUsed,\n computeLimitSeconds: this.schema.podUsage.computeLimitSeconds,\n tokenLimitMonthly: this.schema.podUsage.tokenLimitMonthly,\n periodStart: this.schema.podUsage.periodStart,\n }).from(this.schema.podUsage)\n .where(eq(this.schema.podUsage.podId, podId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n const accountId = String(row.accountId);\n return {\n podId,\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n computeSeconds: this.coerceNumber(row.computeSeconds),\n tokensUsed: this.coerceNumber(row.tokensUsed),\n computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),\n tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),\n periodStart: this.coerceTimestamp(row.periodStart),\n };\n }\n\n public async setAccountStorageLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountUsage(this.db, accountId, undefined, limit, undefined);\n }\n\n public async setPodStorageLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodUsage(this.db, accountId, podId, undefined, limit, undefined);\n }\n\n public async setAccountBandwidthLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountUsage(this.db, accountId, undefined, undefined, limit);\n }\n\n public async setPodBandwidthLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodUsage(this.db, accountId, podId, undefined, undefined, limit);\n }\n\n public async setAccountComputeLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountLimit(this.db, accountId, 'computeLimitSeconds', limit);\n }\n\n public async setAccountTokenLimit(accountId: string, limit: number | null): Promise<void> {\n await this.upsertAccountLimit(this.db, accountId, 'tokenLimitMonthly', limit);\n }\n\n public async setPodComputeLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodLimit(this.db, accountId, podId, 'computeLimitSeconds', limit);\n }\n\n public async setPodTokenLimit(podId: string, accountId: string, limit: number | null): Promise<void> {\n await this.upsertPodLimit(this.db, accountId, podId, 'tokenLimitMonthly', limit);\n }\n\n /**\n * Increment token usage for an account and pod.\n */\n public async incrementTokenUsage(accountId: string, podId: string, tokensDelta: number): Promise<void> {\n const normalized = this.normalizeDelta(tokensDelta);\n if (normalized === 0) {\n return;\n }\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.incrementPodTokensWith(tx, accountId, podId, normalized);\n await this.incrementAccountTokensWith(tx, accountId, normalized);\n });\n }\n\n /**\n * Increment compute usage for an account and pod.\n */\n public async incrementComputeUsage(accountId: string, podId: string, secondsDelta: number): Promise<void> {\n const normalized = this.normalizeDelta(secondsDelta);\n if (normalized === 0) {\n return;\n }\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await this.incrementPodComputeWith(tx, accountId, podId, normalized);\n await this.incrementAccountComputeWith(tx, accountId, normalized);\n });\n }\n\n private async incrementAccountTokensWith(client: DbClient, accountId: string, tokensDelta: number): Promise<void> {\n await client.insert(this.schema.accountUsage)\n .values({\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n tokensUsed: tokensDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.accountUsage.accountId,\n set: {\n tokensUsed: sql`${this.schema.accountUsage.tokensUsed} + ${tokensDelta}`,\n updatedAt: this.now(),\n },\n });\n }\n\n private async incrementPodTokensWith(client: DbClient, accountId: string, podId: string, tokensDelta: number): Promise<void> {\n await client.insert(this.schema.podUsage)\n .values({\n podId,\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n tokensUsed: tokensDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.podUsage.podId,\n set: {\n tokensUsed: sql`${this.schema.podUsage.tokensUsed} + ${tokensDelta}`,\n accountId,\n updatedAt: this.now(),\n },\n });\n }\n\n private async incrementAccountComputeWith(client: DbClient, accountId: string, secondsDelta: number): Promise<void> {\n await client.insert(this.schema.accountUsage)\n .values({\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n computeSeconds: secondsDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.accountUsage.accountId,\n set: {\n computeSeconds: sql`${this.schema.accountUsage.computeSeconds} + ${secondsDelta}`,\n updatedAt: this.now(),\n },\n });\n }\n\n private async incrementPodComputeWith(client: DbClient, accountId: string, podId: string, secondsDelta: number): Promise<void> {\n await client.insert(this.schema.podUsage)\n .values({\n podId,\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n computeSeconds: secondsDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.podUsage.podId,\n set: {\n computeSeconds: sql`${this.schema.podUsage.computeSeconds} + ${secondsDelta}`,\n accountId,\n updatedAt: this.now(),\n },\n });\n }\n\n private async incrementAccountUsageWith(client: DbClient, accountId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n await client.insert(this.schema.accountUsage)\n .values({\n accountId,\n storageBytes: storageDelta,\n ingressBytes: ingressDelta,\n egressBytes: egressDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.accountUsage.accountId,\n set: {\n storageBytes: sql`${this.schema.accountUsage.storageBytes} + ${storageDelta}`,\n ingressBytes: sql`${this.schema.accountUsage.ingressBytes} + ${ingressDelta}`,\n egressBytes: sql`${this.schema.accountUsage.egressBytes} + ${egressDelta}`,\n updatedAt: this.now(),\n },\n });\n }\n\n private async incrementPodUsageWith(client: DbClient, accountId: string, podId: string, storageDelta: number, ingressDelta: number, egressDelta: number): Promise<void> {\n await client.insert(this.schema.podUsage)\n .values({\n podId,\n accountId,\n storageBytes: storageDelta,\n ingressBytes: ingressDelta,\n egressBytes: egressDelta,\n })\n .onConflictDoUpdate({\n target: this.schema.podUsage.podId,\n set: {\n storageBytes: sql`${this.schema.podUsage.storageBytes} + ${storageDelta}`,\n ingressBytes: sql`${this.schema.podUsage.ingressBytes} + ${ingressDelta}`,\n egressBytes: sql`${this.schema.podUsage.egressBytes} + ${egressDelta}`,\n accountId,\n updatedAt: this.now(),\n },\n });\n }\n\n private async upsertAccountUsage(client: DbClient, accountId: string, storageBytes?: number, storageLimit?: number | null, bandwidthLimit?: number | null): Promise<void> {\n const storageValue = typeof storageBytes === 'number' ? this.normalizeValue(storageBytes) : undefined;\n const insertValues: Record<string, unknown> = {\n accountId,\n storageBytes: storageValue ?? 0,\n ingressBytes: 0,\n egressBytes: 0,\n };\n if (storageLimit !== undefined) {\n insertValues.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n insertValues.bandwidthLimitBps = bandwidthLimit;\n }\n const updateSet: Record<string, unknown> = {\n updatedAt: this.now(),\n };\n if (typeof storageValue === 'number') {\n updateSet.storageBytes = storageValue;\n }\n if (storageLimit !== undefined) {\n updateSet.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n updateSet.bandwidthLimitBps = bandwidthLimit;\n }\n await client.insert(this.schema.accountUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: this.schema.accountUsage.accountId,\n set: updateSet,\n });\n }\n\n private async upsertPodUsage(client: DbClient, accountId: string, podId: string, storageBytes?: number, storageLimit?: number | null, bandwidthLimit?: number | null): Promise<void> {\n const storageValue = typeof storageBytes === 'number' ? this.normalizeValue(storageBytes) : undefined;\n const insertValues: Record<string, unknown> = {\n podId,\n accountId,\n storageBytes: storageValue ?? 0,\n ingressBytes: 0,\n egressBytes: 0,\n };\n if (storageLimit !== undefined) {\n insertValues.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n insertValues.bandwidthLimitBps = bandwidthLimit;\n }\n const updateSet: Record<string, unknown> = {\n accountId,\n updatedAt: this.now(),\n };\n if (typeof storageValue === 'number') {\n updateSet.storageBytes = storageValue;\n }\n if (storageLimit !== undefined) {\n updateSet.storageLimitBytes = storageLimit;\n }\n if (bandwidthLimit !== undefined) {\n updateSet.bandwidthLimitBps = bandwidthLimit;\n }\n await client.insert(this.schema.podUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: this.schema.podUsage.podId,\n set: updateSet,\n });\n }\n\n /**\n * Generic account limit setter for compute/token limits.\n */\n private async upsertAccountLimit(client: DbClient, accountId: string, field: 'computeLimitSeconds' | 'tokenLimitMonthly', value: number | null): Promise<void> {\n const insertValues: Record<string, unknown> = {\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n [field]: value,\n };\n await client.insert(this.schema.accountUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: this.schema.accountUsage.accountId,\n set: {\n [field]: value,\n updatedAt: this.now(),\n },\n });\n }\n\n /**\n * Generic pod limit setter for compute/token limits.\n */\n private async upsertPodLimit(client: DbClient, accountId: string, podId: string, field: 'computeLimitSeconds' | 'tokenLimitMonthly', value: number | null): Promise<void> {\n const insertValues: Record<string, unknown> = {\n podId,\n accountId,\n storageBytes: 0,\n ingressBytes: 0,\n egressBytes: 0,\n [field]: value,\n };\n await client.insert(this.schema.podUsage)\n .values(insertValues)\n .onConflictDoUpdate({\n target: this.schema.podUsage.podId,\n set: {\n accountId,\n [field]: value,\n updatedAt: this.now(),\n },\n });\n }\n\n private async getPodUsageWith(client: DbClient, podId: string): Promise<PodUsageRecord | undefined> {\n const result = await client.select({\n accountId: this.schema.podUsage.accountId,\n storage: this.schema.podUsage.storageBytes,\n ingress: this.schema.podUsage.ingressBytes,\n egress: this.schema.podUsage.egressBytes,\n storageLimit: this.schema.podUsage.storageLimitBytes,\n bandwidthLimit: this.schema.podUsage.bandwidthLimitBps,\n computeSeconds: this.schema.podUsage.computeSeconds,\n tokensUsed: this.schema.podUsage.tokensUsed,\n computeLimitSeconds: this.schema.podUsage.computeLimitSeconds,\n tokenLimitMonthly: this.schema.podUsage.tokenLimitMonthly,\n periodStart: this.schema.podUsage.periodStart,\n }).from(this.schema.podUsage)\n .where(eq(this.schema.podUsage.podId, podId));\n if (!result || result.length === 0) {\n return undefined;\n }\n const row = result[0];\n const accountId = String(row.accountId);\n return {\n podId,\n accountId,\n storageBytes: this.coerceNumber(row.storage),\n ingressBytes: this.coerceNumber(row.ingress),\n egressBytes: this.coerceNumber(row.egress),\n storageLimitBytes: this.coerceNullable(row.storageLimit),\n bandwidthLimitBps: this.coerceNullable(row.bandwidthLimit),\n computeSeconds: this.coerceNumber(row.computeSeconds),\n tokensUsed: this.coerceNumber(row.tokensUsed),\n computeLimitSeconds: this.coerceNullable(row.computeLimitSeconds),\n tokenLimitMonthly: this.coerceNullable(row.tokenLimitMonthly),\n periodStart: this.coerceTimestamp(row.periodStart),\n };\n }\n\n private normalizeDelta(value: number): number {\n if (!Number.isFinite(value) || value === 0) {\n return 0;\n }\n return Math.trunc(value);\n }\n\n private normalizeValue(value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n return 0;\n }\n return Math.max(0, Math.trunc(value));\n }\n\n private coerceNumber(value: unknown): number {\n const numeric = Number(value ?? 0);\n return Number.isFinite(numeric) ? numeric : 0;\n }\n\n private coerceNullable(value: unknown): number | null | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n const numeric = Number(value);\n if (!Number.isFinite(numeric)) {\n return null;\n }\n return Math.trunc(numeric);\n }\n\n /**\n * Coerce timestamp value to Unix timestamp (seconds).\n * Handles Date objects (from PG) and numbers (from SQLite).\n */\n private coerceTimestamp(value: unknown): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n if (value instanceof Date) {\n return Math.floor(value.getTime() / 1000);\n }\n if (typeof value === 'number') {\n return value;\n }\n return null;\n }\n\n /**\n * Get the current timestamp in the format expected by the database.\n * PG expects Date objects, SQLite expects Unix timestamps (seconds).\n */\n private now(): Date | number {\n const timestamp = new Date();\n return isDatabaseSqlite(this.db) ? Math.floor(timestamp.getTime() / 1000) : timestamp;\n }\n}\n"]}
@@ -119,6 +119,15 @@ export declare class ComunicaQuintEngine {
119
119
  * Uses RDF.Store interface since UPDATE doesn't need FILTER pushdown
120
120
  */
121
121
  queryVoid(query: string, context?: QueryContext): Promise<void>;
122
+ /**
123
+ * Parse "DELETE WHERE { GRAPH <uri> { ?s ?p ?o. } }" and return the graph URI.
124
+ * Returns null if the statement doesn't match this pattern.
125
+ */
126
+ private parseDeleteWhereGraph;
127
+ /**
128
+ * Split a compound SPARQL UPDATE into individual statements.
129
+ */
130
+ private splitUpdateStatements;
122
131
  /**
123
132
  * Extract optimization params from SPARQL query
124
133
  */
@@ -559,25 +559,66 @@ class ComunicaQuintEngine {
559
559
  * Uses RDF.Store interface since UPDATE doesn't need FILTER pushdown
560
560
  */
561
561
  async queryVoid(query, context) {
562
- console.log(`[ComunicaQuintEngine.queryVoid] Starting: ${query.slice(0, 100)}...`);
563
562
  this.currentSecurityFilters = context?.filters;
564
563
  try {
565
- const start = Date.now();
566
- const result = await this.engine.queryVoid(query, {
567
- sources: [this.rdfStore],
568
- ...context,
569
- });
570
- console.log(`[ComunicaQuintEngine.queryVoid] Completed in ${Date.now() - start}ms`);
571
- return result;
564
+ // Comunica does not properly await the RDF.Store remove() EventEmitter
565
+ // before proceeding to the next operation. This causes DELETE WHERE to
566
+ // complete after INSERT DATA, deleting newly inserted triples.
567
+ // Fix: split compound updates and handle DELETE WHERE directly via QuintStore.
568
+ const statements = this.splitUpdateStatements(query);
569
+ for (const stmt of statements) {
570
+ const deleteGraphUri = this.parseDeleteWhereGraph(stmt);
571
+ if (deleteGraphUri) {
572
+ // Execute DELETE WHERE directly via QuintStore.del()
573
+ await this.store.del({ graph: { termType: 'NamedNode', value: deleteGraphUri } });
574
+ }
575
+ else {
576
+ await this.engine.queryVoid(stmt, {
577
+ sources: [this.rdfStore],
578
+ ...context,
579
+ });
580
+ }
581
+ }
572
582
  }
573
583
  catch (err) {
574
- console.error(`[ComunicaQuintEngine.queryVoid] Failed:`, err);
575
584
  throw err;
576
585
  }
577
586
  finally {
578
587
  this.currentSecurityFilters = undefined;
579
588
  }
580
589
  }
590
+ /**
591
+ * Parse "DELETE WHERE { GRAPH <uri> { ?s ?p ?o. } }" and return the graph URI.
592
+ * Returns null if the statement doesn't match this pattern.
593
+ */
594
+ parseDeleteWhereGraph(stmt) {
595
+ const m = stmt.match(/^\s*DELETE\s+WHERE\s*\{\s*GRAPH\s*<([^>]+)>\s*\{\s*\?(\w+)\s+\?(\w+)\s+\?(\w+)\s*\.?\s*\}\s*\}\s*$/i);
596
+ return m ? m[1] : null;
597
+ }
598
+ /**
599
+ * Split a compound SPARQL UPDATE into individual statements.
600
+ */
601
+ splitUpdateStatements(query) {
602
+ const statements = [];
603
+ let depth = 0;
604
+ let start = 0;
605
+ for (let i = 0; i < query.length; i++) {
606
+ if (query[i] === '{')
607
+ depth++;
608
+ else if (query[i] === '}')
609
+ depth--;
610
+ else if (query[i] === ';' && depth === 0) {
611
+ const stmt = query.slice(start, i).trim();
612
+ if (stmt)
613
+ statements.push(stmt);
614
+ start = i + 1;
615
+ }
616
+ }
617
+ const last = query.slice(start).trim();
618
+ if (last)
619
+ statements.push(last);
620
+ return statements;
621
+ }
581
622
  /**
582
623
  * Extract optimization params from SPARQL query
583
624
  */