@undefineds.co/xpod 0.3.29 → 0.3.32

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 (167) 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/container/business-token.d.ts +1 -1
  10. package/dist/api/container/business-token.js +5 -1
  11. package/dist/api/container/business-token.js.map +1 -1
  12. package/dist/api/container/common.js +14 -10
  13. package/dist/api/container/common.js.map +1 -1
  14. package/dist/api/container/routes.js +16 -3
  15. package/dist/api/container/routes.js.map +1 -1
  16. package/dist/api/container/types.d.ts +2 -4
  17. package/dist/api/container/types.js.map +1 -1
  18. package/dist/api/handlers/ChatHandler.d.ts +1 -1
  19. package/dist/api/handlers/ChatHandler.js +1 -1
  20. package/dist/api/handlers/ChatHandler.js.map +1 -1
  21. package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
  22. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  23. package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
  24. package/dist/api/handlers/PodManagementHandler.js +114 -12
  25. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  26. package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
  27. package/dist/api/handlers/ProvisionHandler.js +339 -32
  28. package/dist/api/handlers/ProvisionHandler.js.map +1 -1
  29. package/dist/api/handlers/QuotaHandler.js +0 -12
  30. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  31. package/dist/api/handlers/index.d.ts +0 -1
  32. package/dist/api/handlers/index.js +0 -1
  33. package/dist/api/handlers/index.js.map +1 -1
  34. package/dist/api/runtime.js +3 -3
  35. package/dist/api/runtime.js.map +1 -1
  36. package/dist/authorization/PodAuthorizationResources.d.ts +1 -0
  37. package/dist/authorization/PodAuthorizationResources.js +36 -4
  38. package/dist/authorization/PodAuthorizationResources.js.map +1 -1
  39. package/dist/components/context.jsonld +12 -0
  40. package/dist/edge/EdgeNodeAgent.d.ts +1 -1
  41. package/dist/edge/EdgeNodeAgent.js +1 -1
  42. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  43. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
  44. package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
  45. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  46. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
  47. package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
  48. package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
  49. package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
  50. package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
  51. package/dist/http/ClusterIngressRouter.js +6 -3
  52. package/dist/http/ClusterIngressRouter.js.map +1 -1
  53. package/dist/http/ClusterWebSocketConfigurator.js +6 -2
  54. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  55. package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
  56. package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
  57. package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
  58. package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
  59. package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
  60. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  61. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
  62. package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
  63. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  64. package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
  65. package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
  66. package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
  67. package/dist/identity/drizzle/AccountRepository.js +9 -113
  68. package/dist/identity/drizzle/AccountRepository.js.map +1 -1
  69. package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
  70. package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
  71. package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
  72. package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
  73. package/dist/identity/drizzle/DdnsRepository.js +13 -49
  74. package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
  75. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
  76. package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
  77. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  78. package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
  79. package/dist/identity/drizzle/PodLookupRepository.js +103 -126
  80. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  81. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
  82. package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
  83. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
  84. package/dist/identity/drizzle/db.d.ts +2 -1
  85. package/dist/identity/drizzle/db.js +173 -297
  86. package/dist/identity/drizzle/db.js.map +1 -1
  87. package/dist/identity/drizzle/schema.pg.d.ts +3 -11
  88. package/dist/identity/drizzle/schema.pg.js +10 -45
  89. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  90. package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
  91. package/dist/identity/drizzle/schema.sqlite.js +13 -46
  92. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  93. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
  94. package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
  95. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
  96. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
  97. package/dist/provision/LocalPodProvisioningService.js +2 -0
  98. package/dist/provision/LocalPodProvisioningService.js.map +1 -1
  99. package/dist/provision/ProvisionCodeCodec.js +10 -1
  100. package/dist/provision/ProvisionCodeCodec.js.map +1 -1
  101. package/dist/provision/ProvisionPodCreator.d.ts +8 -2
  102. package/dist/provision/ProvisionPodCreator.js +136 -27
  103. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  104. package/dist/provision/ProvisionPodCreator.jsonld +38 -3
  105. package/dist/quota/DrizzleQuotaService.d.ts +0 -4
  106. package/dist/quota/DrizzleQuotaService.js +1 -21
  107. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  108. package/dist/quota/DrizzleQuotaService.jsonld +0 -16
  109. package/dist/quota/NoopQuotaService.d.ts +0 -4
  110. package/dist/quota/NoopQuotaService.js +0 -8
  111. package/dist/quota/NoopQuotaService.js.map +1 -1
  112. package/dist/quota/NoopQuotaService.jsonld +0 -16
  113. package/dist/quota/QuotaService.d.ts +0 -4
  114. package/dist/quota/QuotaService.js.map +1 -1
  115. package/dist/quota/QuotaService.jsonld +0 -16
  116. package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
  117. package/dist/service/EdgeNodeSignalClient.js +0 -4
  118. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  119. package/dist/service/PodMigrationService.d.ts +2 -2
  120. package/dist/service/PodMigrationService.js +4 -4
  121. package/dist/service/PodMigrationService.js.map +1 -1
  122. package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
  123. package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
  124. package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
  125. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  126. package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
  127. package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
  128. package/dist/storage/quota/UsageRepository.d.ts +10 -32
  129. package/dist/storage/quota/UsageRepository.js +84 -281
  130. package/dist/storage/quota/UsageRepository.js.map +1 -1
  131. package/dist/storage/rdf/PostgresRdfEngine.d.ts +12 -15
  132. package/dist/storage/rdf/PostgresRdfEngine.js +1040 -150
  133. package/dist/storage/rdf/PostgresRdfEngine.js.map +1 -1
  134. package/dist/storage/rdf/PostgresRdfEngine.jsonld +40 -52
  135. package/dist/storage/rdf/{RdfLocalQueryEngine.d.ts → RdfQueryExecutor.d.ts} +3 -3
  136. package/dist/storage/rdf/{RdfLocalQueryEngine.js → RdfQueryExecutor.js} +9 -9
  137. package/dist/storage/rdf/RdfQueryExecutor.js.map +1 -0
  138. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +5 -5
  139. package/dist/storage/rdf/RdfSparqlAdapter.js +27 -27
  140. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -1
  141. package/dist/storage/rdf/SolidRdfEngine.d.ts +2 -5
  142. package/dist/storage/rdf/SolidRdfEngine.js +6 -38
  143. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -1
  144. package/dist/storage/rdf/SolidRdfEngine.jsonld +0 -12
  145. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -1
  146. package/dist/storage/rdf/index.d.ts +3 -3
  147. package/dist/storage/rdf/index.js +6 -6
  148. package/dist/storage/rdf/index.js.map +1 -1
  149. package/dist/storage/rdf/models-benchmark.d.ts +9 -9
  150. package/dist/storage/rdf/models-benchmark.js +23 -23
  151. package/dist/storage/rdf/models-benchmark.js.map +1 -1
  152. package/dist/storage/rdf/types.d.ts +5 -5
  153. package/dist/storage/rdf/types.js.map +1 -1
  154. package/dist/subdomain/SubdomainService.d.ts +1 -1
  155. package/dist/subdomain/SubdomainService.js +1 -1
  156. package/dist/subdomain/SubdomainService.js.map +1 -1
  157. package/dist/subdomain/SubdomainService.jsonld +1 -1
  158. package/package.json +1 -1
  159. package/templates/pod/acp/profile/.acr +21 -0
  160. package/templates/pod/wac/profile/.acl.hbs +18 -0
  161. package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
  162. package/dist/api/handlers/ApiKeyHandler.js +0 -153
  163. package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
  164. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
  165. package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
  166. package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
  167. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +0 -1
