@undefineds.co/xpod 0.3.31 → 0.3.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/dist/api/auth/AuthContext.d.ts +3 -2
  2. package/dist/api/auth/AuthContext.js +2 -1
  3. package/dist/api/auth/AuthContext.js.map +1 -1
  4. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
  5. package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
  6. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  7. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
  8. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
  9. package/dist/api/chatkit/pod-store.d.ts +3 -0
  10. package/dist/api/chatkit/pod-store.js +93 -59
  11. package/dist/api/chatkit/pod-store.js.map +1 -1
  12. package/dist/api/chatkit/schema.d.ts +5 -6
  13. package/dist/api/container/business-token.d.ts +1 -1
  14. package/dist/api/container/business-token.js +5 -1
  15. package/dist/api/container/business-token.js.map +1 -1
  16. package/dist/api/container/common.js +14 -10
  17. package/dist/api/container/common.js.map +1 -1
  18. package/dist/api/container/routes.js +16 -3
  19. package/dist/api/container/routes.js.map +1 -1
  20. package/dist/api/container/types.d.ts +2 -4
  21. package/dist/api/container/types.js.map +1 -1
  22. package/dist/api/handlers/ChatHandler.d.ts +1 -1
  23. package/dist/api/handlers/ChatHandler.js +1 -1
  24. package/dist/api/handlers/ChatHandler.js.map +1 -1
  25. package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
  26. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  27. package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
  28. package/dist/api/handlers/PodManagementHandler.js +114 -12
  29. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  30. package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
  31. package/dist/api/handlers/ProvisionHandler.js +339 -32
  32. package/dist/api/handlers/ProvisionHandler.js.map +1 -1
  33. package/dist/api/handlers/QuotaHandler.js +0 -12
  34. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  35. package/dist/api/handlers/index.d.ts +0 -1
  36. package/dist/api/handlers/index.js +0 -1
  37. package/dist/api/handlers/index.js.map +1 -1
  38. package/dist/api/matrix/PodMatrixStore.js +26 -21
  39. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  40. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  41. package/dist/api/runs/schema.d.ts +5 -7
  42. package/dist/api/runs/store.js +6 -4
  43. package/dist/api/runs/store.js.map +1 -1
  44. package/dist/api/runtime.js +3 -3
  45. package/dist/api/runtime.js.map +1 -1
  46. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  47. package/dist/api/tasks/schema.d.ts +17 -13
  48. package/dist/api/tasks/schema.js +7 -2
  49. package/dist/api/tasks/schema.js.map +1 -1
  50. package/dist/api/tasks/store.js +1 -2
  51. package/dist/api/tasks/store.js.map +1 -1
  52. package/dist/components/context.jsonld +12 -0
  53. package/dist/edge/EdgeNodeAgent.d.ts +1 -1
  54. package/dist/edge/EdgeNodeAgent.js +1 -1
  55. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  56. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
  57. package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
  58. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  59. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
  60. package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
  61. package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
  62. package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
  63. package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
  64. package/dist/http/ClusterIngressRouter.js +6 -3
  65. package/dist/http/ClusterIngressRouter.js.map +1 -1
  66. package/dist/http/ClusterWebSocketConfigurator.js +6 -2
  67. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  68. package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
  69. package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
  70. package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
  71. package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
  72. package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
  73. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  74. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
  75. package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
  76. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  77. package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
  78. package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
  79. package/dist/http/search/SearchHttpHandler.js +2 -2
  80. package/dist/http/search/SearchHttpHandler.js.map +1 -1
  81. package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
  82. package/dist/identity/drizzle/AccountRepository.js +9 -113
  83. package/dist/identity/drizzle/AccountRepository.js.map +1 -1
  84. package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
  85. package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
  86. package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
  87. package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
  88. package/dist/identity/drizzle/DdnsRepository.js +13 -49
  89. package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
  90. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
  91. package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
  92. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  93. package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
  94. package/dist/identity/drizzle/PodLookupRepository.js +103 -126
  95. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  96. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
  97. package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
  98. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
  99. package/dist/identity/drizzle/db.d.ts +2 -1
  100. package/dist/identity/drizzle/db.js +173 -297
  101. package/dist/identity/drizzle/db.js.map +1 -1
  102. package/dist/identity/drizzle/schema.pg.d.ts +3 -11
  103. package/dist/identity/drizzle/schema.pg.js +10 -45
  104. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  105. package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
  106. package/dist/identity/drizzle/schema.sqlite.js +13 -46
  107. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  108. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
  109. package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
  110. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
  111. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
  112. package/dist/provision/ProvisionCodeCodec.js +10 -1
  113. package/dist/provision/ProvisionCodeCodec.js.map +1 -1
  114. package/dist/provision/ProvisionPodCreator.d.ts +8 -2
  115. package/dist/provision/ProvisionPodCreator.js +134 -41
  116. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  117. package/dist/provision/ProvisionPodCreator.jsonld +38 -3
  118. package/dist/quota/DrizzleQuotaService.d.ts +0 -4
  119. package/dist/quota/DrizzleQuotaService.js +1 -21
  120. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  121. package/dist/quota/DrizzleQuotaService.jsonld +0 -16
  122. package/dist/quota/NoopQuotaService.d.ts +0 -4
  123. package/dist/quota/NoopQuotaService.js +0 -8
  124. package/dist/quota/NoopQuotaService.js.map +1 -1
  125. package/dist/quota/NoopQuotaService.jsonld +0 -16
  126. package/dist/quota/QuotaService.d.ts +0 -4
  127. package/dist/quota/QuotaService.js.map +1 -1
  128. package/dist/quota/QuotaService.jsonld +0 -16
  129. package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
  130. package/dist/service/EdgeNodeSignalClient.js +0 -4
  131. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  132. package/dist/service/PodMigrationService.d.ts +2 -2
  133. package/dist/service/PodMigrationService.js +4 -4
  134. package/dist/service/PodMigrationService.js.map +1 -1
  135. package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
  136. package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
  137. package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
  138. package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
  139. package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
  140. package/dist/storage/quota/UsageRepository.d.ts +10 -32
  141. package/dist/storage/quota/UsageRepository.js +84 -281
  142. package/dist/storage/quota/UsageRepository.js.map +1 -1
  143. package/dist/storage/vector/VectorIndexingListener.js +2 -2
  144. package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
  145. package/dist/subdomain/SubdomainService.d.ts +1 -1
  146. package/dist/subdomain/SubdomainService.js +1 -1
  147. package/dist/subdomain/SubdomainService.js.map +1 -1
  148. package/dist/subdomain/SubdomainService.jsonld +1 -1
  149. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts +21 -0
  150. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts.map +1 -0
  151. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js +85 -0
  152. package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js.map +1 -0
  153. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts +10 -0
  154. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts.map +1 -0
  155. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js +365 -0
  156. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js.map +1 -0
  157. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts +1 -0
  158. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts.map +1 -1
  159. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js +3 -1
  160. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js.map +1 -1
  161. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
  162. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js +5 -1
  163. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js.map +1 -1
  164. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts +2 -0
  165. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts.map +1 -1
  166. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js +2 -1
  167. package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js.map +1 -1
  168. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts +18 -0
  169. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts.map +1 -1
  170. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js +234 -10
  171. package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js.map +1 -1
  172. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts +13 -0
  173. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts.map +1 -1
  174. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js +19 -0
  175. package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js.map +1 -1
  176. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts +21 -0
  177. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts.map +1 -0
  178. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js +78 -0
  179. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js.map +1 -0
  180. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts +10 -0
  181. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts.map +1 -0
  182. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js +362 -0
  183. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js.map +1 -0
  184. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts +1 -0
  185. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts.map +1 -1
  186. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js +1 -0
  187. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js.map +1 -1
  188. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
  189. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js +5 -1
  190. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
  191. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts +2 -0
  192. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts.map +1 -1
  193. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js +1 -0
  194. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js.map +1 -1
  195. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts +18 -0
  196. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts.map +1 -1
  197. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js +225 -10
  198. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js.map +1 -1
  199. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts +13 -0
  200. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts.map +1 -1
  201. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js +19 -0
  202. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js.map +1 -1
  203. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts +5 -4
  204. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts.map +1 -1
  205. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js +4 -3
  206. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js.map +1 -1
  207. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts +5 -4
  208. package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts.map +1 -1
  209. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js +20 -3
  210. package/node_modules/@undefineds.co/drizzle-solid/dist/index.js.map +1 -1
  211. package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
  212. package/package.json +3 -3
  213. package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
  214. package/dist/api/handlers/ApiKeyHandler.js +0 -153
  215. package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
  216. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
  217. package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
  218. package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
