@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.
- package/dist/api/auth/AuthContext.d.ts +3 -2
- package/dist/api/auth/AuthContext.js +2 -1
- package/dist/api/auth/AuthContext.js.map +1 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
- package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
- package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
- package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
- package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
- package/dist/api/chatkit/pod-store.d.ts +3 -0
- package/dist/api/chatkit/pod-store.js +93 -59
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +5 -6
- package/dist/api/container/business-token.d.ts +1 -1
- package/dist/api/container/business-token.js +5 -1
- package/dist/api/container/business-token.js.map +1 -1
- package/dist/api/container/common.js +14 -10
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/routes.js +16 -3
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +2 -4
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/ChatHandler.d.ts +1 -1
- package/dist/api/handlers/ChatHandler.js +1 -1
- package/dist/api/handlers/ChatHandler.js.map +1 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
- package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
- package/dist/api/handlers/PodManagementHandler.js +114 -12
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
- package/dist/api/handlers/ProvisionHandler.js +339 -32
- package/dist/api/handlers/ProvisionHandler.js.map +1 -1
- package/dist/api/handlers/QuotaHandler.js +0 -12
- package/dist/api/handlers/QuotaHandler.js.map +1 -1
- package/dist/api/handlers/index.d.ts +0 -1
- package/dist/api/handlers/index.js +0 -1
- package/dist/api/handlers/index.js.map +1 -1
- package/dist/api/matrix/PodMatrixStore.js +26 -21
- package/dist/api/matrix/PodMatrixStore.js.map +1 -1
- package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
- package/dist/api/runs/schema.d.ts +5 -7
- package/dist/api/runs/store.js +6 -4
- package/dist/api/runs/store.js.map +1 -1
- package/dist/api/runtime.js +3 -3
- package/dist/api/runtime.js.map +1 -1
- package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
- package/dist/api/tasks/schema.d.ts +17 -13
- package/dist/api/tasks/schema.js +7 -2
- package/dist/api/tasks/schema.js.map +1 -1
- package/dist/api/tasks/store.js +1 -2
- package/dist/api/tasks/store.js.map +1 -1
- package/dist/components/context.jsonld +12 -0
- package/dist/edge/EdgeNodeAgent.d.ts +1 -1
- package/dist/edge/EdgeNodeAgent.js +1 -1
- package/dist/edge/EdgeNodeAgent.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
- package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
- package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
- package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
- package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
- package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
- package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
- package/dist/http/ClusterIngressRouter.js +6 -3
- package/dist/http/ClusterIngressRouter.js.map +1 -1
- package/dist/http/ClusterWebSocketConfigurator.js +6 -2
- package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
- package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
- package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
- package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
- package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
- package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
- package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
- package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
- package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
- package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
- package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
- package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
- package/dist/http/search/SearchHttpHandler.js +2 -2
- package/dist/http/search/SearchHttpHandler.js.map +1 -1
- package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
- package/dist/identity/drizzle/AccountRepository.js +9 -113
- package/dist/identity/drizzle/AccountRepository.js.map +1 -1
- package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
- package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
- package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
- package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
- package/dist/identity/drizzle/DdnsRepository.js +13 -49
- package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
- package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
- package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
- package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
- package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
- package/dist/identity/drizzle/PodLookupRepository.js +103 -126
- package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
- package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
- package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
- package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
- package/dist/identity/drizzle/db.d.ts +2 -1
- package/dist/identity/drizzle/db.js +173 -297
- package/dist/identity/drizzle/db.js.map +1 -1
- package/dist/identity/drizzle/schema.pg.d.ts +3 -11
- package/dist/identity/drizzle/schema.pg.js +10 -45
- package/dist/identity/drizzle/schema.pg.js.map +1 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
- package/dist/identity/drizzle/schema.sqlite.js +13 -46
- package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
- package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
- package/dist/provision/ProvisionCodeCodec.js +10 -1
- package/dist/provision/ProvisionCodeCodec.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.d.ts +8 -2
- package/dist/provision/ProvisionPodCreator.js +134 -41
- package/dist/provision/ProvisionPodCreator.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.jsonld +38 -3
- package/dist/quota/DrizzleQuotaService.d.ts +0 -4
- package/dist/quota/DrizzleQuotaService.js +1 -21
- package/dist/quota/DrizzleQuotaService.js.map +1 -1
- package/dist/quota/DrizzleQuotaService.jsonld +0 -16
- package/dist/quota/NoopQuotaService.d.ts +0 -4
- package/dist/quota/NoopQuotaService.js +0 -8
- package/dist/quota/NoopQuotaService.js.map +1 -1
- package/dist/quota/NoopQuotaService.jsonld +0 -16
- package/dist/quota/QuotaService.d.ts +0 -4
- package/dist/quota/QuotaService.js.map +1 -1
- package/dist/quota/QuotaService.jsonld +0 -16
- package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
- package/dist/service/EdgeNodeSignalClient.js +0 -4
- package/dist/service/EdgeNodeSignalClient.js.map +1 -1
- package/dist/service/PodMigrationService.d.ts +2 -2
- package/dist/service/PodMigrationService.js +4 -4
- package/dist/service/PodMigrationService.js.map +1 -1
- package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
- package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
- package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
- package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
- package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
- package/dist/storage/quota/UsageRepository.d.ts +10 -32
- package/dist/storage/quota/UsageRepository.js +84 -281
- package/dist/storage/quota/UsageRepository.js.map +1 -1
- package/dist/storage/vector/VectorIndexingListener.js +2 -2
- package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
- package/dist/subdomain/SubdomainService.d.ts +1 -1
- package/dist/subdomain/SubdomainService.js +1 -1
- package/dist/subdomain/SubdomainService.js.map +1 -1
- package/dist/subdomain/SubdomainService.jsonld +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts +21 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js +85 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts +10 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js +365 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js +3 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js +5 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts +2 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js +2 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts +18 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js +234 -10
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts +13 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js +19 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts +21 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js +78 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts +10 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js +362 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js +5 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts +2 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts +18 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js +225 -10
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts +13 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js +19 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts +5 -4
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js +4 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts +5 -4
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.js +20 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
- package/package.json +3 -3
- package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
- package/dist/api/handlers/ApiKeyHandler.js +0 -153
- package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
- package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
- package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
- 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
|
-
|
|
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.
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
129
|
-
const
|
|
130
|
-
|
|
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
|
|
142
|
-
SELECT payload
|
|
143
|
-
FROM
|
|
144
|
-
WHERE
|
|
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
|
-
|
|
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
|
|
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) `
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
210
|
-
if (
|
|
211
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
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
|
|
318
|
+
if (code === '42P01') {
|
|
226
319
|
return true;
|
|
227
320
|
}
|
|
228
321
|
const message = error.message ?? '';
|
|
229
|
-
return /
|
|
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)
|