@undefineds.co/xpod 0.3.31 → 0.3.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/runtime.js +3 -3
- package/dist/api/runtime.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/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/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/package.json +1 -1
- 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
|
@@ -1,130 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AccountRepository = void 0;
|
|
4
|
-
const
|
|
5
|
-
const db_1 = require("./db");
|
|
4
|
+
const PodLookupRepository_1 = require("./PodLookupRepository");
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Reads account/pod data from CSS's internal_kv table.
|
|
10
|
-
* Quota limits are stored in identity_account_usage / identity_pod_usage tables.
|
|
6
|
+
* Reads account/pod ownership data from the CSS identity facts.
|
|
7
|
+
* Quota values live in identity_usage and are managed by UsageRepository.
|
|
11
8
|
*/
|
|
12
9
|
class AccountRepository {
|
|
13
10
|
constructor(db, kvTableName) {
|
|
14
|
-
this.
|
|
15
|
-
this.kvTableName = kvTableName ?? 'internal_kv';
|
|
16
|
-
this.accountUsageTable = 'identity_account_usage';
|
|
17
|
-
this.podUsageTable = 'identity_pod_usage';
|
|
18
|
-
}
|
|
19
|
-
async getAccountQuota(accountId) {
|
|
20
|
-
try {
|
|
21
|
-
const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
|
|
22
|
-
const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE account_id = ${accountId} LIMIT 1`);
|
|
23
|
-
if (result.rows.length === 0) {
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
const limit = result.rows[0].storage_limit_bytes;
|
|
27
|
-
return limit != null ? limit : undefined;
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Table might not exist
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
11
|
+
this.podLookupRepo = new PodLookupRepository_1.PodLookupRepository(db, kvTableName);
|
|
33
12
|
}
|
|
34
13
|
async getPodInfo(podId) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
SELECT key, value FROM ${kvTableId}
|
|
39
|
-
WHERE key LIKE 'accounts/data/%'
|
|
40
|
-
`);
|
|
41
|
-
for (const row of result.rows) {
|
|
42
|
-
try {
|
|
43
|
-
const accountId = row.key.replace('accounts/data/', '');
|
|
44
|
-
const data = typeof row.value === 'string' ? JSON.parse(row.value) : row.value;
|
|
45
|
-
const podMap = data['**pod**'] || data.pod || {};
|
|
46
|
-
if (podMap[podId]) {
|
|
47
|
-
const pod = podMap[podId];
|
|
48
|
-
const podQuota = await this.getPodQuota(podId);
|
|
49
|
-
return {
|
|
50
|
-
accountId,
|
|
51
|
-
baseUrl: typeof pod.baseUrl === 'string' ? pod.baseUrl : undefined,
|
|
52
|
-
podQuota,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
// Skip malformed entries
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return undefined;
|
|
61
|
-
}
|
|
62
|
-
async getPodQuota(podId) {
|
|
63
|
-
try {
|
|
64
|
-
const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
|
|
65
|
-
const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `SELECT storage_limit_bytes FROM ${tableId} WHERE pod_id = ${podId} LIMIT 1`);
|
|
66
|
-
if (result.rows.length === 0) {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
const limit = result.rows[0].storage_limit_bytes;
|
|
70
|
-
return limit != null ? limit : undefined;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
// Table might not exist
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async getQuotaContext(accountId, podId) {
|
|
78
|
-
const podInfo = await this.getPodInfo(podId);
|
|
79
|
-
if (!podInfo) {
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
if (podInfo.accountId !== accountId) {
|
|
14
|
+
const pod = await this.podLookupRepo.findById(podId)
|
|
15
|
+
?? await this.podLookupRepo.findByResourceIdentifier(podId);
|
|
16
|
+
if (!pod) {
|
|
83
17
|
return undefined;
|
|
84
18
|
}
|
|
85
|
-
const accountQuota = await this.getAccountQuota(accountId);
|
|
86
19
|
return {
|
|
87
|
-
accountId,
|
|
88
|
-
|
|
89
|
-
baseUrl: podInfo.baseUrl,
|
|
90
|
-
podQuota: podInfo.podQuota,
|
|
91
|
-
accountQuota,
|
|
20
|
+
accountId: pod.accountId,
|
|
21
|
+
baseUrl: pod.baseUrl,
|
|
92
22
|
};
|
|
93
23
|
}
|
|
94
|
-
async setAccountQuota(accountId, quota) {
|
|
95
|
-
const tableId = drizzle_orm_1.sql.identifier([this.accountUsageTable]);
|
|
96
|
-
if ((0, db_1.isDatabaseSqlite)(this.db)) {
|
|
97
|
-
await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
98
|
-
INSERT INTO ${tableId} (account_id, storage_limit_bytes)
|
|
99
|
-
VALUES (${accountId}, ${quota ?? null})
|
|
100
|
-
ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
|
|
101
|
-
`);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
105
|
-
INSERT INTO ${tableId} (account_id, storage_limit_bytes)
|
|
106
|
-
VALUES (${accountId}, ${quota ?? null})
|
|
107
|
-
ON CONFLICT (account_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
|
|
108
|
-
`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
async setPodQuota(podId, quota) {
|
|
112
|
-
const tableId = drizzle_orm_1.sql.identifier([this.podUsageTable]);
|
|
113
|
-
if ((0, db_1.isDatabaseSqlite)(this.db)) {
|
|
114
|
-
await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
115
|
-
INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
|
|
116
|
-
VALUES (${podId}, '', ${quota ?? null})
|
|
117
|
-
ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = ${quota ?? null}
|
|
118
|
-
`);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
122
|
-
INSERT INTO ${tableId} (pod_id, account_id, storage_limit_bytes)
|
|
123
|
-
VALUES (${podId}, '', ${quota ?? null})
|
|
124
|
-
ON CONFLICT (pod_id) DO UPDATE SET storage_limit_bytes = EXCLUDED.storage_limit_bytes
|
|
125
|
-
`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
24
|
}
|
|
129
25
|
exports.AccountRepository = AccountRepository;
|
|
130
26
|
//# sourceMappingURL=AccountRepository.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"AccountRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/AccountRepository.ts"],"names":[],"mappings":";;;AACA,+DAA4D;AAE5D;;;GAGG;AACH,MAAa,iBAAiB;IAG5B,YACE,EAAoB,EACpB,WAAoB;QAEpB,IAAI,CAAC,aAAa,GAAG,IAAI,yCAAmB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,KAAa;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;eAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC;IACJ,CAAC;CACF;AArBD,8CAqBC","sourcesContent":["import type { IdentityDatabase } from './db';\nimport { PodLookupRepository } from './PodLookupRepository';\n\n/**\n * Reads account/pod ownership data from the CSS identity facts.\n * Quota values live in identity_usage and are managed by UsageRepository.\n */\nexport class AccountRepository {\n private readonly podLookupRepo: PodLookupRepository;\n\n public constructor(\n db: IdentityDatabase,\n kvTableName?: string,\n ) {\n this.podLookupRepo = new PodLookupRepository(db, kvTableName);\n }\n\n public async getPodInfo(podId: string): Promise<{ accountId: string; baseUrl?: string } | undefined> {\n const pod = await this.podLookupRepo.findById(podId)\n ?? await this.podLookupRepo.findByResourceIdentifier(podId);\n if (!pod) {\n return undefined;\n }\n return {\n accountId: pod.accountId,\n baseUrl: pod.baseUrl,\n };\n }\n}\n"]}
|
|
@@ -6,18 +6,18 @@ export interface AccountRoleContext {
|
|
|
6
6
|
}
|
|
7
7
|
export declare class AccountRoleRepository {
|
|
8
8
|
private readonly db;
|
|
9
|
-
private readonly ready;
|
|
10
9
|
private readonly logger;
|
|
11
10
|
constructor(db: IdentityDatabase);
|
|
12
11
|
findByAccountId(accountId: string): Promise<AccountRoleContext | undefined>;
|
|
13
12
|
findByWebId(webId: string): Promise<AccountRoleContext | undefined>;
|
|
14
13
|
findByWebIdLoose(webId: string): Promise<AccountRoleContext | undefined>;
|
|
15
14
|
addRoles(accountId: string, roles: string[]): Promise<void>;
|
|
16
|
-
private
|
|
17
|
-
private fetchRoles;
|
|
18
|
-
private getAccountPayloadById;
|
|
15
|
+
private getAccountById;
|
|
19
16
|
private loadAllAccounts;
|
|
17
|
+
private loadIdentityStoreAccounts;
|
|
18
|
+
private loadInternalKvAccounts;
|
|
20
19
|
private loadFileAccountMap;
|
|
20
|
+
private updateAccountRecord;
|
|
21
|
+
private toJsonSql;
|
|
21
22
|
private isTableMissing;
|
|
22
|
-
private isDuplicateDefinitionError;
|
|
23
23
|
}
|
|
@@ -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
|