@@ -10,6 +10,8 @@ const drizzle_orm_1 = require("drizzle-orm");
10
10
  const global_logger_factory_1 = require("global-logger-factory");
11
11
  const db_1 = require("./db");
12
12
  const ACCOUNT_DATA_DIR = node_path_1.default.resolve('.internal', 'accounts', 'data');
13
+ const IDENTITY_STORE_TABLE = 'identity_store';
14
+ const INTERNAL_KV_TABLE = 'internal_kv';
13
15
  function resolveWebIds(payload) {
14
16
  const candidates = new Set();
15
17
  const possibleKeys = ['webId', 'webid', 'primaryWebId', 'primary_webid'];
@@ -38,39 +40,87 @@ function resolveWebIds(payload) {
38
40
  }
39
41
  }
40
42
  }
41
- return [...candidates];
43
+ const webIdLink = payload['**webIdLink**'] ?? payload.webIdLink;
44
+ if (webIdLink && typeof webIdLink === 'object') {
45
+ for (const entry of Object.values(webIdLink)) {
46
+ if (!entry || typeof entry !== 'object') {
47
+ continue;
48
+ }
49
+ const webId = entry.webId;
50
+ if (typeof webId === 'string' && webId.trim().length > 0) {
51
+ candidates.add(webId.trim());
52
+ }
53
+ }
54
+ }
55
+ const podMap = payload['**pod**'] ?? payload.pod;
56
+ if (podMap && typeof podMap === 'object') {
57
+ for (const pod of Object.values(podMap)) {
58
+ if (!pod || typeof pod !== 'object') {
59
+ continue;
60
+ }
61
+ const owner = pod['**owner**'] ?? pod.owner;
62
+ if (!owner || typeof owner !== 'object') {
63
+ continue;
64
+ }
65
+ for (const entry of Object.values(owner)) {
66
+ if (!entry || typeof entry !== 'object') {
67
+ continue;
68
+ }
69
+ const webId = entry.webId;
70
+ if (typeof webId === 'string' && webId.trim().length > 0) {
71
+ candidates.add(webId.trim());
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return Array.from(candidates);
77
+ }
78
+ function resolveRoles(payload) {
79
+ const roles = payload.roles;
80
+ if (!Array.isArray(roles)) {
81
+ return [];
82
+ }
83
+ return Array.from(new Set(roles
84
+ .map((role) => typeof role === 'string' ? role.trim() : '')
85
+ .filter((role) => role.length > 0)));
86
+ }
87
+ function parsePayload(value) {
88
+ if (!value) {
89
+ return undefined;
90
+ }
91
+ if (typeof value === 'string') {
92
+ try {
93
+ const parsed = JSON.parse(value);
94
+ return parsed && typeof parsed === 'object' ? parsed : undefined;
95
+ }
96
+ catch {
97
+ return undefined;
98
+ }
99
+ }
100
+ return typeof value === 'object' ? value : undefined;
42
101
  }
43
102
  class AccountRoleRepository {
44
103
  constructor(db) {
45
104
  this.db = db;
46
105
  this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
47
- this.ready = this.ensureSchema();
48
106
  }
49
107
  async findByAccountId(accountId) {
50
- await this.ready;
51
- const payload = await this.getAccountPayloadById(accountId);
52
- if (!payload) {
53
- const rolesFallback = await this.fetchRoles(accountId);
54
- if (rolesFallback.length === 0) {
55
- return undefined;
56
- }
57
- return { accountId, roles: rolesFallback };
108
+ const record = await this.getAccountById(accountId);
109
+ if (!record) {
110
+ return undefined;
58
111
  }
59
- const [webId] = resolveWebIds(payload);
60
- const roles = await this.fetchRoles(accountId);
61
- return { accountId, webId, roles };
112
+ const [webId] = resolveWebIds(record.payload);
113
+ return { accountId, webId, roles: resolveRoles(record.payload) };
62
114
  }
63
115
  async findByWebId(webId) {
64
- await this.ready;
65
116
  const accounts = await this.loadAllAccounts();
66
- for (const { id, payload } of accounts) {
117
+ for (const { id, payload } of accounts.values()) {
67
118
  const knownWebIds = resolveWebIds(payload);
68
119
  if (knownWebIds.includes(webId)) {
69
- const roles = await this.fetchRoles(id);
70
120
  return {
71
121
  accountId: id,
72
122
  webId,
73
- roles,
123
+ roles: resolveRoles(payload),
74
124
  };
75
125
  }
76
126
  }
@@ -80,100 +130,131 @@ class AccountRoleRepository {
80
130
  return this.findByWebId(webId);
81
131
  }
82
132
  async addRoles(accountId, roles) {
83
- await this.ready;
84
133
  const unique = Array.from(new Set(roles.map((role) => role.trim()).filter((role) => role.length > 0)));
85
134
  if (unique.length === 0) {
86
135
  return;
87
136
  }
88
- for (const role of unique) {
89
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
90
- INSERT INTO identity_account_role (account_id, role)
91
- VALUES (${accountId}, ${role})
92
- ON CONFLICT (account_id, role) DO NOTHING
93
- `);
137
+ const record = await this.getAccountById(accountId);
138
+ if (!record) {
139
+ this.logger.warn(`Cannot add roles for unknown account ${accountId}`);
140
+ return;
94
141
  }
142
+ const nextRoles = Array.from(new Set([...resolveRoles(record.payload), ...unique]));
143
+ await this.updateAccountRecord(record, { ...record.payload, roles: nextRoles });
95
144
  }
96
- async ensureSchema() {
97
- try {
98
- if ((0, db_1.isDatabaseSqlite)(this.db)) {
99
- // SQLite syntax
100
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
101
- CREATE TABLE IF NOT EXISTS identity_account_role (
102
- account_id TEXT NOT NULL,
103
- role TEXT NOT NULL,
104
- created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
105
- PRIMARY KEY (account_id, role)
106
- )
107
- `);
108
- }
109
- else {
110
- // PostgreSQL syntax
111
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
112
- CREATE TABLE IF NOT EXISTS identity_account_role (
113
- account_id TEXT NOT NULL,
114
- role TEXT NOT NULL,
115
- created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
116
- PRIMARY KEY (account_id, role)
117
- )
118
- `);
119
- }
120
- }
121
- catch (error) {
122
- if (!this.isDuplicateDefinitionError(error)) {
123
- throw error;
145
+ async getAccountById(accountId) {
146
+ const accounts = await this.loadAllAccounts();
147
+ return accounts.get(accountId);
148
+ }
149
+ async loadAllAccounts() {
150
+ const accounts = new Map();
151
+ await this.loadIdentityStoreAccounts(accounts);
152
+ await this.loadInternalKvAccounts(accounts);
153
+ for (const [id, payload] of await this.loadFileAccountMap()) {
154
+ if (!accounts.has(id)) {
155
+ accounts.set(id, { id, payload, source: 'file' });
124
156
  }
125
- this.logger.debug('identity_account_role schema already present, skipping creation.');
126
157
  }
158
+ return accounts;
127
159
  }
128
- async fetchRoles(accountId) {
129
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
130
- SELECT role
131
- FROM identity_account_role
132
- WHERE account_id = ${accountId}
133
- `);
134
- return result.rows.map((row) => {
135
- const value = typeof row.role === 'string' ? row.role.trim() : '';
136
- return value;
137
- }).filter((value) => value.length > 0);
138
- }
139
- async getAccountPayloadById(accountId) {
160
+ async loadIdentityStoreAccounts(accounts) {
161
+ const tableId = drizzle_orm_1.sql.identifier([IDENTITY_STORE_TABLE]);
162
+ let rows = [];
140
163
  try {
141
- const accountResult = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
142
- SELECT payload
143
- FROM identity_account
144
- WHERE id = ${accountId}
145
- LIMIT 1
164
+ const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
165
+ SELECT container, id, payload
166
+ FROM ${tableId}
167
+ WHERE container IN ('account', 'pod', 'owner', 'webIdLink')
146
168
  `);
147
- if (accountResult.rows.length > 0) {
148
- const payload = accountResult.rows[0]?.payload;
149
- if (payload && typeof payload === 'object') {
150
- return payload;
151
- }
152
- }
169
+ rows = result.rows;
153
170
  }
154
171
  catch (error) {
155
172
  if (!this.isTableMissing(error)) {
156
173
  throw error;
157
174
  }
175
+ return;
176
+ }
177
+ const podAccountIds = new Map();
178
+ const webIdsByAccount = new Map();
179
+ for (const row of rows) {
180
+ if (!row.id || !row.container) {
181
+ continue;
182
+ }
183
+ const payload = parsePayload(row.payload);
184
+ if (!payload) {
185
+ continue;
186
+ }
187
+ if (row.container === 'account') {
188
+ accounts.set(row.id, { id: row.id, payload, source: 'identity-store' });
189
+ }
190
+ else if (row.container === 'pod') {
191
+ const accountId = typeof payload.accountId === 'string' ? payload.accountId : undefined;
192
+ if (accountId) {
193
+ podAccountIds.set(row.id, accountId);
194
+ }
195
+ }
196
+ }
197
+ for (const row of rows) {
198
+ const payload = parsePayload(row.payload);
199
+ if (!row.container || !payload) {
200
+ continue;
201
+ }
202
+ if (row.container === 'webIdLink') {
203
+ const accountId = typeof payload.accountId === 'string' ? payload.accountId : undefined;
204
+ const webId = typeof payload.webId === 'string' ? payload.webId : undefined;
205
+ if (accountId && webId) {
206
+ appendWebId(webIdsByAccount, accountId, webId);
207
+ }
208
+ }
209
+ else if (row.container === 'owner') {
210
+ const podId = typeof payload.podId === 'string' ? payload.podId : undefined;
211
+ const webId = typeof payload.webId === 'string' ? payload.webId : undefined;
212
+ const accountId = podId ? podAccountIds.get(podId) : undefined;
213
+ if (accountId && webId) {
214
+ appendWebId(webIdsByAccount, accountId, webId);
215
+ }
216
+ }
217
+ }
218
+ for (const [accountId, webIds] of webIdsByAccount) {
219
+ const record = accounts.get(accountId);
220
+ if (!record) {
221
+ continue;
222
+ }
223
+ record.payload = {
224
+ ...record.payload,
225
+ webIdLink: Object.fromEntries(Array.from(webIds).map((webId, index) => [
226
+ `webid-${index}`,
227
+ { accountId, webId },
228
+ ])),
229
+ };
158
230
  }
159
- const files = await this.loadFileAccountMap();
160
- return files.get(accountId);
161
231
  }
162
- async loadAllAccounts() {
232
+ async loadInternalKvAccounts(accounts) {
233
+ const tableId = drizzle_orm_1.sql.identifier([INTERNAL_KV_TABLE]);
163
234
  try {
164
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT id, payload FROM identity_account`);
165
- return result.rows.map((row) => ({
166
- id: row.id,
167
- payload: (row.payload ?? {}),
168
- }));
235
+ const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
236
+ SELECT key, value
237
+ FROM ${tableId}
238
+ WHERE key LIKE 'accounts/data/%'
239
+ OR key LIKE '/.internal/accounts/data/%'
240
+ `);
241
+ for (const row of result.rows) {
242
+ if (!row.key) {
243
+ continue;
244
+ }
245
+ const accountId = extractAccountIdFromKey(row.key);
246
+ const payload = parsePayload(row.value);
247
+ if (!accountId || !payload || accounts.has(accountId)) {
248
+ continue;
249
+ }
250
+ accounts.set(accountId, { id: accountId, payload, source: 'internal-kv', key: row.key });
251
+ }
169
252
  }
170
253
  catch (error) {
171
254
  if (!this.isTableMissing(error)) {
172
255
  throw error;
173
256
  }
174
257
  }
175
- const files = await this.loadFileAccountMap();
176
- return Array.from(files.entries()).map(([id, payload]) => ({ id, payload }));
177
258
  }
178
259
  async loadFileAccountMap() {
179
260
  const map = new Map();
@@ -206,28 +287,54 @@ class AccountRoleRepository {
206
287
  }
207
288
  return map;
208
289
  }
209
- isTableMissing(error) {
210
- if (!error || typeof error !== 'object') {
211
- return false;
290
+ async updateAccountRecord(record, payload) {
291
+ if (record.source === 'identity-store') {
292
+ const tableId = drizzle_orm_1.sql.identifier([IDENTITY_STORE_TABLE]);
293
+ await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
294
+ UPDATE ${tableId}
295
+ SET payload = ${this.toJsonSql(payload)}
296
+ WHERE container = 'account' AND id = ${record.id}
297
+ `);
298
+ return;
212
299
  }
213
- const code = error.code;
214
- if (code === '42P01') {
215
- return true;
300
+ if (record.source === 'internal-kv' && record.key) {
301
+ const tableId = drizzle_orm_1.sql.identifier([INTERNAL_KV_TABLE]);
302
+ await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
303
+ UPDATE ${tableId}
304
+ SET value = ${JSON.stringify(payload)}
305
+ WHERE key = ${record.key}
306
+ `);
216
307
  }
217
- const message = error.message ?? '';
218
- return /does not exist/u.test(message);
219
308
  }
220
- isDuplicateDefinitionError(error) {
309
+ toJsonSql(payload) {
310
+ const serialized = JSON.stringify(payload);
311
+ return (0, db_1.isDatabaseSqlite)(this.db) ? (0, drizzle_orm_1.sql) `${serialized}` : (0, drizzle_orm_1.sql) `${serialized}::jsonb`;
312
+ }
313
+ isTableMissing(error) {
221
314
  if (!error || typeof error !== 'object') {
222
315
  return false;
223
316
  }
224
317
  const code = error.code;
225
- if (code && ['23505', '42P07', '42710'].includes(code)) {
318
+ if (code === '42P01') {
226
319
  return true;
227
320
  }
228
321
  const message = error.message ?? '';
229
- return /already exists/u.test(message);
322
+ return /does not exist|no such table/u.test(message);
230
323
  }
231
324
  }
232
325
  exports.AccountRoleRepository = AccountRoleRepository;
326
+ function appendWebId(target, accountId, webId) {
327
+ const values = target.get(accountId) ?? new Set();
328
+ values.add(webId);
329
+ target.set(accountId, values);
330
+ }
331
+ function extractAccountIdFromKey(key) {
332
+ const marker = 'accounts/data/';
333
+ const index = key.indexOf(marker);
334
+ if (index < 0) {
335
+ return undefined;
336
+ }
337
+ const accountId = key.slice(index + marker.length).replace(/\.json$/u, '');
338
+ return accountId || undefined;
339
+ }
233
340
  //# sourceMappingURL=AccountRoleRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountRoleRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRoleRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { sql } from 'drizzle-orm';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { IdentityDatabase } from './db';\nimport { executeQuery, executeStatement, isDatabaseSqlite } from './db';\n\nconst ACCOUNT_DATA_DIR = path.resolve('.internal', 'accounts', 'data');\n\nexport interface AccountRoleContext {\n accountId: string;\n webId?: string;\n roles: string[];\n}\n\nfunction resolveWebIds(payload: Record<string, unknown>): string[] {\n const candidates = new Set<string>();\n const possibleKeys = [ 'webId', 'webid', 'primaryWebId', 'primary_webid' ];\n for (const key of possibleKeys) {\n const value = payload[key];\n if (typeof value === 'string' && value.trim().length > 0) {\n candidates.add(value.trim());\n }\n }\n const settings = payload.settings;\n if (settings && typeof settings === 'object') {\n const webId = (settings as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n const pods = payload.pods;\n if (Array.isArray(pods)) {\n for (const entry of pods) {\n if (!entry || typeof entry !== 'object') {\n continue;\n }\n const webId = (entry as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n }\n return [ ...candidates ];\n}\n\nexport class AccountRoleRepository {\n private readonly ready: Promise<void>;\n private readonly logger = getLoggerFor(this);\n\n public constructor(private readonly db: IdentityDatabase) {\n this.ready = this.ensureSchema();\n }\n\n public async findByAccountId(accountId: string): Promise<AccountRoleContext | undefined> {\n await this.ready;\n const payload = await this.getAccountPayloadById(accountId);\n if (!payload) {\n const rolesFallback = await this.fetchRoles(accountId);\n if (rolesFallback.length === 0) {\n return undefined;\n }\n return { accountId, roles: rolesFallback };\n }\n const [ webId ] = resolveWebIds(payload);\n const roles = await this.fetchRoles(accountId);\n return { accountId, webId, roles };\n }\n\n public async findByWebId(webId: string): Promise<AccountRoleContext | undefined> {\n await this.ready;\n const accounts = await this.loadAllAccounts();\n for (const { id, payload } of accounts) {\n const knownWebIds = resolveWebIds(payload);\n if (knownWebIds.includes(webId)) {\n const roles = await this.fetchRoles(id);\n return {\n accountId: id,\n webId,\n roles,\n };\n }\n }\n return undefined;\n }\n\n public async findByWebIdLoose(webId: string): Promise<AccountRoleContext | undefined> {\n return this.findByWebId(webId);\n }\n\n public async addRoles(accountId: string, roles: string[]): Promise<void> {\n await this.ready;\n const unique = Array.from(new Set(\n roles.map((role) => role.trim()).filter((role) => role.length > 0),\n ));\n if (unique.length === 0) {\n return;\n }\n for (const role of unique) {\n await executeStatement(this.db, sql`\n INSERT INTO identity_account_role (account_id, role)\n VALUES (${accountId}, ${role})\n ON CONFLICT (account_id, role) DO NOTHING\n `);\n }\n }\n\n private async ensureSchema(): Promise<void> {\n try {\n if (isDatabaseSqlite(this.db)) {\n // SQLite syntax\n await executeStatement(this.db, sql`\n CREATE TABLE IF NOT EXISTS identity_account_role (\n account_id TEXT NOT NULL,\n role TEXT NOT NULL,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n PRIMARY KEY (account_id, role)\n )\n `);\n } else {\n // PostgreSQL syntax\n await executeStatement(this.db, sql`\n CREATE TABLE IF NOT EXISTS identity_account_role (\n account_id TEXT NOT NULL,\n role TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (account_id, role)\n )\n `);\n }\n } catch (error: unknown) {\n if (!this.isDuplicateDefinitionError(error)) {\n throw error;\n }\n this.logger.debug('identity_account_role schema already present, skipping creation.');\n }\n }\n\n private async fetchRoles(accountId: string): Promise<string[]> {\n const result = await executeQuery<{ role?: unknown }>(this.db, sql`\n SELECT role\n FROM identity_account_role\n WHERE account_id = ${accountId}\n `);\n return result.rows.map((row) => {\n const value = typeof row.role === 'string' ? row.role.trim() : '';\n return value;\n }).filter((value) => value.length > 0);\n }\n\n private async getAccountPayloadById(accountId: string): Promise<Record<string, unknown> | undefined> {\n try {\n const accountResult = await executeQuery<{ payload?: unknown }>(this.db, sql`\n SELECT payload\n FROM identity_account\n WHERE id = ${accountId}\n LIMIT 1\n `);\n if (accountResult.rows.length > 0) {\n const payload = accountResult.rows[0]?.payload;\n if (payload && typeof payload === 'object') {\n return payload as Record<string, unknown>;\n }\n }\n } catch (error: unknown) {\n if (!this.isTableMissing(error)) {\n throw error;\n }\n }\n const files = await this.loadFileAccountMap();\n return files.get(accountId);\n }\n\n private async loadAllAccounts(): Promise<Array<{ id: string; payload: Record<string, unknown> }>> {\n try {\n const result = await executeQuery<{ id: string; payload: unknown }>(this.db, sql`SELECT id, payload FROM identity_account`);\n return result.rows.map((row) => ({\n id: row.id,\n payload: (row.payload ?? {}) as Record<string, unknown>,\n }));\n } catch (error: unknown) {\n if (!this.isTableMissing(error)) {\n throw error;\n }\n }\n const files = await this.loadFileAccountMap();\n return Array.from(files.entries()).map(([ id, payload ]) => ({ id, payload }));\n }\n\n private async loadFileAccountMap(): Promise<Map<string, Record<string, unknown>>> {\n const map = new Map<string, Record<string, unknown>>();\n try {\n const files = await fs.readdir(ACCOUNT_DATA_DIR);\n for (const file of files) {\n if (!file.endsWith('.json')) {\n continue;\n }\n const fullPath = path.join(ACCOUNT_DATA_DIR, file);\n try {\n const raw = await fs.readFile(fullPath, 'utf8');\n const parsed = JSON.parse(raw) as { payload?: unknown };\n const payload = parsed?.payload;\n if (!payload || typeof payload !== 'object') {\n continue;\n }\n const accountId = (payload as Record<string, unknown>).id;\n if (typeof accountId === 'string' && accountId.trim().length > 0) {\n map.set(accountId, payload as Record<string, unknown>);\n }\n } catch (error: unknown) {\n this.logger.debug(`Skipping account file ${fullPath}: ${(error as Error).message}`);\n }\n }\n } catch (error: unknown) {\n this.logger.debug(`Account data directory unavailable (${ACCOUNT_DATA_DIR}): ${(error as Error).message}`);\n }\n return map;\n }\n\n private isTableMissing(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const code = (error as { code?: string }).code;\n if (code === '42P01') {\n return true;\n }\n const message = (error as { message?: string }).message ?? '';\n return /does not exist/u.test(message);\n }\n\n private isDuplicateDefinitionError(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const code = (error as { code?: string }).code;\n if (code && [ '23505', '42P07', '42710' ].includes(code)) {\n return true;\n }\n const message = (error as { message?: string }).message ?? '';\n return /already exists/u.test(message);\n }\n}\n"]}
1
+ {"version":3,"file":"AccountRoleRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRoleRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { sql } from 'drizzle-orm';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { IdentityDatabase } from './db';\nimport { executeQuery, executeStatement, isDatabaseSqlite } from './db';\n\nconst ACCOUNT_DATA_DIR = path.resolve('.internal', 'accounts', 'data');\nconst IDENTITY_STORE_TABLE = 'identity_store';\nconst INTERNAL_KV_TABLE = 'internal_kv';\n\nexport interface AccountRoleContext {\n accountId: string;\n webId?: string;\n roles: string[];\n}\n\ninterface AccountPayloadRecord {\n id: string;\n payload: Record<string, unknown>;\n source: 'identity-store' | 'internal-kv' | 'file';\n key?: string;\n}\n\nfunction resolveWebIds(payload: Record<string, unknown>): string[] {\n const candidates = new Set<string>();\n const possibleKeys = [ 'webId', 'webid', 'primaryWebId', 'primary_webid' ];\n for (const key of possibleKeys) {\n const value = payload[key];\n if (typeof value === 'string' && value.trim().length > 0) {\n candidates.add(value.trim());\n }\n }\n const settings = payload.settings;\n if (settings && typeof settings === 'object') {\n const webId = (settings as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n const pods = payload.pods;\n if (Array.isArray(pods)) {\n for (const entry of pods) {\n if (!entry || typeof entry !== 'object') {\n continue;\n }\n const webId = (entry as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n }\n\n const webIdLink = payload['**webIdLink**'] ?? payload.webIdLink;\n if (webIdLink && typeof webIdLink === 'object') {\n for (const entry of Object.values(webIdLink as Record<string, unknown>)) {\n if (!entry || typeof entry !== 'object') {\n continue;\n }\n const webId = (entry as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n }\n\n const podMap = payload['**pod**'] ?? payload.pod;\n if (podMap && typeof podMap === 'object') {\n for (const pod of Object.values(podMap as Record<string, unknown>)) {\n if (!pod || typeof pod !== 'object') {\n continue;\n }\n const owner = (pod as Record<string, unknown>)['**owner**'] ?? (pod as Record<string, unknown>).owner;\n if (!owner || typeof owner !== 'object') {\n continue;\n }\n for (const entry of Object.values(owner as Record<string, unknown>)) {\n if (!entry || typeof entry !== 'object') {\n continue;\n }\n const webId = (entry as Record<string, unknown>).webId;\n if (typeof webId === 'string' && webId.trim().length > 0) {\n candidates.add(webId.trim());\n }\n }\n }\n }\n\n return Array.from(candidates);\n}\n\nfunction resolveRoles(payload: Record<string, unknown>): string[] {\n const roles = payload.roles;\n if (!Array.isArray(roles)) {\n return [];\n }\n return Array.from(new Set(\n roles\n .map((role) => typeof role === 'string' ? role.trim() : '')\n .filter((role) => role.length > 0),\n ));\n}\n\nfunction parsePayload(value: unknown): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value) as unknown;\n return parsed && typeof parsed === 'object' ? parsed as Record<string, unknown> : undefined;\n } catch {\n return undefined;\n }\n }\n return typeof value === 'object' ? value as Record<string, unknown> : undefined;\n}\n\nexport class AccountRoleRepository {\n private readonly logger = getLoggerFor(this);\n\n public constructor(private readonly db: IdentityDatabase) {}\n\n public async findByAccountId(accountId: string): Promise<AccountRoleContext | undefined> {\n const record = await this.getAccountById(accountId);\n if (!record) {\n return undefined;\n }\n const [ webId ] = resolveWebIds(record.payload);\n return { accountId, webId, roles: resolveRoles(record.payload) };\n }\n\n public async findByWebId(webId: string): Promise<AccountRoleContext | undefined> {\n const accounts = await this.loadAllAccounts();\n for (const { id, payload } of accounts.values()) {\n const knownWebIds = resolveWebIds(payload);\n if (knownWebIds.includes(webId)) {\n return {\n accountId: id,\n webId,\n roles: resolveRoles(payload),\n };\n }\n }\n return undefined;\n }\n\n public async findByWebIdLoose(webId: string): Promise<AccountRoleContext | undefined> {\n return this.findByWebId(webId);\n }\n\n public async addRoles(accountId: string, roles: string[]): Promise<void> {\n const unique = Array.from(new Set(\n roles.map((role) => role.trim()).filter((role) => role.length > 0),\n ));\n if (unique.length === 0) {\n return;\n }\n const record = await this.getAccountById(accountId);\n if (!record) {\n this.logger.warn(`Cannot add roles for unknown account ${accountId}`);\n return;\n }\n const nextRoles = Array.from(new Set([ ...resolveRoles(record.payload), ...unique ]));\n await this.updateAccountRecord(record, { ...record.payload, roles: nextRoles });\n }\n\n private async getAccountById(accountId: string): Promise<AccountPayloadRecord | undefined> {\n const accounts = await this.loadAllAccounts();\n return accounts.get(accountId);\n }\n\n private async loadAllAccounts(): Promise<Map<string, AccountPayloadRecord>> {\n const accounts = new Map<string, AccountPayloadRecord>();\n await this.loadIdentityStoreAccounts(accounts);\n await this.loadInternalKvAccounts(accounts);\n for (const [id, payload] of await this.loadFileAccountMap()) {\n if (!accounts.has(id)) {\n accounts.set(id, { id, payload, source: 'file' });\n }\n }\n return accounts;\n }\n\n private async loadIdentityStoreAccounts(accounts: Map<string, AccountPayloadRecord>): Promise<void> {\n const tableId = sql.identifier([IDENTITY_STORE_TABLE]);\n let rows: Array<{ container?: string; id?: string; payload?: unknown }> = [];\n try {\n const result = await executeQuery<{ container?: string; id?: string; payload?: unknown }>(this.db, sql`\n SELECT container, id, payload\n FROM ${tableId}\n WHERE container IN ('account', 'pod', 'owner', 'webIdLink')\n `);\n rows = result.rows;\n } catch (error: unknown) {\n if (!this.isTableMissing(error)) {\n throw error;\n }\n return;\n }\n\n const podAccountIds = new Map<string, string>();\n const webIdsByAccount = new Map<string, Set<string>>();\n\n for (const row of rows) {\n if (!row.id || !row.container) {\n continue;\n }\n const payload = parsePayload(row.payload);\n if (!payload) {\n continue;\n }\n if (row.container === 'account') {\n accounts.set(row.id, { id: row.id, payload, source: 'identity-store' });\n } else if (row.container === 'pod') {\n const accountId = typeof payload.accountId === 'string' ? payload.accountId : undefined;\n if (accountId) {\n podAccountIds.set(row.id, accountId);\n }\n }\n }\n\n for (const row of rows) {\n const payload = parsePayload(row.payload);\n if (!row.container || !payload) {\n continue;\n }\n if (row.container === 'webIdLink') {\n const accountId = typeof payload.accountId === 'string' ? payload.accountId : undefined;\n const webId = typeof payload.webId === 'string' ? payload.webId : undefined;\n if (accountId && webId) {\n appendWebId(webIdsByAccount, accountId, webId);\n }\n } else if (row.container === 'owner') {\n const podId = typeof payload.podId === 'string' ? payload.podId : undefined;\n const webId = typeof payload.webId === 'string' ? payload.webId : undefined;\n const accountId = podId ? podAccountIds.get(podId) : undefined;\n if (accountId && webId) {\n appendWebId(webIdsByAccount, accountId, webId);\n }\n }\n }\n\n for (const [accountId, webIds] of webIdsByAccount) {\n const record = accounts.get(accountId);\n if (!record) {\n continue;\n }\n record.payload = {\n ...record.payload,\n webIdLink: Object.fromEntries(Array.from(webIds).map((webId, index) => [\n `webid-${index}`,\n { accountId, webId },\n ])),\n };\n }\n }\n\n private async loadInternalKvAccounts(accounts: Map<string, AccountPayloadRecord>): Promise<void> {\n const tableId = sql.identifier([INTERNAL_KV_TABLE]);\n try {\n const result = await executeQuery<{ key?: string; value?: unknown }>(this.db, sql`\n SELECT key, value\n FROM ${tableId}\n WHERE key LIKE 'accounts/data/%'\n OR key LIKE '/.internal/accounts/data/%'\n `);\n for (const row of result.rows) {\n if (!row.key) {\n continue;\n }\n const accountId = extractAccountIdFromKey(row.key);\n const payload = parsePayload(row.value);\n if (!accountId || !payload || accounts.has(accountId)) {\n continue;\n }\n accounts.set(accountId, { id: accountId, payload, source: 'internal-kv', key: row.key });\n }\n } catch (error: unknown) {\n if (!this.isTableMissing(error)) {\n throw error;\n }\n }\n }\n\n private async loadFileAccountMap(): Promise<Map<string, Record<string, unknown>>> {\n const map = new Map<string, Record<string, unknown>>();\n try {\n const files = await fs.readdir(ACCOUNT_DATA_DIR);\n for (const file of files) {\n if (!file.endsWith('.json')) {\n continue;\n }\n const fullPath = path.join(ACCOUNT_DATA_DIR, file);\n try {\n const raw = await fs.readFile(fullPath, 'utf8');\n const parsed = JSON.parse(raw) as { payload?: unknown };\n const payload = parsed?.payload;\n if (!payload || typeof payload !== 'object') {\n continue;\n }\n const accountId = (payload as Record<string, unknown>).id;\n if (typeof accountId === 'string' && accountId.trim().length > 0) {\n map.set(accountId, payload as Record<string, unknown>);\n }\n } catch (error: unknown) {\n this.logger.debug(`Skipping account file ${fullPath}: ${(error as Error).message}`);\n }\n }\n } catch (error: unknown) {\n this.logger.debug(`Account data directory unavailable (${ACCOUNT_DATA_DIR}): ${(error as Error).message}`);\n }\n return map;\n }\n\n private async updateAccountRecord(record: AccountPayloadRecord, payload: Record<string, unknown>): Promise<void> {\n if (record.source === 'identity-store') {\n const tableId = sql.identifier([IDENTITY_STORE_TABLE]);\n await executeStatement(this.db, sql`\n UPDATE ${tableId}\n SET payload = ${this.toJsonSql(payload)}\n WHERE container = 'account' AND id = ${record.id}\n `);\n return;\n }\n if (record.source === 'internal-kv' && record.key) {\n const tableId = sql.identifier([INTERNAL_KV_TABLE]);\n await executeStatement(this.db, sql`\n UPDATE ${tableId}\n SET value = ${JSON.stringify(payload)}\n WHERE key = ${record.key}\n `);\n }\n }\n\n private toJsonSql(payload: Record<string, unknown>): unknown {\n const serialized = JSON.stringify(payload);\n return isDatabaseSqlite(this.db) ? sql`${serialized}` : sql`${serialized}::jsonb`;\n }\n\n private isTableMissing(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const code = (error as { code?: string }).code;\n if (code === '42P01') {\n return true;\n }\n const message = (error as { message?: string }).message ?? '';\n return /does not exist|no such table/u.test(message);\n }\n}\n\nfunction appendWebId(target: Map<string, Set<string>>, accountId: string, webId: string): void {\n const values = target.get(accountId) ?? new Set<string>();\n values.add(webId);\n target.set(accountId, values);\n}\n\nfunction extractAccountIdFromKey(key: string): string | undefined {\n const marker = 'accounts/data/';\n const index = key.indexOf(marker);\n if (index < 0) {\n return undefined;\n }\n const accountId = key.slice(index + marker.length).replace(/\\.json$/u, '');\n return accountId || undefined;\n}\n"]}
@@ -1,16 +1,12 @@
1
1
  /**
2
2
  * DDNS Repository
3
3
  *
4
- * 管理 DDNS 域名池和记录
4
+ * 管理 Cloud 已分配的 DDNS 记录。
5
+ *
6
+ * 根域名、DNS provider 和 zone 等属于 Cloud 部署配置,不在控制面表中
7
+ * 再维护一份域名池,避免配置事实和数据库事实分叉。
5
8
  */
6
9
  import type { IdentityDatabase } from './db';
7
- export interface DdnsDomain {
8
- domain: string;
9
- status: 'active' | 'suspended';
10
- provider?: string;
11
- zoneId?: string;
12
- createdAt: Date;
13
- }
14
10
  export interface DdnsRecord {
15
11
  subdomain: string;
16
12
  domain: string;
@@ -42,19 +38,8 @@ export interface UpdateDdnsRecordInput {
42
38
  export declare class DdnsRepository {
43
39
  private readonly db;
44
40
  private readonly schema;
41
+ private readonly ready;
45
42
  constructor(db: IdentityDatabase);
46
- /**
47
- * 添加域名到池中
48
- */
49
- addDomain(domain: string, provider?: string, zoneId?: string): Promise<DdnsDomain>;
50
- /**
51
- * 获取所有活跃的域名
52
- */
53
- getActiveDomains(): Promise<DdnsDomain[]>;
54
- /**
55
- * 暂停域名
56
- */
57
- suspendDomain(domain: string): Promise<void>;
58
43
  /**
59
44
  * 分配子域名
60
45
  */
@@ -2,7 +2,10 @@
2
2
  /**
3
3
  * DDNS Repository
4
4
  *
5
- * 管理 DDNS 域名池和记录
5
+ * 管理 Cloud 已分配的 DDNS 记录。
6
+ *
7
+ * 根域名、DNS provider 和 zone 等属于 Cloud 部署配置,不在控制面表中
8
+ * 再维护一份域名池,避免配置事实和数据库事实分叉。
6
9
  */
7
10
  Object.defineProperty(exports, "__esModule", { value: true });
8
11
  exports.DdnsRepository = void 0;
@@ -14,60 +17,14 @@ class DdnsRepository {
14
17
  constructor(db) {
15
18
  this.db = db;
16
19
  this.schema = (0, db_1.getSchema)(db);
17
- }
18
- // ==================== Domain Pool ====================
19
- /**
20
- * 添加域名到池中
21
- */
22
- async addDomain(domain, provider, zoneId) {
23
- const now = new Date();
24
- await this.db.insert(this.schema.ddnsDomains).values({
25
- domain,
26
- status: 'active',
27
- provider,
28
- zoneId,
29
- createdAt: (0, db_1.toDbTimestamp)(this.db, now),
30
- });
31
- logger.info(`Added domain to pool: ${domain}`);
32
- return {
33
- domain,
34
- status: 'active',
35
- provider,
36
- zoneId,
37
- createdAt: now,
38
- };
39
- }
40
- /**
41
- * 获取所有活跃的域名
42
- */
43
- async getActiveDomains() {
44
- const results = await this.db
45
- .select()
46
- .from(this.schema.ddnsDomains)
47
- .where((0, drizzle_orm_1.eq)(this.schema.ddnsDomains.status, 'active'));
48
- return results.map((row) => ({
49
- domain: row.domain,
50
- status: row.status,
51
- provider: row.provider ?? undefined,
52
- zoneId: row.zoneId ?? undefined,
53
- createdAt: (0, db_1.fromDbTimestamp)(row.createdAt) ?? new Date(0),
54
- }));
55
- }
56
- /**
57
- * 暂停域名
58
- */
59
- async suspendDomain(domain) {
60
- await this.db
61
- .update(this.schema.ddnsDomains)
62
- .set({ status: 'suspended' })
63
- .where((0, drizzle_orm_1.eq)(this.schema.ddnsDomains.domain, domain));
64
- logger.info(`Suspended domain: ${domain}`);
20
+ this.ready = (0, db_1.ensureCloudClusterTables)(db);
65
21
  }
66
22
  // ==================== DDNS Records ====================
67
23
  /**
68
24
  * 分配子域名
69
25
  */
70
26
  async allocateSubdomain(input) {
27
+ await this.ready;
71
28
  const { subdomain, domain, ipAddress, ipv6Address, nodeId, username } = input;
72
29
  // 检查是否已存在
73
30
  const existing = await this.getRecord(subdomain);
@@ -108,6 +65,7 @@ class DdnsRepository {
108
65
  * 获取 DDNS 记录
109
66
  */
110
67
  async getRecord(subdomain) {
68
+ await this.ready;
111
69
  const results = await this.db
112
70
  .select()
113
71
  .from(this.schema.ddnsRecords)
@@ -136,6 +94,7 @@ class DdnsRepository {
136
94
  * 更新 DDNS 记录的 IP 地址
137
95
  */
138
96
  async updateRecordIp(subdomain, input) {
97
+ await this.ready;
139
98
  const existing = await this.getRecord(subdomain);
140
99
  if (!existing) {
141
100
  return null;
@@ -177,6 +136,7 @@ class DdnsRepository {
177
136
  * 封禁子域名
178
137
  */
179
138
  async banSubdomain(subdomain, reason) {
139
+ await this.ready;
180
140
  await this.db
181
141
  .update(this.schema.ddnsRecords)
182
142
  .set({
@@ -191,6 +151,7 @@ class DdnsRepository {
191
151
  * 解封子域名
192
152
  */
193
153
  async unbanSubdomain(subdomain) {
154
+ await this.ready;
194
155
  await this.db
195
156
  .update(this.schema.ddnsRecords)
196
157
  .set({
@@ -205,6 +166,7 @@ class DdnsRepository {
205
166
  * 释放子域名
206
167
  */
207
168
  async releaseSubdomain(subdomain) {
169
+ await this.ready;
208
170
  await this.db
209
171
  .delete(this.schema.ddnsRecords)
210
172
  .where((0, drizzle_orm_1.eq)(this.schema.ddnsRecords.subdomain, subdomain));
@@ -215,6 +177,7 @@ class DdnsRepository {
215
177
  * 获取用户的所有子域名
216
178
  */
217
179
  async getRecordsByUsername(username) {
180
+ await this.ready;
218
181
  const results = await this.db
219
182
  .select()
220
183
  .from(this.schema.ddnsRecords)
@@ -238,6 +201,7 @@ class DdnsRepository {
238
201
  * 获取节点的子域名
239
202
  */
240
203
  async getRecordByNodeId(nodeId) {
204
+ await this.ready;
241
205
  const results = await this.db
242
206
  .select()
243
207
  .from(this.schema.ddnsRecords)