@@ -50,11 +50,11 @@ class QuotaAdminHttpHandler extends community_server_1.HttpHandler {
50
50
  }
51
51
  async handleGet(target, response) {
52
52
  if (target.type === 'account') {
53
- const quota = await this.quotaService.getAccountLimit(target.id);
53
+ const quota = await this.quotaService.getAccountQuota(target.id);
54
54
  this.writeJson(response, 200, {
55
55
  type: 'account',
56
56
  accountId: target.id,
57
- quotaLimit: quota ?? null,
57
+ quota,
58
58
  });
59
59
  return;
60
60
  }
@@ -62,13 +62,13 @@ class QuotaAdminHttpHandler extends community_server_1.HttpHandler {
62
62
  if (!podInfo) {
63
63
  throw new community_server_2.BadRequestHttpError('Unknown pod identifier.');
64
64
  }
65
- const quota = await this.quotaService.getPodLimit(target.id);
65
+ const quota = await this.quotaService.getPodQuota(target.id);
66
66
  this.writeJson(response, 200, {
67
67
  type: 'pod',
68
68
  podId: target.id,
69
69
  accountId: podInfo.accountId,
70
70
  baseUrl: podInfo.baseUrl ?? null,
71
- quotaLimit: quota ?? null,
71
+ quota,
72
72
  });
73
73
  }
74
74
  async handlePut(target, request, response) {
@@ -85,23 +85,23 @@ class QuotaAdminHttpHandler extends community_server_1.HttpHandler {
85
85
  }
86
86
  }
87
87
  if (target.type === 'account') {
88
- await this.quotaService.setAccountLimit(target.id, quota);
89
- const latest = await this.quotaService.getAccountLimit(target.id);
88
+ await this.quotaService.setAccountQuota(target.id, quota);
89
+ const latest = await this.quotaService.getAccountQuota(target.id);
90
90
  this.writeJson(response, 200, {
91
91
  status: 'updated',
92
92
  targetType: target.type,
93
93
  targetId: target.id,
94
- quotaLimit: latest ?? null,
94
+ quota: latest,
95
95
  });
96
96
  return;
97
97
  }
98
- await this.quotaService.setPodLimit(target.id, quota);
99
- const latest = await this.quotaService.getPodLimit(target.id);
98
+ await this.quotaService.setPodQuota(target.id, quota);
99
+ const latest = await this.quotaService.getPodQuota(target.id);
100
100
  this.writeJson(response, 200, {
101
101
  status: 'updated',
102
102
  targetType: target.type,
103
103
  targetId: target.id,
104
- quotaLimit: latest ?? null,
104
+ quota: latest,
105
105
  });
106
106
  }
107
107
  async handleDelete(target, response) {
@@ -112,10 +112,10 @@ class QuotaAdminHttpHandler extends community_server_1.HttpHandler {
112
112
  }
113
113
  }
114
114
  if (target.type === 'account') {
115
- await this.quotaService.setAccountLimit(target.id, null);
115
+ await this.quotaService.clearAccountQuota(target.id);
116
116
  }
117
117
  else {
118
- await this.quotaService.setPodLimit(target.id, null);
118
+ await this.quotaService.clearPodQuota(target.id);
119
119
  }
120
120
  this.writeJson(response, 200, {
121
121
  status: 'cleared',
@@ -175,17 +175,23 @@ class QuotaAdminHttpHandler extends community_server_1.HttpHandler {
175
175
  }
176
176
  }
177
177
  extractQuota(body) {
178
- if (!Object.prototype.hasOwnProperty.call(body, 'quotaLimit')) {
179
- throw new community_server_2.BadRequestHttpError('Body must include quotaLimit.');
180
- }
181
- const quotaValue = body.quotaLimit;
182
- if (quotaValue === null) {
183
- return null;
178
+ const quota = {};
179
+ let hasQuotaField = false;
180
+ for (const field of ['storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly']) {
181
+ if (!Object.prototype.hasOwnProperty.call(body, field)) {
182
+ continue;
183
+ }
184
+ const value = body[field];
185
+ if (value !== null && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {
186
+ throw new community_server_2.BadRequestHttpError(`${field} must be a non-negative number or null.`);
187
+ }
188
+ quota[field] = value;
189
+ hasQuotaField = true;
184
190
  }
185
- if (typeof quotaValue !== 'number' || !Number.isFinite(quotaValue) || quotaValue < 0) {
186
- throw new community_server_2.BadRequestHttpError('quotaLimit must be a non-negative number or null.');
191
+ if (!hasQuotaField) {
192
+ throw new community_server_2.BadRequestHttpError('Body must include at least one quota field.');
187
193
  }
188
- return quotaValue;
194
+ return quota;
189
195
  }
190
196
  writeOptions(response) {
191
197
  response.statusCode = 204;
@@ -1 +1 @@
1
- {"version":3,"file":"QuotaAdminHttpHandler.js","sourceRoot":"","sources":["../../../src/http/quota/QuotaAdminHttpHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSolidTokenVerifier } from '@solid/access-token-verifier';\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n \n BadRequestHttpError,\n ForbiddenHttpError,\n MethodNotAllowedHttpError,\n NotImplementedHttpError,\n UnauthorizedHttpError,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { AccountRepository } from '../../identity/drizzle/AccountRepository';\nimport { AccountRoleRepository } from '../../identity/drizzle/AccountRoleRepository';\nimport type { QuotaService } from '../../quota/QuotaService';\n\ninterface QuotaAdminHttpHandlerOptions {\n identityDbUrl: string;\n basePath?: string;\n roleRepository?: AccountRoleRepository;\n quotaService: QuotaService;\n}\n\ntype QuotaTarget =\n | { type: 'account'; id: string }\n | { type: 'pod'; id: string };\n\nexport class QuotaAdminHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n private readonly verify = createSolidTokenVerifier();\n private readonly accountRepo: AccountRepository;\n private readonly roleRepo: AccountRoleRepository;\n private readonly quotaService: QuotaService;\n private readonly basePath: string;\n\n public constructor(options: QuotaAdminHttpHandlerOptions) {\n super();\n const db = getIdentityDatabase(options.identityDbUrl);\n this.accountRepo = new AccountRepository(db);\n this.roleRepo = options.roleRepository ?? new AccountRoleRepository(db);\n this.basePath = options.basePath ?? '/api/quota/';\n this.quotaService = options.quotaService;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.getUrl(request).pathname;\n if (!path.startsWith(this.basePath)) {\n throw new NotImplementedHttpError('Not a quota admin request.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (![ 'GET', 'PUT', 'DELETE' ].includes(method)) {\n throw new MethodNotAllowedHttpError([ 'GET', 'PUT', 'DELETE', 'OPTIONS' ]);\n }\n\n await this.authenticateAdmin(request);\n\n const target = this.parseTarget(this.getUrl(request).pathname);\n\n switch (method) {\n case 'GET':\n await this.handleGet(target, response);\n break;\n case 'PUT':\n await this.handlePut(target, request, response);\n break;\n case 'DELETE':\n await this.handleDelete(target, response);\n break;\n }\n }\n\n private async handleGet(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'account') {\n const quota = await this.quotaService.getAccountLimit(target.id);\n this.writeJson(response, 200, {\n type: 'account',\n accountId: target.id,\n quotaLimit: quota ?? null,\n });\n return;\n }\n\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n const quota = await this.quotaService.getPodLimit(target.id);\n this.writeJson(response, 200, {\n type: 'pod',\n podId: target.id,\n accountId: podInfo.accountId,\n baseUrl: podInfo.baseUrl ?? null,\n quotaLimit: quota ?? null,\n });\n }\n\n private async handlePut(target: QuotaTarget, request: HttpRequest, response: HttpResponse): Promise<void> {\n const body = await this.readJson(request);\n if (body == null || typeof body !== 'object') {\n throw new BadRequestHttpError('Request body must be an object.');\n }\n const payload = body as Record<string, unknown>;\n const quota = this.extractQuota(payload);\n\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountLimit(target.id, quota);\n const latest = await this.quotaService.getAccountLimit(target.id);\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quotaLimit: latest ?? null,\n });\n return;\n }\n\n await this.quotaService.setPodLimit(target.id, quota);\n const latest = await this.quotaService.getPodLimit(target.id);\n\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quotaLimit: latest ?? null,\n });\n }\n\n private async handleDelete(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountLimit(target.id, null);\n } else {\n await this.quotaService.setPodLimit(target.id, null);\n }\n this.writeJson(response, 200, {\n status: 'cleared',\n targetType: target.type,\n targetId: target.id,\n });\n }\n\n private async authenticateAdmin(request: HttpRequest): Promise<void> {\n const authorization = request.headers.authorization;\n if (!authorization || !authorization.startsWith('Bearer ')) {\n throw new UnauthorizedHttpError('Quota管理接口需要携带 Bearer Token。');\n }\n let payload: Record<string, unknown>;\n try {\n payload = await this.verify(authorization) as unknown as Record<string, unknown>;\n } catch (error: unknown) {\n throw new UnauthorizedHttpError('无法验证访问令牌。', { cause: error });\n }\n const webId = this.extractWebId(payload);\n if (!webId) {\n throw new UnauthorizedHttpError('访问令牌缺少 webid。');\n }\n const context = await this.roleRepo.findByWebId(webId);\n if (!context || !context.roles.includes('admin')) {\n throw new ForbiddenHttpError('仅限管理员修改配额。');\n }\n }\n\n private parseTarget(pathname: string): QuotaTarget {\n const relative = pathname.slice(this.basePath.length);\n const segments = relative.split('/').filter(Boolean);\n if (segments.length !== 2) {\n throw new BadRequestHttpError('Quota path must match /accounts/{id} or /pods/{id}.');\n }\n const [ scope, identifier ] = segments;\n if (!identifier) {\n throw new BadRequestHttpError('Missing identifier.');\n }\n if (scope === 'accounts') {\n return { type: 'account', id: decodeURIComponent(identifier) };\n }\n if (scope === 'pods') {\n return { type: 'pod', id: decodeURIComponent(identifier) };\n }\n throw new BadRequestHttpError('Unknown quota scope.');\n }\n\n private async readJson(request: HttpRequest): Promise<unknown> {\n const body = await this.readBody(request);\n if (!body) {\n return undefined;\n }\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new BadRequestHttpError('Body must contain valid JSON.', { cause: error });\n }\n }\n\n private extractQuota(body: Record<string, unknown>): number | null {\n if (!Object.prototype.hasOwnProperty.call(body, 'quotaLimit')) {\n throw new BadRequestHttpError('Body must include quotaLimit.');\n }\n const quotaValue = body.quotaLimit as unknown;\n if (quotaValue === null) {\n return null;\n }\n if (typeof quotaValue !== 'number' || !Number.isFinite(quotaValue) || quotaValue < 0) {\n throw new BadRequestHttpError('quotaLimit must be a non-negative number or null.');\n }\n return quotaValue;\n }\n\n private writeOptions(response: HttpResponse): void {\n response.statusCode = 204;\n response.setHeader('Allow', 'GET,PUT,DELETE,OPTIONS');\n response.end();\n }\n\n private writeJson(response: HttpResponse, status: number, payload: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.setHeader('Cache-Control', 'no-store');\n response.end(JSON.stringify(payload));\n }\n\n private async readBody(request: HttpRequest): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => resolve(data));\n request.on('error', reject);\n });\n }\n\n private getUrl(request: HttpRequest): URL {\n const hostHeader = request.headers.host ?? request.headers.Host ?? 'localhost';\n const protoHeader = request.headers['x-forwarded-proto'] ?? request.headers['X-Forwarded-Proto'];\n const protocol = Array.isArray(protoHeader) ? protoHeader[0] : protoHeader;\n const scheme = typeof protocol === 'string' ? protocol.split(',')[0]?.trim() ?? 'http' : 'http';\n const rawUrl = request.url ?? '/';\n return new URL(rawUrl, `${scheme}://${hostHeader}`);\n }\n\n private extractWebId(payload: Record<string, unknown>): string | undefined {\n const getString = (key: string): string | undefined => {\n const value = payload[key];\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n };\n const direct = getString('webid') ?? getString('webId') ?? getString('sub');\n if (direct) {\n return direct;\n }\n const clientId = getString('client_id');\n if (clientId && clientId.startsWith('https://')) {\n return clientId;\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"QuotaAdminHttpHandler.js","sourceRoot":"","sources":["../../../src/http/quota/QuotaAdminHttpHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSolidTokenVerifier } from '@solid/access-token-verifier';\nimport { getLoggerFor } from 'global-logger-factory';\nimport { HttpHandler } from '@solid/community-server';\nimport type { HttpHandlerInput, HttpRequest, HttpResponse } from '@solid/community-server';\nimport {\n BadRequestHttpError,\n ForbiddenHttpError,\n MethodNotAllowedHttpError,\n NotImplementedHttpError,\n UnauthorizedHttpError,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { AccountRepository } from '../../identity/drizzle/AccountRepository';\nimport { AccountRoleRepository } from '../../identity/drizzle/AccountRoleRepository';\nimport type { AccountQuota, QuotaService } from '../../quota/QuotaService';\n\ninterface QuotaAdminHttpHandlerOptions {\n identityDbUrl: string;\n basePath?: string;\n roleRepository?: AccountRoleRepository;\n quotaService: QuotaService;\n}\n\ntype QuotaTarget =\n | { type: 'account'; id: string }\n | { type: 'pod'; id: string };\n\nexport class QuotaAdminHttpHandler extends HttpHandler {\n protected readonly logger = getLoggerFor(this);\n private readonly verify = createSolidTokenVerifier();\n private readonly accountRepo: AccountRepository;\n private readonly roleRepo: AccountRoleRepository;\n private readonly quotaService: QuotaService;\n private readonly basePath: string;\n\n public constructor(options: QuotaAdminHttpHandlerOptions) {\n super();\n const db = getIdentityDatabase(options.identityDbUrl);\n this.accountRepo = new AccountRepository(db);\n this.roleRepo = options.roleRepository ?? new AccountRoleRepository(db);\n this.basePath = options.basePath ?? '/api/quota/';\n this.quotaService = options.quotaService;\n }\n\n public override async canHandle({ request }: HttpHandlerInput): Promise<void> {\n const path = this.getUrl(request).pathname;\n if (!path.startsWith(this.basePath)) {\n throw new NotImplementedHttpError('Not a quota admin request.');\n }\n }\n\n public override async handle({ request, response }: HttpHandlerInput): Promise<void> {\n const method = (request.method ?? 'GET').toUpperCase();\n if (method === 'OPTIONS') {\n this.writeOptions(response);\n return;\n }\n\n if (![ 'GET', 'PUT', 'DELETE' ].includes(method)) {\n throw new MethodNotAllowedHttpError([ 'GET', 'PUT', 'DELETE', 'OPTIONS' ]);\n }\n\n await this.authenticateAdmin(request);\n\n const target = this.parseTarget(this.getUrl(request).pathname);\n\n switch (method) {\n case 'GET':\n await this.handleGet(target, response);\n break;\n case 'PUT':\n await this.handlePut(target, request, response);\n break;\n case 'DELETE':\n await this.handleDelete(target, response);\n break;\n }\n }\n\n private async handleGet(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'account') {\n const quota = await this.quotaService.getAccountQuota(target.id);\n this.writeJson(response, 200, {\n type: 'account',\n accountId: target.id,\n quota,\n });\n return;\n }\n\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n const quota = await this.quotaService.getPodQuota(target.id);\n this.writeJson(response, 200, {\n type: 'pod',\n podId: target.id,\n accountId: podInfo.accountId,\n baseUrl: podInfo.baseUrl ?? null,\n quota,\n });\n }\n\n private async handlePut(target: QuotaTarget, request: HttpRequest, response: HttpResponse): Promise<void> {\n const body = await this.readJson(request);\n if (body == null || typeof body !== 'object') {\n throw new BadRequestHttpError('Request body must be an object.');\n }\n const payload = body as Record<string, unknown>;\n const quota = this.extractQuota(payload);\n\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.setAccountQuota(target.id, quota);\n const latest = await this.quotaService.getAccountQuota(target.id);\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quota: latest,\n });\n return;\n }\n\n await this.quotaService.setPodQuota(target.id, quota);\n const latest = await this.quotaService.getPodQuota(target.id);\n\n this.writeJson(response, 200, {\n status: 'updated',\n targetType: target.type,\n targetId: target.id,\n quota: latest,\n });\n }\n\n private async handleDelete(target: QuotaTarget, response: HttpResponse): Promise<void> {\n if (target.type === 'pod') {\n const podInfo = await this.accountRepo.getPodInfo(target.id);\n if (!podInfo) {\n throw new BadRequestHttpError('Unknown pod identifier.');\n }\n }\n\n if (target.type === 'account') {\n await this.quotaService.clearAccountQuota(target.id);\n } else {\n await this.quotaService.clearPodQuota(target.id);\n }\n this.writeJson(response, 200, {\n status: 'cleared',\n targetType: target.type,\n targetId: target.id,\n });\n }\n\n private async authenticateAdmin(request: HttpRequest): Promise<void> {\n const authorization = request.headers.authorization;\n if (!authorization || !authorization.startsWith('Bearer ')) {\n throw new UnauthorizedHttpError('Quota管理接口需要携带 Bearer Token。');\n }\n let payload: Record<string, unknown>;\n try {\n payload = await this.verify(authorization) as unknown as Record<string, unknown>;\n } catch (error: unknown) {\n throw new UnauthorizedHttpError('无法验证访问令牌。', { cause: error });\n }\n const webId = this.extractWebId(payload);\n if (!webId) {\n throw new UnauthorizedHttpError('访问令牌缺少 webid。');\n }\n const context = await this.roleRepo.findByWebId(webId);\n if (!context || !context.roles.includes('admin')) {\n throw new ForbiddenHttpError('仅限管理员修改配额。');\n }\n }\n\n private parseTarget(pathname: string): QuotaTarget {\n const relative = pathname.slice(this.basePath.length);\n const segments = relative.split('/').filter(Boolean);\n if (segments.length !== 2) {\n throw new BadRequestHttpError('Quota path must match /accounts/{id} or /pods/{id}.');\n }\n const [ scope, identifier ] = segments;\n if (!identifier) {\n throw new BadRequestHttpError('Missing identifier.');\n }\n if (scope === 'accounts') {\n return { type: 'account', id: decodeURIComponent(identifier) };\n }\n if (scope === 'pods') {\n return { type: 'pod', id: decodeURIComponent(identifier) };\n }\n throw new BadRequestHttpError('Unknown quota scope.');\n }\n\n private async readJson(request: HttpRequest): Promise<unknown> {\n const body = await this.readBody(request);\n if (!body) {\n return undefined;\n }\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new BadRequestHttpError('Body must contain valid JSON.', { cause: error });\n }\n }\n\n private extractQuota(body: Record<string, unknown>): Partial<AccountQuota> {\n const quota: Partial<AccountQuota> = {};\n let hasQuotaField = false;\n for (const field of [ 'storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly' ] as const) {\n if (!Object.prototype.hasOwnProperty.call(body, field)) {\n continue;\n }\n const value = body[field];\n if (value !== null && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {\n throw new BadRequestHttpError(`${field} must be a non-negative number or null.`);\n }\n quota[field] = value;\n hasQuotaField = true;\n }\n if (!hasQuotaField) {\n throw new BadRequestHttpError('Body must include at least one quota field.');\n }\n return quota;\n }\n\n private writeOptions(response: HttpResponse): void {\n response.statusCode = 204;\n response.setHeader('Allow', 'GET,PUT,DELETE,OPTIONS');\n response.end();\n }\n\n private writeJson(response: HttpResponse, status: number, payload: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.setHeader('Cache-Control', 'no-store');\n response.end(JSON.stringify(payload));\n }\n\n private async readBody(request: HttpRequest): Promise<string> {\n return await new Promise<string>((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => resolve(data));\n request.on('error', reject);\n });\n }\n\n private getUrl(request: HttpRequest): URL {\n const hostHeader = request.headers.host ?? request.headers.Host ?? 'localhost';\n const protoHeader = request.headers['x-forwarded-proto'] ?? request.headers['X-Forwarded-Proto'];\n const protocol = Array.isArray(protoHeader) ? protoHeader[0] : protoHeader;\n const scheme = typeof protocol === 'string' ? protocol.split(',')[0]?.trim() ?? 'http' : 'http';\n const rawUrl = request.url ?? '/';\n return new URL(rawUrl, `${scheme}://${hostHeader}`);\n }\n\n private extractWebId(payload: Record<string, unknown>): string | undefined {\n const getString = (key: string): string | undefined => {\n const value = payload[key];\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n };\n const direct = getString('webid') ?? getString('webId') ?? getString('sub');\n if (direct) {\n return direct;\n }\n const clientId = getString('client_id');\n if (clientId && clientId.startsWith('https://')) {\n return clientId;\n }\n return undefined;\n }\n}\n"]}
@@ -1,31 +1,13 @@
1
- import { type IdentityDatabase } from './db';
2
- export interface PodQuotaContext {
3
- accountId: string;
4
- podId: string;
5
- baseUrl?: string;
6
- podQuota?: number;
7
- accountQuota?: number;
8
- }
1
+ import type { IdentityDatabase } from './db';
9
2
  /**
10
- * Repository for account and pod quota operations.
11
- *
12
- * Reads account/pod data from CSS's internal_kv table.
13
- * Quota limits are stored in identity_account_usage / identity_pod_usage tables.
3
+ * Reads account/pod ownership data from the CSS identity facts.
4
+ * Quota values live in identity_usage and are managed by UsageRepository.
14
5
  */
15
6
  export declare class AccountRepository {
16
- private readonly db;
17
- private readonly kvTableName;
18
- private readonly accountUsageTable;
19
- private readonly podUsageTable;
7
+ private readonly podLookupRepo;
20
8
  constructor(db: IdentityDatabase, kvTableName?: string);
21
- getAccountQuota(accountId: string): Promise<number | undefined>;
22
9
  getPodInfo(podId: string): Promise<{
23
10
  accountId: string;
24
- podQuota?: number;
25
11
  baseUrl?: string;
26
12
  } | undefined>;
27
- private getPodQuota;
28
- getQuotaContext(accountId: string, podId: string): Promise<PodQuotaContext | undefined>;
29
- setAccountQuota(accountId: string, quota?: number): Promise<void>;
30
- setPodQuota(podId: string, quota?: number): Promise<void>;
31
13
  }
@@ -1,130 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AccountRepository = void 0;
4
- const drizzle_orm_1 = require("drizzle-orm");
5
- const db_1 = require("./db");
4
+ const PodLookupRepository_1 = require("./PodLookupRepository");
6
5
  /**
7
- * Repository for account and pod quota operations.
8
- *
9
- * Reads account/pod data from CSS's internal_kv table.
10
- * Quota limits are stored in identity_account_usage / identity_pod_usage tables.
6
+ * Reads account/pod ownership data from the CSS identity facts.
7
+ * Quota values live in identity_usage and are managed by UsageRepository.
11
8
  */
12
9
  class AccountRepository {
13
10
  constructor(db, kvTableName) {
14
- this.db = db;
15
- this.kvTableName = kvTableName ?? 'internal_kv';
16
- this.accountUsageTable = 'identity_account_usage';
17
- this.podUsageTable = 'identity_pod_usage';
18
- }
19
- async getAccountQuota(accountId) {
20
- try {
21
- const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
22
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE account_id = ${accountId} LIMIT 1`);
23
- if (result.rows.length === 0) {
24
- return undefined;
25
- }
26
- const limit = result.rows[0].storage_limit_bytes;
27
- return limit != null ? limit : undefined;
28
- }
29
- catch {
30
- // Table might not exist
31
- return undefined;
32
- }
11
+ this.podLookupRepo = new PodLookupRepository_1.PodLookupRepository(db, kvTableName);
33
12
  }
34
13
  async getPodInfo(podId) {
35
- // Get pod info from CSS's internal_kv
36
- const kvTableId = drizzle_orm_1.sql.identifier([this.kvTableName]);
37
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
38
- SELECT key, value FROM ${kvTableId}
39
- WHERE key LIKE 'accounts/data/%'
40
- `);
41
- for (const row of result.rows) {
42
- try {
43
- const accountId = row.key.replace('accounts/data/', '');
44
- const data = typeof row.value === 'string' ? JSON.parse(row.value) : row.value;
45
- const podMap = data['**pod**'] || data.pod || {};
46
- if (podMap[podId]) {
47
- const pod = podMap[podId];
48
- const podQuota = await this.getPodQuota(podId);
49
- return {
50
- accountId,
51
- baseUrl: typeof pod.baseUrl === 'string' ? pod.baseUrl : undefined,
52
- podQuota,
53
- };
54
- }
55
- }
56
- catch {
57
- // Skip malformed entries
58
- }
59
- }
60
- return undefined;
61
- }
62
- async getPodQuota(podId) {
63
- try {
64
- const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
65
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE pod_id = ${podId} LIMIT 1`);
66
- if (result.rows.length === 0) {
67
- return undefined;
68
- }
69
- const limit = result.rows[0].storage_limit_bytes;
70
- return limit != null ? limit : undefined;
71
- }
72
- catch {
73
- // Table might not exist
74
- return undefined;
75
- }
76
- }
77
- async getQuotaContext(accountId, podId) {
78
- const podInfo = await this.getPodInfo(podId);
79
- if (!podInfo) {
80
- return undefined;
81
- }
82
- if (podInfo.accountId !== accountId) {
14
+ const pod = await this.podLookupRepo.findById(podId)
15
+ ?? await this.podLookupRepo.findByResourceIdentifier(podId);
16
+ if (!pod) {
83
17
  return undefined;
84
18
  }
85
- const accountQuota = await this.getAccountQuota(accountId);
86
19
  return {
87
- accountId,
88
- podId,
89
- baseUrl: podInfo.baseUrl,
90
- podQuota: podInfo.podQuota,
91
- accountQuota,
20
+ accountId: pod.accountId,
21
+ baseUrl: pod.baseUrl,
92
22
  };
93
23
  }
94
- async setAccountQuota(accountId, quota) {
95
- const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
96
- if ((0, db_1.isDatabaseSqlite)(this.db)) {
97
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
98
- INSERT INTO ${tableId} (account_id, storage_limit_bytes)
99
- VALUES (${accountId}, ${quota ?? null})
100
- ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
101
- `);
102
- }
103
- else {
104
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
105
- INSERT INTO ${tableId} (account_id, storage_limit_bytes)
106
- VALUES (${accountId}, ${quota ?? null})
107
- ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
108
- `);
109
- }
110
- }
111
- async setPodQuota(podId, quota) {
112
- const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
113
- if ((0, db_1.isDatabaseSqlite)(this.db)) {
114
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
115
- INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
116
- VALUES (${podId}, '', ${quota ?? null})
117
- ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
118
- `);
119
- }
120
- else {
121
- await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
122
- INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
123
- VALUES (${podId}, '', ${quota ?? null})
124
- ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
125
- `);
126
- }
127
- }
128
24
  }
129
25
  exports.AccountRepository = AccountRepository;
130
26
  //# sourceMappingURL=AccountRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from 'drizzle-orm';\nimport { type IdentityDatabase, executeQuery, isDatabaseSqlite } from './db';\n\nexport interface PodQuotaContext {\n accountId: string;\n podId: string;\n baseUrl?: string;\n podQuota?: number;\n accountQuota?: number;\n}\n\ninterface InternalKvRow {\n key: string;\n value: string;\n}\n\n/**\n * Repository for account and pod quota operations.\n *\n * Reads account/pod data from CSS's internal_kv table.\n * Quota limits are stored in identity_account_usage / identity_pod_usage tables.\n */\nexport class AccountRepository {\n private readonly kvTableName: string;\n private readonly accountUsageTable: string;\n private readonly podUsageTable: string;\n\n public constructor(\n private readonly db: IdentityDatabase,\n kvTableName?: string,\n ) {\n this.kvTableName = kvTableName ?? 'internal_kv';\n this.accountUsageTable = 'identity_account_usage';\n this.podUsageTable = 'identity_pod_usage';\n }\n\n public async getAccountQuota(accountId: string): Promise<number | undefined> {\n try {\n const tableId = sql.identifier([this.accountUsageTable]);\n const result = await executeQuery<{ storage_limit_bytes: number | null }>(\n this.db,\n sql`SELECT storage_limit_bytes FROM ${tableId} WHERE account_id = ${accountId} LIMIT 1`,\n );\n if (result.rows.length === 0) {\n return undefined;\n }\n const limit = result.rows[0].storage_limit_bytes;\n return limit != null ? limit : undefined;\n } catch {\n // Table might not exist\n return undefined;\n }\n }\n\n public async getPodInfo(podId: string): Promise<{ accountId: string; podQuota?: number; baseUrl?: string } | undefined> {\n // Get pod info from CSS's internal_kv\n const kvTableId = sql.identifier([this.kvTableName]);\n const result = await executeQuery<InternalKvRow>(this.db, sql`\n SELECT key, value FROM ${kvTableId}\n WHERE key LIKE 'accounts/data/%'\n `);\n\n for (const row of result.rows) {\n try {\n const accountId = row.key.replace('accounts/data/', '');\n const data = typeof row.value === 'string' ? JSON.parse(row.value) : row.value;\n const podMap = data['**pod**'] || data.pod || {};\n\n if (podMap[podId]) {\n const pod = podMap[podId] as Record<string, unknown>;\n const podQuota = await this.getPodQuota(podId);\n return {\n accountId,\n baseUrl: typeof pod.baseUrl === 'string' ? pod.baseUrl : undefined,\n podQuota,\n };\n }\n } catch {\n // Skip malformed entries\n }\n }\n\n return undefined;\n }\n\n private async getPodQuota(podId: string): Promise<number | undefined> {\n try {\n const tableId = sql.identifier([this.podUsageTable]);\n const result = await executeQuery<{ storage_limit_bytes: number | null }>(\n this.db,\n sql`SELECT storage_limit_bytes FROM ${tableId} WHERE pod_id = ${podId} LIMIT 1`,\n );\n if (result.rows.length === 0) {\n return undefined;\n }\n const limit = result.rows[0].storage_limit_bytes;\n return limit != null ? limit : undefined;\n } catch {\n // Table might not exist\n return undefined;\n }\n }\n\n public async getQuotaContext(accountId: string, podId: string): Promise<PodQuotaContext | undefined> {\n const podInfo = await this.getPodInfo(podId);\n if (!podInfo) {\n return undefined;\n }\n if (podInfo.accountId !== accountId) {\n return undefined;\n }\n const accountQuota = await this.getAccountQuota(accountId);\n return {\n accountId,\n podId,\n baseUrl: podInfo.baseUrl,\n podQuota: podInfo.podQuota,\n accountQuota,\n };\n }\n\n public async setAccountQuota(accountId: string, quota?: number): Promise<void> {\n const tableId = sql.identifier([this.accountUsageTable]);\n if (isDatabaseSqlite(this.db)) {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (account_id, storage_limit_bytes)\n VALUES (${accountId}, ${quota ?? null})\n ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}\n `);\n } else {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (account_id, storage_limit_bytes)\n VALUES (${accountId}, ${quota ?? null})\n ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes\n `);\n }\n }\n\n public async setPodQuota(podId: string, quota?: number): Promise<void> {\n const tableId = sql.identifier([this.podUsageTable]);\n if (isDatabaseSqlite(this.db)) {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)\n VALUES (${podId}, '', ${quota ?? null})\n ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}\n `);\n } else {\n await executeQuery(this.db, sql`\n INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)\n VALUES (${podId}, '', ${quota ?? null})\n ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes\n `);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":";;;AACA,+DAA4D;AAE5D;;;GAGG;AACH,MAAa,iBAAiB;IAG5B,YACE,EAAoB,EACpB,WAAoB;QAEpB,IAAI,CAAC,aAAa,GAAG,IAAI,yCAAmB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,KAAa;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;eAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC;IACJ,CAAC;CACF;AArBD,8CAqBC","sourcesContent":["import type { IdentityDatabase } from './db';\nimport { PodLookupRepository } from './PodLookupRepository';\n\n/**\n * Reads account/pod ownership data from the CSS identity facts.\n * Quota values live in identity_usage and are managed by UsageRepository.\n */\nexport class AccountRepository {\n private readonly podLookupRepo: PodLookupRepository;\n\n public constructor(\n db: IdentityDatabase,\n kvTableName?: string,\n ) {\n this.podLookupRepo = new PodLookupRepository(db, kvTableName);\n }\n\n public async getPodInfo(podId: string): Promise<{ accountId: string; baseUrl?: string } | undefined> {\n const pod = await this.podLookupRepo.findById(podId)\n ?? await this.podLookupRepo.findByResourceIdentifier(podId);\n if (!pod) {\n return undefined;\n }\n return {\n accountId: pod.accountId,\n baseUrl: pod.baseUrl,\n };\n }\n}\n"]}
@@ -6,18 +6,18 @@ export interface AccountRoleContext {
6
6
  }
7
7
  export declare class AccountRoleRepository {
8
8
  private readonly db;
9
- private readonly ready;
10
9
  private readonly logger;
11
10
  constructor(db: IdentityDatabase);
12
11
  findByAccountId(accountId: string): Promise<AccountRoleContext | undefined>;
13
12
  findByWebId(webId: string): Promise<AccountRoleContext | undefined>;
14
13
  findByWebIdLoose(webId: string): Promise<AccountRoleContext | undefined>;
15
14
  addRoles(accountId: string, roles: string[]): Promise<void>;
16
- private ensureSchema;
17
- private fetchRoles;
18
- private getAccountPayloadById;
15
+ private getAccountById;
19
16
  private loadAllAccounts;
17
+ private loadIdentityStoreAccounts;
18
+ private loadInternalKvAccounts;
20
19
  private loadFileAccountMap;
20
+ private updateAccountRecord;
21
+ private toJsonSql;
21
22
  private isTableMissing;
22
- private isDuplicateDefinitionError;
23
23
  }