@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
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.serviceTokens = exports.
|
|
3
|
+
exports.serviceTokens = exports.edgeNodes = exports.ddnsRecords = exports.usage = void 0;
|
|
4
4
|
const sqlite_core_1 = require("drizzle-orm/sqlite-core");
|
|
5
|
-
exports.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ingressBytes: (0, sqlite_core_1.integer)('ingress_bytes').notNull().default(0),
|
|
9
|
-
egressBytes: (0, sqlite_core_1.integer)('egress_bytes').notNull().default(0),
|
|
10
|
-
storageLimitBytes: (0, sqlite_core_1.integer)('storage_limit_bytes'),
|
|
11
|
-
bandwidthLimitBps: (0, sqlite_core_1.integer)('bandwidth_limit_bps'),
|
|
12
|
-
computeSeconds: (0, sqlite_core_1.integer)('compute_seconds').notNull().default(0),
|
|
13
|
-
tokensUsed: (0, sqlite_core_1.integer)('tokens_used').notNull().default(0),
|
|
14
|
-
computeLimitSeconds: (0, sqlite_core_1.integer)('compute_limit_seconds'),
|
|
15
|
-
tokenLimitMonthly: (0, sqlite_core_1.integer)('token_limit_monthly'),
|
|
16
|
-
periodStart: (0, sqlite_core_1.integer)('period_start'),
|
|
17
|
-
updatedAt: (0, sqlite_core_1.integer)('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
18
|
-
});
|
|
19
|
-
exports.podUsage = (0, sqlite_core_1.sqliteTable)('identity_pod_usage', {
|
|
20
|
-
podId: (0, sqlite_core_1.text)('pod_id').primaryKey(),
|
|
5
|
+
exports.usage = (0, sqlite_core_1.sqliteTable)('identity_usage', {
|
|
6
|
+
scopeType: (0, sqlite_core_1.text)('scope_type').notNull(), // 'account' | 'pod'
|
|
7
|
+
scopeId: (0, sqlite_core_1.text)('scope_id').notNull(),
|
|
21
8
|
accountId: (0, sqlite_core_1.text)('account_id').notNull(),
|
|
22
|
-
storageUrl: (0, sqlite_core_1.text)('storage_url'),
|
|
23
9
|
storageBytes: (0, sqlite_core_1.integer)('storage_bytes').notNull().default(0),
|
|
24
10
|
ingressBytes: (0, sqlite_core_1.integer)('ingress_bytes').notNull().default(0),
|
|
25
11
|
egressBytes: (0, sqlite_core_1.integer)('egress_bytes').notNull().default(0),
|
|
@@ -31,23 +17,14 @@ exports.podUsage = (0, sqlite_core_1.sqliteTable)('identity_pod_usage', {
|
|
|
31
17
|
tokenLimitMonthly: (0, sqlite_core_1.integer)('token_limit_monthly'),
|
|
32
18
|
periodStart: (0, sqlite_core_1.integer)('period_start'),
|
|
33
19
|
updatedAt: (0, sqlite_core_1.integer)('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
* 管理可用的 DDNS 域名
|
|
38
|
-
*/
|
|
39
|
-
exports.ddnsDomains = (0, sqlite_core_1.sqliteTable)('identity_ddns_domain', {
|
|
40
|
-
domain: (0, sqlite_core_1.text)('domain').primaryKey(), // undefineds.xyz
|
|
41
|
-
status: (0, sqlite_core_1.text)('status').default('active'), // 'active' | 'suspended'
|
|
42
|
-
provider: (0, sqlite_core_1.text)('provider'), // 'cloudflare' | 'tencent'
|
|
43
|
-
zoneId: (0, sqlite_core_1.text)('zone_id'), // DNS Zone ID
|
|
44
|
-
createdAt: (0, sqlite_core_1.integer)('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
45
|
-
});
|
|
20
|
+
}, (table) => [
|
|
21
|
+
(0, sqlite_core_1.primaryKey)({ columns: [table.scopeType, table.scopeId] }),
|
|
22
|
+
]);
|
|
46
23
|
/**
|
|
47
|
-
* DDNS 记录表
|
|
24
|
+
* Cloud cluster DDNS 记录表
|
|
48
25
|
* 已分配的子域名记录
|
|
49
26
|
*/
|
|
50
|
-
exports.ddnsRecords = (0, sqlite_core_1.sqliteTable)('
|
|
27
|
+
exports.ddnsRecords = (0, sqlite_core_1.sqliteTable)('cluster_ddns_record', {
|
|
51
28
|
subdomain: (0, sqlite_core_1.text)('subdomain').primaryKey(), // alice
|
|
52
29
|
domain: (0, sqlite_core_1.text)('domain').notNull(), // undefineds.xyz
|
|
53
30
|
ipAddress: (0, sqlite_core_1.text)('ip_address'),
|
|
@@ -61,7 +38,7 @@ exports.ddnsRecords = (0, sqlite_core_1.sqliteTable)('identity_ddns_record', {
|
|
|
61
38
|
createdAt: (0, sqlite_core_1.integer)('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
62
39
|
updatedAt: (0, sqlite_core_1.integer)('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
63
40
|
});
|
|
64
|
-
exports.edgeNodes = (0, sqlite_core_1.sqliteTable)('
|
|
41
|
+
exports.edgeNodes = (0, sqlite_core_1.sqliteTable)('cluster_node', {
|
|
65
42
|
id: (0, sqlite_core_1.text)('id').primaryKey(),
|
|
66
43
|
displayName: (0, sqlite_core_1.text)('display_name'),
|
|
67
44
|
tokenHash: (0, sqlite_core_1.text)('token_hash').notNull(),
|
|
@@ -82,28 +59,18 @@ exports.edgeNodes = (0, sqlite_core_1.sqliteTable)('identity_edge_node', {
|
|
|
82
59
|
// JSON fields
|
|
83
60
|
capabilities: (0, sqlite_core_1.text)('capabilities'), // JSON string: 能力列表
|
|
84
61
|
metadata: (0, sqlite_core_1.text)('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)
|
|
62
|
+
podBaseUrls: (0, sqlite_core_1.text)('pod_base_urls'), // JSON string: node-owned Pod/storage URL prefixes
|
|
85
63
|
connectivityStatus: (0, sqlite_core_1.text)('connectivity_status').default('unknown'),
|
|
86
64
|
lastConnectivityCheck: (0, sqlite_core_1.integer)('last_connectivity_check'),
|
|
87
65
|
createdAt: (0, sqlite_core_1.integer)('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
88
66
|
updatedAt: (0, sqlite_core_1.integer)('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
89
67
|
lastSeen: (0, sqlite_core_1.integer)('last_seen'),
|
|
90
68
|
});
|
|
91
|
-
exports.edgeNodePods = (0, sqlite_core_1.sqliteTable)('identity_edge_node_pod', {
|
|
92
|
-
nodeId: (0, sqlite_core_1.text)('node_id').notNull().references(() => exports.edgeNodes.id, { onDelete: 'cascade' }),
|
|
93
|
-
baseUrl: (0, sqlite_core_1.text)('base_url').notNull(),
|
|
94
|
-
});
|
|
95
|
-
exports.apiClientCredentials = (0, sqlite_core_1.sqliteTable)('identity_api_client_credentials', {
|
|
96
|
-
clientId: (0, sqlite_core_1.text)('client_id').primaryKey(),
|
|
97
|
-
webId: (0, sqlite_core_1.text)('web_id').notNull(),
|
|
98
|
-
accountId: (0, sqlite_core_1.text)('account_id').notNull(),
|
|
99
|
-
displayName: (0, sqlite_core_1.text)('display_name'),
|
|
100
|
-
createdAt: (0, sqlite_core_1.integer)('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),
|
|
101
|
-
});
|
|
102
69
|
/**
|
|
103
|
-
* Service Token 表
|
|
70
|
+
* Cloud cluster Service Token 表
|
|
104
71
|
* 用于服务间认证 (Business, Local SP, Cloud, Compute)
|
|
105
72
|
*/
|
|
106
|
-
exports.serviceTokens = (0, sqlite_core_1.sqliteTable)('
|
|
73
|
+
exports.serviceTokens = (0, sqlite_core_1.sqliteTable)('cluster_service_token', {
|
|
107
74
|
id: (0, sqlite_core_1.text)('id').primaryKey(),
|
|
108
75
|
tokenHash: (0, sqlite_core_1.text)('token_hash').notNull().unique(),
|
|
109
76
|
serviceType: (0, sqlite_core_1.text)('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.sqlite.js","sourceRoot":"","sources":["../../../src/identity/drizzle/schema.sqlite.ts"],"names":[],"mappings":";;;AAAA,yDAAqE;AAExD,QAAA,YAAY,GAAG,IAAA,yBAAW,EAAC,wBAAwB,EAAE;IAChE,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,UAAU,EAAE;IAC1C,YAAY,EAAE,IAAA,qBAAO,EAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,YAAY,EAAE,IAAA,qBAAO,EAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,WAAW,EAAE,IAAA,qBAAO,EAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,cAAc,EAAE,IAAA,qBAAO,EAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,UAAU,EAAE,IAAA,qBAAO,EAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,mBAAmB,EAAE,IAAA,qBAAO,EAAC,uBAAuB,CAAC;IACrD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,WAAW,EAAE,IAAA,qBAAO,EAAC,cAAc,CAAC;IACpC,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;CAC3F,CAAC,CAAC;AAEU,QAAA,QAAQ,GAAG,IAAA,yBAAW,EAAC,oBAAoB,EAAE;IACxD,KAAK,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,UAAU,EAAE;IAClC,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,UAAU,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC;IAC/B,YAAY,EAAE,IAAA,qBAAO,EAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,YAAY,EAAE,IAAA,qBAAO,EAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,WAAW,EAAE,IAAA,qBAAO,EAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,cAAc,EAAE,IAAA,qBAAO,EAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,UAAU,EAAE,IAAA,qBAAO,EAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,mBAAmB,EAAE,IAAA,qBAAO,EAAC,uBAAuB,CAAC;IACrD,iBAAiB,EAAE,IAAA,qBAAO,EAAC,qBAAqB,CAAC;IACjD,WAAW,EAAE,IAAA,qBAAO,EAAC,cAAc,CAAC;IACpC,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;CAC3F,CAAC,CAAC;AAEH;;;GAGG;AACU,QAAA,WAAW,GAAG,IAAA,yBAAW,EAAC,sBAAsB,EAAE;IAC7D,MAAM,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,EAAiB,iBAAiB;IACrE,MAAM,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAY,yBAAyB;IAC7E,QAAQ,EAAE,IAAA,kBAAI,EAAC,UAAU,CAAC,EAA0B,2BAA2B;IAC/E,MAAM,EAAE,IAAA,kBAAI,EAAC,SAAS,CAAC,EAA6B,cAAc;IAClE,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;CAC3F,CAAC,CAAC;AAEH;;;GAGG;AACU,QAAA,WAAW,GAAG,IAAA,yBAAW,EAAC,sBAAsB,EAAE;IAC7D,SAAS,EAAE,IAAA,kBAAI,EAAC,WAAW,CAAC,CAAC,UAAU,EAAE,EAAW,QAAQ;IAC5D,MAAM,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAoB,iBAAiB;IACrE,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC;IAC7B,WAAW,EAAE,IAAA,kBAAI,EAAC,cAAc,CAAC;IACjC,UAAU,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAQ,eAAe;IACnE,MAAM,EAAE,IAAA,kBAAI,EAAC,SAAS,CAAC,EAA6B,WAAW;IAC/D,QAAQ,EAAE,IAAA,kBAAI,EAAC,UAAU,CAAC,EAA0B,SAAS;IAC7D,MAAM,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAY,sBAAsB;IAC1E,YAAY,EAAE,IAAA,kBAAI,EAAC,eAAe,CAAC;IACnC,GAAG,EAAE,IAAA,qBAAO,EAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/B,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1F,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;CAC3F,CAAC,CAAC;AAEU,QAAA,SAAS,GAAG,IAAA,yBAAW,EAAC,oBAAoB,EAAE;IACzD,EAAE,EAAE,IAAA,kBAAI,EAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,WAAW,EAAE,IAAA,kBAAI,EAAC,cAAc,CAAC;IACjC,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,QAAQ,EAAE,IAAA,kBAAI,EAAC,WAAW,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAG,2BAA2B;IACzE,SAAS,EAAE,IAAA,kBAAI,EAAC,WAAW,CAAC,CAAC,MAAM,EAAE;IACrC,UAAU,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC;IAC/B,IAAI,EAAE,IAAA,kBAAI,EAAC,MAAM,CAAC,EAA2B,UAAU;IACvD,UAAU,EAAE,IAAA,qBAAO,EAAC,aAAa,CAAC;IAClC,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,EAAiB,qCAAqC;IACnF,gBAAgB,EAAE,IAAA,kBAAI,EAAC,oBAAoB,CAAC,EAAE,6BAA6B;IAC3E,iBAAiB,EAAE,IAAA,kBAAI,EAAC,qBAAqB,CAAC,EAAE,wBAAwB;IACxE,UAAU,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC,EAAe,uCAAuC;IACrF,YAAY,EAAE,IAAA,qBAAO,EAAC,eAAe,CAAC;IACtC,0BAA0B;IAC1B,QAAQ,EAAE,IAAA,kBAAI,EAAC,UAAU,CAAC,EAAoB,QAAQ;IACtD,IAAI,EAAE,IAAA,kBAAI,EAAC,MAAM,CAAC,EAA2B,UAAU;IACvD,OAAO,EAAE,IAAA,kBAAI,EAAC,SAAS,CAAC,EAAqB,WAAW;IACxD,cAAc;IACd,YAAY,EAAE,IAAA,kBAAI,EAAC,cAAc,CAAC,EAAY,oBAAoB;IAClE,QAAQ,EAAE,IAAA,kBAAI,EAAC,UAAU,CAAC,EAAoB,mDAAmD;IACjG,kBAAkB,EAAE,IAAA,kBAAI,EAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAClE,qBAAqB,EAAE,IAAA,qBAAO,EAAC,yBAAyB,CAAC;IACzD,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1F,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1F,QAAQ,EAAE,IAAA,qBAAO,EAAC,WAAW,CAAC;CAC/B,CAAC,CAAC;AAEU,QAAA,YAAY,GAAG,IAAA,yBAAW,EAAC,wBAAwB,EAAE;IAChE,MAAM,EAAE,IAAA,kBAAI,EAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,iBAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACzF,OAAO,EAAE,IAAA,kBAAI,EAAC,UAAU,CAAC,CAAC,OAAO,EAAE;CACpC,CAAC,CAAC;AAEU,QAAA,oBAAoB,GAAG,IAAA,yBAAW,EAAC,iCAAiC,EAAE;IACjF,QAAQ,EAAE,IAAA,kBAAI,EAAC,WAAW,CAAC,CAAC,UAAU,EAAE;IACxC,KAAK,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAC/B,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,WAAW,EAAE,IAAA,kBAAI,EAAC,cAAc,CAAC;IACjC,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;CAC3F,CAAC,CAAC;AAEH;;;GAGG;AACU,QAAA,aAAa,GAAG,IAAA,yBAAW,EAAC,wBAAwB,EAAE;IACjE,EAAE,EAAE,IAAA,kBAAI,EAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE;IAChD,WAAW,EAAE,IAAA,kBAAI,EAAC,cAAc,CAAC,CAAC,OAAO,EAAE,EAAE,6CAA6C;IAC1F,SAAS,EAAE,IAAA,kBAAI,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,MAAM,EAAE,IAAA,kBAAI,EAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,2CAA2C;IAC7E,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1F,SAAS,EAAE,IAAA,qBAAO,EAAC,YAAY,CAAC;CACjC,CAAC,CAAC","sourcesContent":["import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';\n\nexport const accountUsage = sqliteTable('identity_account_usage', {\n accountId: text('account_id').primaryKey(),\n storageBytes: integer('storage_bytes').notNull().default(0),\n ingressBytes: integer('ingress_bytes').notNull().default(0),\n egressBytes: integer('egress_bytes').notNull().default(0),\n storageLimitBytes: integer('storage_limit_bytes'),\n bandwidthLimitBps: integer('bandwidth_limit_bps'),\n computeSeconds: integer('compute_seconds').notNull().default(0),\n tokensUsed: integer('tokens_used').notNull().default(0),\n computeLimitSeconds: integer('compute_limit_seconds'),\n tokenLimitMonthly: integer('token_limit_monthly'),\n periodStart: integer('period_start'),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\nexport const podUsage = sqliteTable('identity_pod_usage', {\n podId: text('pod_id').primaryKey(),\n accountId: text('account_id').notNull(),\n storageUrl: text('storage_url'),\n storageBytes: integer('storage_bytes').notNull().default(0),\n ingressBytes: integer('ingress_bytes').notNull().default(0),\n egressBytes: integer('egress_bytes').notNull().default(0),\n storageLimitBytes: integer('storage_limit_bytes'),\n bandwidthLimitBps: integer('bandwidth_limit_bps'),\n computeSeconds: integer('compute_seconds').notNull().default(0),\n tokensUsed: integer('tokens_used').notNull().default(0),\n computeLimitSeconds: integer('compute_limit_seconds'),\n tokenLimitMonthly: integer('token_limit_monthly'),\n periodStart: integer('period_start'),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * DDNS 域名池表\n * 管理可用的 DDNS 域名\n */\nexport const ddnsDomains = sqliteTable('identity_ddns_domain', {\n domain: text('domain').primaryKey(), // undefineds.xyz\n status: text('status').default('active'), // 'active' | 'suspended'\n provider: text('provider'), // 'cloudflare' | 'tencent'\n zoneId: text('zone_id'), // DNS Zone ID\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * DDNS 记录表\n * 已分配的子域名记录\n */\nexport const ddnsRecords = sqliteTable('identity_ddns_record', {\n subdomain: text('subdomain').primaryKey(), // alice\n domain: text('domain').notNull(), // undefineds.xyz\n ipAddress: text('ip_address'),\n ipv6Address: text('ipv6_address'),\n recordType: text('record_type').default('A'), // 'A' | 'AAAA'\n nodeId: text('node_id'), // 关联的节点 ID\n username: text('username'), // 关联的用户名\n status: text('status').default('active'), // 'active' | 'banned'\n bannedReason: text('banned_reason'),\n ttl: integer('ttl').default(60),\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\nexport const edgeNodes = sqliteTable('identity_edge_node', {\n id: text('id').primaryKey(),\n displayName: text('display_name'),\n tokenHash: text('token_hash').notNull(),\n nodeType: text('node_type').default('edge'), // 'center' | 'edge' | 'sp'\n subdomain: text('subdomain').unique(),\n accessMode: text('access_mode'),\n ipv4: text('ipv4'), // IPv4 地址\n publicPort: integer('public_port'),\n publicUrl: text('public_url'), // SP 的公网地址 (e.g. https://sp.example)\n serviceTokenHash: text('service_token_hash'), // Cloud → SP 回调认证 token (明文)\n provisionCodeHash: text('provision_code_hash'), // bind 时用户传入的配对码 (hash)\n internalIp: text('internal_ip'), // Internal network IP for center nodes\n internalPort: integer('internal_port'),\n // Extracted from metadata\n hostname: text('hostname'), // 节点主机名\n ipv6: text('ipv6'), // IPv6 地址\n version: text('version'), // Agent 版本\n // JSON fields\n capabilities: text('capabilities'), // JSON string: 能力列表\n metadata: text('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)\n connectivityStatus: text('connectivity_status').default('unknown'),\n lastConnectivityCheck: integer('last_connectivity_check'),\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n lastSeen: integer('last_seen'),\n});\n\nexport const edgeNodePods = sqliteTable('identity_edge_node_pod', {\n nodeId: text('node_id').notNull().references(() => edgeNodes.id, { onDelete: 'cascade' }),\n baseUrl: text('base_url').notNull(),\n});\n\nexport const apiClientCredentials = sqliteTable('identity_api_client_credentials', {\n clientId: text('client_id').primaryKey(),\n webId: text('web_id').notNull(),\n accountId: text('account_id').notNull(),\n displayName: text('display_name'),\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * Service Token 表\n * 用于服务间认证 (Business, Local SP, Cloud, Compute)\n */\nexport const serviceTokens = sqliteTable('identity_service_token', {\n id: text('id').primaryKey(),\n tokenHash: text('token_hash').notNull().unique(),\n serviceType: text('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'\n serviceId: text('service_id').notNull(),\n scopes: text('scopes').notNull(), // JSON array: [\"quota:write\",\"usage:read\"]\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n expiresAt: integer('expires_at'),\n});\n"]}
|
|
1
|
+
{"version":3,"file":"schema.sqlite.js","sourceRoot":"","sources":["../../../src/identity/drizzle/schema.sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { sqliteTable, text, integer, primaryKey } from 'drizzle-orm/sqlite-core';\n\nexport const usage = sqliteTable('identity_usage', {\n scopeType: text('scope_type').notNull(), // 'account' | 'pod'\n scopeId: text('scope_id').notNull(),\n accountId: text('account_id').notNull(),\n storageBytes: integer('storage_bytes').notNull().default(0),\n ingressBytes: integer('ingress_bytes').notNull().default(0),\n egressBytes: integer('egress_bytes').notNull().default(0),\n storageLimitBytes: integer('storage_limit_bytes'),\n bandwidthLimitBps: integer('bandwidth_limit_bps'),\n computeSeconds: integer('compute_seconds').notNull().default(0),\n tokensUsed: integer('tokens_used').notNull().default(0),\n computeLimitSeconds: integer('compute_limit_seconds'),\n tokenLimitMonthly: integer('token_limit_monthly'),\n periodStart: integer('period_start'),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n}, (table) => [\n primaryKey({ columns: [ table.scopeType, table.scopeId ] }),\n]);\n\n/**\n * Cloud cluster DDNS 记录表\n * 已分配的子域名记录\n */\nexport const ddnsRecords = sqliteTable('cluster_ddns_record', {\n subdomain: text('subdomain').primaryKey(), // alice\n domain: text('domain').notNull(), // undefineds.xyz\n ipAddress: text('ip_address'),\n ipv6Address: text('ipv6_address'),\n recordType: text('record_type').default('A'), // 'A' | 'AAAA'\n nodeId: text('node_id'), // 关联的节点 ID\n username: text('username'), // 关联的用户名\n status: text('status').default('active'), // 'active' | 'banned'\n bannedReason: text('banned_reason'),\n ttl: integer('ttl').default(60),\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\nexport const edgeNodes = sqliteTable('cluster_node', {\n id: text('id').primaryKey(),\n displayName: text('display_name'),\n tokenHash: text('token_hash').notNull(),\n nodeType: text('node_type').default('edge'), // 'center' | 'edge' | 'sp'\n subdomain: text('subdomain').unique(),\n accessMode: text('access_mode'),\n ipv4: text('ipv4'), // IPv4 地址\n publicPort: integer('public_port'),\n publicUrl: text('public_url'), // SP 的公网地址 (e.g. https://sp.example)\n serviceTokenHash: text('service_token_hash'), // Cloud → SP 回调认证 token (明文)\n provisionCodeHash: text('provision_code_hash'), // bind 时用户传入的配对码 (hash)\n internalIp: text('internal_ip'), // Internal network IP for center nodes\n internalPort: integer('internal_port'),\n // Extracted from metadata\n hostname: text('hostname'), // 节点主机名\n ipv6: text('ipv6'), // IPv6 地址\n version: text('version'), // Agent 版本\n // JSON fields\n capabilities: text('capabilities'), // JSON string: 能力列表\n metadata: text('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)\n podBaseUrls: text('pod_base_urls'), // JSON string: node-owned Pod/storage URL prefixes\n connectivityStatus: text('connectivity_status').default('unknown'),\n lastConnectivityCheck: integer('last_connectivity_check'),\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: integer('updated_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n lastSeen: integer('last_seen'),\n});\n\n/**\n * Cloud cluster Service Token 表\n * 用于服务间认证 (Business, Local SP, Cloud, Compute)\n */\nexport const serviceTokens = sqliteTable('cluster_service_token', {\n id: text('id').primaryKey(),\n tokenHash: text('token_hash').notNull().unique(),\n serviceType: text('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'\n serviceId: text('service_id').notNull(),\n scopes: text('scopes').notNull(), // JSON array: [\"quota:write\",\"usage:read\"]\n createdAt: integer('created_at').notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n expiresAt: integer('expires_at'),\n});\n"]}
|
|
@@ -6,12 +6,14 @@ export interface ScopedPickWebIdHandlerOptions {
|
|
|
6
6
|
webIdStore: WebIdStore;
|
|
7
7
|
providerFactory: ProviderFactory;
|
|
8
8
|
identityDbUrl?: string;
|
|
9
|
+
provisionBaseUrl?: string;
|
|
9
10
|
podLookupRepository?: PodWebIdLookupRepository;
|
|
10
11
|
fetch?: FetchLike;
|
|
11
12
|
}
|
|
12
13
|
export interface PodWebIdLookupRepository {
|
|
13
14
|
findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;
|
|
14
15
|
findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;
|
|
16
|
+
findByWebIds?: (webIds: string[]) => Promise<PodLookupResult[]>;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* CSS-compatible WebID picker scoped to the current storage provider.
|
|
@@ -24,6 +26,7 @@ export declare class ScopedPickWebIdHandler extends JsonInteractionHandler imple
|
|
|
24
26
|
private readonly logger;
|
|
25
27
|
private readonly webIdStore;
|
|
26
28
|
private readonly providerFactory;
|
|
29
|
+
private readonly provisionBaseUrl?;
|
|
27
30
|
private readonly podLookupRepository?;
|
|
28
31
|
private readonly fetch;
|
|
29
32
|
constructor(options: ScopedPickWebIdHandlerOptions);
|
|
@@ -24,6 +24,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
|
|
|
24
24
|
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
25
25
|
this.webIdStore = options.webIdStore;
|
|
26
26
|
this.providerFactory = options.providerFactory;
|
|
27
|
+
this.provisionBaseUrl = normalizeOptionalUrl(options.provisionBaseUrl);
|
|
27
28
|
this.podLookupRepository = options.podLookupRepository ??
|
|
28
29
|
(options.identityDbUrl ? new PodLookupRepository_1.PodLookupRepository((0, db_1.getIdentityDatabase)(options.identityDbUrl)) : undefined);
|
|
29
30
|
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -97,10 +98,16 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
|
|
|
97
98
|
return undefined;
|
|
98
99
|
}
|
|
99
100
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
if (this.podLookupRepository.findAllByWebId) {
|
|
102
|
+
const pods = await this.podLookupRepository.findAllByWebId(webId);
|
|
103
|
+
return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));
|
|
104
|
+
}
|
|
105
|
+
if (this.podLookupRepository.findByWebIds) {
|
|
106
|
+
const pods = await this.podLookupRepository.findByWebIds([webId]);
|
|
107
|
+
return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));
|
|
108
|
+
}
|
|
109
|
+
const pod = await this.podLookupRepository.findByWebId(webId);
|
|
110
|
+
return pod && matchesTargetStorage(pod, targetStorageUrl) ? pod : undefined;
|
|
104
111
|
}
|
|
105
112
|
catch (error) {
|
|
106
113
|
this.logger.warn(`Pod lookup unavailable for WebID ${webId}: ${error}`);
|
|
@@ -112,7 +119,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
|
|
|
112
119
|
if (!provisionCode) {
|
|
113
120
|
return { storageUrl: ensureTrailingSlash(provider.issuer) };
|
|
114
121
|
}
|
|
115
|
-
const payload = new ProvisionCodeCodec_1.ProvisionCodeCodec(provider.issuer).decode(provisionCode);
|
|
122
|
+
const payload = new ProvisionCodeCodec_1.ProvisionCodeCodec(this.provisionBaseUrl ?? provider.issuer).decode(provisionCode);
|
|
116
123
|
if (!payload) {
|
|
117
124
|
throw new community_server_1.BadRequestHttpError('Invalid or expired provisionCode.');
|
|
118
125
|
}
|
|
@@ -187,8 +194,13 @@ function deriveStorageRoot(url) {
|
|
|
187
194
|
function ensureTrailingSlash(url) {
|
|
188
195
|
return url.replace(/\/+$/u, '') + '/';
|
|
189
196
|
}
|
|
197
|
+
function normalizeOptionalUrl(url) {
|
|
198
|
+
const trimmed = url?.trim();
|
|
199
|
+
return trimmed ? trimmed : undefined;
|
|
200
|
+
}
|
|
190
201
|
function matchesTargetStorage(pod, targetStorageUrl) {
|
|
191
|
-
const candidateUrls =
|
|
202
|
+
const candidateUrls = (pod.storageUrl ? [pod.storageUrl] : [pod.baseUrl])
|
|
203
|
+
.filter((value) => typeof value === 'string' && value.length > 0);
|
|
192
204
|
const targetRoot = deriveStorageRoot(targetStorageUrl);
|
|
193
205
|
if (!targetRoot) {
|
|
194
206
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScopedPickWebIdHandler.js","sourceRoot":"","sources":["../../../src/identity/oidc/ScopedPickWebIdHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { boolean, object, string } from 'yup';\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BadRequestHttpError,\n FoundHttpError,\n JsonInteractionHandler,\n assertAccountId,\n assertOidcInteraction,\n finishInteraction,\n forgetWebId,\n parseSchema,\n validateWithError,\n} from '@solid/community-server';\nimport type {\n Json,\n JsonInteractionHandlerInput,\n JsonRepresentation,\n JsonView,\n ProviderFactory,\n WebIdStore,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../drizzle/db';\nimport { PodLookupRepository, type PodLookupResult } from '../drizzle/PodLookupRepository';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst inSchema = object({\n webId: string().trim().required(),\n remember: boolean().default(false),\n});\n\nexport interface ScopedPickWebIdHandlerOptions {\n webIdStore: WebIdStore;\n providerFactory: ProviderFactory;\n identityDbUrl?: string;\n podLookupRepository?: PodWebIdLookupRepository;\n fetch?: FetchLike;\n}\n\nexport interface PodWebIdLookupRepository {\n findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;\n findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;\n}\n\ninterface WebIdEntry extends Record<string, Json | undefined> {\n webId: string;\n storageUrl?: string;\n storageMode?: 'cloud' | 'local' | 'custom';\n}\n\n/**\n * CSS-compatible WebID picker scoped to the current storage provider.\n *\n * The upstream handler lists every WebID linked to the IdP account. In an\n * IDP/SP split flow that lets a Local SP login pick a Cloud Pod again, so this\n * replacement keeps consent choices constrained by the selected SP's Pod facts.\n */\nexport class ScopedPickWebIdHandler extends JsonInteractionHandler implements JsonView {\n private readonly logger = getLoggerFor(this);\n private readonly webIdStore: WebIdStore;\n private readonly providerFactory: ProviderFactory;\n private readonly podLookupRepository?: PodWebIdLookupRepository;\n private readonly fetch: FetchLike;\n\n public constructor(options: ScopedPickWebIdHandlerOptions) {\n super();\n this.webIdStore = options.webIdStore;\n this.providerFactory = options.providerFactory;\n this.podLookupRepository = options.podLookupRepository ??\n (options.identityDbUrl ? new PodLookupRepository(getIdentityDatabase(options.identityDbUrl)) : undefined);\n this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation> {\n assertAccountId(accountId);\n const provider = await this.providerFactory.getProvider();\n const description = parseSchema(inSchema);\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n const entries = await this.resolveScopedEntries(accountId, target);\n\n return {\n json: {\n ...description,\n webIds: entries.map((entry) => entry.webId),\n entries,\n },\n };\n }\n\n public async handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never> {\n assertOidcInteraction(oidcInteraction);\n assertAccountId(accountId);\n const { webId, remember } = await validateWithError(inSchema, json);\n const provider = await this.providerFactory.getProvider();\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n\n if (!await this.webIdStore.isLinked(webId, accountId)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to account ${accountId}`);\n throw new BadRequestHttpError('WebID does not belong to this account.');\n }\n\n if (!await this.isResolvableByCurrentSp(webId, target)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to this storage provider`);\n throw new BadRequestHttpError('WebID does not belong to this storage provider.');\n }\n\n await forgetWebId(provider, oidcInteraction);\n const location = await finishInteraction(oidcInteraction, {\n login: {\n accountId: webId,\n remember,\n },\n }, true);\n throw new FoundHttpError(location);\n }\n\n private async resolveScopedEntries(accountId: string, target: TargetStorage): Promise<WebIdEntry[]> {\n const webIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);\n if (target.serviceToken) {\n return this.resolveRemoteSpEntries(webIds, target);\n }\n\n const entries: WebIdEntry[] = [];\n for (const webId of webIds) {\n const pod = await this.findSpPod(webId, target.storageUrl);\n if (!pod) {\n continue;\n }\n const storageUrl = ensureTrailingSlash(pod.storageUrl ?? pod.baseUrl);\n entries.push({\n webId,\n storageUrl,\n storageMode: deriveStorageMode(webId, storageUrl),\n });\n }\n return entries;\n }\n\n private async isResolvableByCurrentSp(webId: string, target: TargetStorage): Promise<boolean> {\n if (target.serviceToken) {\n return (await this.resolveRemoteSpEntries([webId], target)).some((entry) => entry.webId === webId);\n }\n return Boolean(await this.findSpPod(webId, target.storageUrl));\n }\n\n private async findSpPod(webId: string, targetStorageUrl: string): Promise<PodLookupResult | undefined> {\n if (!this.podLookupRepository) {\n this.logger.warn('No PodLookupRepository configured; refusing to expose unscoped WebID choices');\n return undefined;\n }\n\n try {\n const pods = this.podLookupRepository.findAllByWebId\n ? await this.podLookupRepository.findAllByWebId(webId)\n : await this.podLookupRepository.findByWebId(webId).then((pod) => pod ? [pod] : []);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for WebID ${webId}: ${error}`);\n return undefined;\n }\n }\n\n private async resolveTargetStorage(\n provider: { issuer: string },\n oidcInteraction?: JsonInteractionHandlerInput['oidcInteraction'],\n ): Promise<TargetStorage> {\n const provisionCode = extractProvisionCode(oidcInteraction);\n if (!provisionCode) {\n return { storageUrl: ensureTrailingSlash(provider.issuer) };\n }\n\n const payload = new ProvisionCodeCodec(provider.issuer).decode(provisionCode);\n if (!payload) {\n throw new BadRequestHttpError('Invalid or expired provisionCode.');\n }\n\n const targetUrl = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl;\n return {\n storageUrl: ensureTrailingSlash(targetUrl),\n lookupUrl: ensureTrailingSlash(payload.spUrl),\n serviceToken: payload.serviceToken,\n };\n }\n\n private async resolveRemoteSpEntries(webIds: string[], target: TargetStorage): Promise<WebIdEntry[]> {\n if (!target.lookupUrl || !target.serviceToken || webIds.length === 0) {\n return [];\n }\n\n const response = await this.fetch(new URL('/provision/webids', target.lookupUrl).toString(), {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${target.serviceToken}`,\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n },\n body: JSON.stringify({ webIds }),\n });\n\n if (!response.ok) {\n this.logger.warn(`Remote SP WebID lookup failed: HTTP ${response.status}`);\n return [];\n }\n\n const body = await response.json().catch(() => null) as { entries?: RemoteSpWebIdEntry[] } | null;\n if (!Array.isArray(body?.entries)) {\n return [];\n }\n\n const allowedWebIds = new Set(webIds);\n return body.entries\n .filter((entry) => typeof entry.webId === 'string' && allowedWebIds.has(entry.webId))\n .filter((entry) => typeof entry.storageUrl === 'string' && matchesTargetStorage(\n {\n podId: '',\n accountId: '',\n baseUrl: entry.podUrl ?? entry.storageUrl,\n storageUrl: entry.storageUrl,\n },\n target.storageUrl,\n ))\n .map((entry) => ({\n webId: entry.webId,\n storageUrl: ensureTrailingSlash(entry.storageUrl),\n storageMode: deriveStorageMode(entry.webId, entry.storageUrl),\n }));\n }\n}\n\ninterface TargetStorage {\n storageUrl: string;\n lookupUrl?: string;\n serviceToken?: string;\n}\n\ninterface RemoteSpWebIdEntry {\n webId: string;\n podUrl?: string;\n storageUrl: string;\n}\n\nfunction deriveStorageMode(webId: string, storageUrl: string): 'cloud' | 'local' | 'custom' {\n const webIdRoot = deriveStorageRoot(webId);\n const storageRoot = deriveStorageRoot(storageUrl);\n if (!webIdRoot || !storageRoot) {\n return 'custom';\n }\n return webIdRoot === storageRoot ? 'cloud' : 'local';\n}\n\nfunction deriveStorageRoot(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n const segments = parsed.pathname.split('/').filter(Boolean);\n if (segments.length === 0) {\n return ensureTrailingSlash(parsed.origin);\n }\n\n return ensureTrailingSlash(new URL(`/${segments[0]}/`, parsed.origin).toString());\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.replace(/\\/+$/u, '') + '/';\n}\n\nfunction matchesTargetStorage(pod: PodLookupResult, targetStorageUrl: string): boolean {\n const candidateUrls = [pod.storageUrl, pod.baseUrl].filter((value): value is string => typeof value === 'string' && value.length > 0);\n const targetRoot = deriveStorageRoot(targetStorageUrl);\n if (!targetRoot) {\n return false;\n }\n\n for (const candidate of candidateUrls) {\n const candidateRoot = deriveStorageRoot(candidate);\n if (candidateRoot && candidateRoot === targetRoot) {\n return true;\n }\n\n const candidateUrl = ensureTrailingSlash(candidate);\n if (candidateUrl.startsWith(targetRoot) || targetRoot.startsWith(candidateUrl)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction extractProvisionCode(oidcInteraction: JsonInteractionHandlerInput['oidcInteraction']): string | undefined {\n const params = oidcInteraction?.params as Record<string, unknown> | undefined;\n const value = params?.provisionCode;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ScopedPickWebIdHandler.js","sourceRoot":"","sources":["../../../src/identity/oidc/ScopedPickWebIdHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { boolean, object, string } from 'yup';\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BadRequestHttpError,\n FoundHttpError,\n JsonInteractionHandler,\n assertAccountId,\n assertOidcInteraction,\n finishInteraction,\n forgetWebId,\n parseSchema,\n validateWithError,\n} from '@solid/community-server';\nimport type {\n Json,\n JsonInteractionHandlerInput,\n JsonRepresentation,\n JsonView,\n ProviderFactory,\n WebIdStore,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../drizzle/db';\nimport { PodLookupRepository, type PodLookupResult } from '../drizzle/PodLookupRepository';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst inSchema = object({\n webId: string().trim().required(),\n remember: boolean().default(false),\n});\n\nexport interface ScopedPickWebIdHandlerOptions {\n webIdStore: WebIdStore;\n providerFactory: ProviderFactory;\n identityDbUrl?: string;\n provisionBaseUrl?: string;\n podLookupRepository?: PodWebIdLookupRepository;\n fetch?: FetchLike;\n}\n\nexport interface PodWebIdLookupRepository {\n findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;\n findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;\n findByWebIds?: (webIds: string[]) => Promise<PodLookupResult[]>;\n}\n\ninterface WebIdEntry extends Record<string, Json | undefined> {\n webId: string;\n storageUrl?: string;\n storageMode?: 'cloud' | 'local' | 'custom';\n}\n\n/**\n * CSS-compatible WebID picker scoped to the current storage provider.\n *\n * The upstream handler lists every WebID linked to the IdP account. In an\n * IDP/SP split flow that lets a Local SP login pick a Cloud Pod again, so this\n * replacement keeps consent choices constrained by the selected SP's Pod facts.\n */\nexport class ScopedPickWebIdHandler extends JsonInteractionHandler implements JsonView {\n private readonly logger = getLoggerFor(this);\n private readonly webIdStore: WebIdStore;\n private readonly providerFactory: ProviderFactory;\n private readonly provisionBaseUrl?: string;\n private readonly podLookupRepository?: PodWebIdLookupRepository;\n private readonly fetch: FetchLike;\n\n public constructor(options: ScopedPickWebIdHandlerOptions) {\n super();\n this.webIdStore = options.webIdStore;\n this.providerFactory = options.providerFactory;\n this.provisionBaseUrl = normalizeOptionalUrl(options.provisionBaseUrl);\n this.podLookupRepository = options.podLookupRepository ??\n (options.identityDbUrl ? new PodLookupRepository(getIdentityDatabase(options.identityDbUrl)) : undefined);\n this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation> {\n assertAccountId(accountId);\n const provider = await this.providerFactory.getProvider();\n const description = parseSchema(inSchema);\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n const entries = await this.resolveScopedEntries(accountId, target);\n\n return {\n json: {\n ...description,\n webIds: entries.map((entry) => entry.webId),\n entries,\n },\n };\n }\n\n public async handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never> {\n assertOidcInteraction(oidcInteraction);\n assertAccountId(accountId);\n const { webId, remember } = await validateWithError(inSchema, json);\n const provider = await this.providerFactory.getProvider();\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n\n if (!await this.webIdStore.isLinked(webId, accountId)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to account ${accountId}`);\n throw new BadRequestHttpError('WebID does not belong to this account.');\n }\n\n if (!await this.isResolvableByCurrentSp(webId, target)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to this storage provider`);\n throw new BadRequestHttpError('WebID does not belong to this storage provider.');\n }\n\n await forgetWebId(provider, oidcInteraction);\n const location = await finishInteraction(oidcInteraction, {\n login: {\n accountId: webId,\n remember,\n },\n }, true);\n throw new FoundHttpError(location);\n }\n\n private async resolveScopedEntries(accountId: string, target: TargetStorage): Promise<WebIdEntry[]> {\n const webIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);\n if (target.serviceToken) {\n return this.resolveRemoteSpEntries(webIds, target);\n }\n\n const entries: WebIdEntry[] = [];\n for (const webId of webIds) {\n const pod = await this.findSpPod(webId, target.storageUrl);\n if (!pod) {\n continue;\n }\n const storageUrl = ensureTrailingSlash(pod.storageUrl ?? pod.baseUrl);\n entries.push({\n webId,\n storageUrl,\n storageMode: deriveStorageMode(webId, storageUrl),\n });\n }\n return entries;\n }\n\n private async isResolvableByCurrentSp(webId: string, target: TargetStorage): Promise<boolean> {\n if (target.serviceToken) {\n return (await this.resolveRemoteSpEntries([webId], target)).some((entry) => entry.webId === webId);\n }\n return Boolean(await this.findSpPod(webId, target.storageUrl));\n }\n\n private async findSpPod(webId: string, targetStorageUrl: string): Promise<PodLookupResult | undefined> {\n if (!this.podLookupRepository) {\n this.logger.warn('No PodLookupRepository configured; refusing to expose unscoped WebID choices');\n return undefined;\n }\n\n try {\n if (this.podLookupRepository.findAllByWebId) {\n const pods = await this.podLookupRepository.findAllByWebId(webId);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n if (this.podLookupRepository.findByWebIds) {\n const pods = await this.podLookupRepository.findByWebIds([webId]);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n const pod = await this.podLookupRepository.findByWebId(webId);\n return pod && matchesTargetStorage(pod, targetStorageUrl) ? pod : undefined;\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for WebID ${webId}: ${error}`);\n return undefined;\n }\n }\n\n private async resolveTargetStorage(\n provider: { issuer: string },\n oidcInteraction?: JsonInteractionHandlerInput['oidcInteraction'],\n ): Promise<TargetStorage> {\n const provisionCode = extractProvisionCode(oidcInteraction);\n if (!provisionCode) {\n return { storageUrl: ensureTrailingSlash(provider.issuer) };\n }\n\n const payload = new ProvisionCodeCodec(this.provisionBaseUrl ?? provider.issuer).decode(provisionCode);\n if (!payload) {\n throw new BadRequestHttpError('Invalid or expired provisionCode.');\n }\n\n const targetUrl = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl;\n return {\n storageUrl: ensureTrailingSlash(targetUrl),\n lookupUrl: ensureTrailingSlash(payload.spUrl),\n serviceToken: payload.serviceToken,\n };\n }\n\n private async resolveRemoteSpEntries(webIds: string[], target: TargetStorage): Promise<WebIdEntry[]> {\n if (!target.lookupUrl || !target.serviceToken || webIds.length === 0) {\n return [];\n }\n\n const response = await this.fetch(new URL('/provision/webids', target.lookupUrl).toString(), {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${target.serviceToken}`,\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n },\n body: JSON.stringify({ webIds }),\n });\n\n if (!response.ok) {\n this.logger.warn(`Remote SP WebID lookup failed: HTTP ${response.status}`);\n return [];\n }\n\n const body = await response.json().catch(() => null) as { entries?: RemoteSpWebIdEntry[] } | null;\n if (!Array.isArray(body?.entries)) {\n return [];\n }\n\n const allowedWebIds = new Set(webIds);\n return body.entries\n .filter((entry) => typeof entry.webId === 'string' && allowedWebIds.has(entry.webId))\n .filter((entry) => typeof entry.storageUrl === 'string' && matchesTargetStorage(\n {\n podId: '',\n accountId: '',\n baseUrl: entry.podUrl ?? entry.storageUrl,\n storageUrl: entry.storageUrl,\n },\n target.storageUrl,\n ))\n .map((entry) => ({\n webId: entry.webId,\n storageUrl: ensureTrailingSlash(entry.storageUrl),\n storageMode: deriveStorageMode(entry.webId, entry.storageUrl),\n }));\n }\n}\n\ninterface TargetStorage {\n storageUrl: string;\n lookupUrl?: string;\n serviceToken?: string;\n}\n\ninterface RemoteSpWebIdEntry {\n webId: string;\n podUrl?: string;\n storageUrl: string;\n}\n\nfunction deriveStorageMode(webId: string, storageUrl: string): 'cloud' | 'local' | 'custom' {\n const webIdRoot = deriveStorageRoot(webId);\n const storageRoot = deriveStorageRoot(storageUrl);\n if (!webIdRoot || !storageRoot) {\n return 'custom';\n }\n return webIdRoot === storageRoot ? 'cloud' : 'local';\n}\n\nfunction deriveStorageRoot(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n const segments = parsed.pathname.split('/').filter(Boolean);\n if (segments.length === 0) {\n return ensureTrailingSlash(parsed.origin);\n }\n\n return ensureTrailingSlash(new URL(`/${segments[0]}/`, parsed.origin).toString());\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.replace(/\\/+$/u, '') + '/';\n}\n\nfunction normalizeOptionalUrl(url: string | undefined): string | undefined {\n const trimmed = url?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction matchesTargetStorage(pod: PodLookupResult, targetStorageUrl: string): boolean {\n const candidateUrls = (pod.storageUrl ? [pod.storageUrl] : [pod.baseUrl])\n .filter((value): value is string => typeof value === 'string' && value.length > 0);\n const targetRoot = deriveStorageRoot(targetStorageUrl);\n if (!targetRoot) {\n return false;\n }\n\n for (const candidate of candidateUrls) {\n const candidateRoot = deriveStorageRoot(candidate);\n if (candidateRoot && candidateRoot === targetRoot) {\n return true;\n }\n\n const candidateUrl = ensureTrailingSlash(candidate);\n if (candidateUrl.startsWith(targetRoot) || targetRoot.startsWith(candidateUrl)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction extractProvisionCode(oidcInteraction: JsonInteractionHandlerInput['oidcInteraction']): string | undefined {\n const params = oidcInteraction?.params as Record<string, unknown> | undefined;\n const value = params?.provisionCode;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n"]}
|
|
@@ -35,6 +35,18 @@
|
|
|
35
35
|
]
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_provisionBaseUrl",
|
|
40
|
+
"range": {
|
|
41
|
+
"@type": "ParameterRangeUnion",
|
|
42
|
+
"parameterRangeElements": [
|
|
43
|
+
"xsd:string",
|
|
44
|
+
{
|
|
45
|
+
"@type": "ParameterRangeUndefined"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
38
50
|
{
|
|
39
51
|
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_podLookupRepository",
|
|
40
52
|
"range": {
|
|
@@ -75,6 +87,10 @@
|
|
|
75
87
|
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_providerFactory",
|
|
76
88
|
"memberFieldName": "providerFactory"
|
|
77
89
|
},
|
|
90
|
+
{
|
|
91
|
+
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_provisionBaseUrl",
|
|
92
|
+
"memberFieldName": "provisionBaseUrl"
|
|
93
|
+
},
|
|
78
94
|
{
|
|
79
95
|
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_podLookupRepository",
|
|
80
96
|
"memberFieldName": "podLookupRepository"
|
|
@@ -138,6 +154,12 @@
|
|
|
138
154
|
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_identityDbUrl"
|
|
139
155
|
}
|
|
140
156
|
},
|
|
157
|
+
{
|
|
158
|
+
"keyRaw": "provisionBaseUrl",
|
|
159
|
+
"value": {
|
|
160
|
+
"@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_provisionBaseUrl"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
141
163
|
{
|
|
142
164
|
"keyRaw": "podLookupRepository",
|
|
143
165
|
"value": {
|
|
@@ -12,12 +12,21 @@
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.ProvisionCodeCodec = void 0;
|
|
14
14
|
const node_crypto_1 = require("node:crypto");
|
|
15
|
+
function normalizeProvisionBaseUrl(baseUrl) {
|
|
16
|
+
try {
|
|
17
|
+
return new URL(baseUrl).toString().replace(/\/+$/, '') + '/';
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return baseUrl.trim().replace(/\/+$/, '') + '/';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
15
23
|
class ProvisionCodeCodec {
|
|
16
24
|
/**
|
|
17
25
|
* @param baseUrl — Cloud 的 baseUrl,用于派生签名密钥
|
|
18
26
|
*/
|
|
19
27
|
constructor(baseUrl) {
|
|
20
|
-
|
|
28
|
+
const normalizedBaseUrl = normalizeProvisionBaseUrl(baseUrl);
|
|
29
|
+
this.secret = Buffer.from((0, node_crypto_1.createHmac)('sha256', 'xpod-provision').update(normalizedBaseUrl).digest());
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
32
|
* 编码 provisionCode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProvisionCodeCodec.js","sourceRoot":"","sources":["../../src/provision/ProvisionCodeCodec.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,6CAAyC;AAezC,MAAa,kBAAkB;IAG7B;;OAEG;IACH,YAAmB,OAAe;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CACvB,IAAA,wBAAU,EAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"ProvisionCodeCodec.js","sourceRoot":"","sources":["../../src/provision/ProvisionCodeCodec.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,6CAAyC;AAezC,SAAS,yBAAyB,CAAC,OAAe;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;IAClD,CAAC;AACH,CAAC;AAED,MAAa,kBAAkB;IAG7B;;OAEG;IACH,YAAmB,OAAe;QAChC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CACvB,IAAA,wBAAU,EAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,MAAM,EAAE,CAC1E,CAAC;IACJ,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,OAA6B;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,IAA+B;QAC3C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAErC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAyB,CAAC;YAEpG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC5D,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,OAAO;YACP,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;gBAChD,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,IAAY;QACvB,OAAO,IAAA,wBAAU,EAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5E,CAAC;CACF;AAjED,gDAiEC","sourcesContent":["/**\n * ProvisionCodeCodec\n *\n * 自包含的 provisionCode 编解码器。\n * provisionCode 编码了 SP 的信息(publicUrl、serviceToken),\n * CSS 侧解码后直接回调 SP,不需要查数据库。\n *\n * 格式: base64url(JSON payload) + \".\" + base64url(HMAC-SHA256 signature)\n * 密钥: 从 baseUrl 派生,无需单独配置。\n */\n\nimport { createHmac } from 'node:crypto';\n\nexport interface ProvisionCodePayload {\n /** SP 的公网地址 */\n spUrl: string;\n /** Cloud → SP 回调认证 token */\n serviceToken: string;\n /** SP 节点 ID(可选,用于记录) */\n nodeId?: string;\n /** Cloud 分配的子域名,如 \"abc123.undefineds.site\" */\n spDomain?: string;\n /** 过期时间 (Unix timestamp, seconds) */\n exp: number;\n}\n\nfunction normalizeProvisionBaseUrl(baseUrl: string): string {\n try {\n return new URL(baseUrl).toString().replace(/\\/+$/, '') + '/';\n } catch {\n return baseUrl.trim().replace(/\\/+$/, '') + '/';\n }\n}\n\nexport class ProvisionCodeCodec {\n private readonly secret: Buffer;\n\n /**\n * @param baseUrl — Cloud 的 baseUrl,用于派生签名密钥\n */\n public constructor(baseUrl: string) {\n const normalizedBaseUrl = normalizeProvisionBaseUrl(baseUrl);\n this.secret = Buffer.from(\n createHmac('sha256', 'xpod-provision').update(normalizedBaseUrl).digest(),\n );\n }\n\n /**\n * 编码 provisionCode\n */\n public encode(payload: ProvisionCodePayload): string {\n const json = JSON.stringify(payload);\n const data = Buffer.from(json, 'utf8').toString('base64url');\n const sig = this.sign(data);\n return `${data}.${sig}`;\n }\n\n /**\n * 解码并验证 provisionCode\n * 返回 payload,过期或签名无效则返回 undefined\n */\n public decode(code: string | undefined | null): ProvisionCodePayload | undefined {\n if (typeof code !== 'string' || code.length === 0) {\n return undefined;\n }\n\n const dotIndex = code.indexOf('.');\n if (dotIndex <= 0) {\n return undefined;\n }\n\n const data = code.slice(0, dotIndex);\n const sig = code.slice(dotIndex + 1);\n\n if (this.sign(data) !== sig) {\n return undefined;\n }\n\n try {\n const payload = JSON.parse(Buffer.from(data, 'base64url').toString('utf8')) as ProvisionCodePayload;\n\n if (!payload.spUrl || !payload.serviceToken || !payload.exp) {\n return undefined;\n }\n\n // 检查过期\n if (payload.exp < Math.floor(Date.now() / 1000)) {\n return undefined;\n }\n\n return payload;\n } catch {\n return undefined;\n }\n }\n\n private sign(data: string): string {\n return createHmac('sha256', this.secret).update(data).digest('base64url');\n }\n}\n"]}
|
|
@@ -11,14 +11,20 @@ import { BasePodCreator, type PodCreatorInput, type PodCreatorOutput, type BaseP
|
|
|
11
11
|
export interface ProvisionPodCreatorArgs extends BasePodCreatorArgs {
|
|
12
12
|
/** 与 ProvisionHandler 使用相同的 baseUrl 派生签名密钥 */
|
|
13
13
|
provisionBaseUrl?: string;
|
|
14
|
-
/**
|
|
14
|
+
/** Current SP node id; used to recognize this SP even when URLs differ by localhost/managed domain. */
|
|
15
|
+
nodeId?: string;
|
|
16
|
+
/** Kept in the component signature for config compatibility; Pod storage facts live in CSS account data. */
|
|
15
17
|
identityDbUrl?: string;
|
|
16
18
|
}
|
|
17
19
|
export declare class ProvisionPodCreator extends BasePodCreator {
|
|
18
20
|
private readonly provisionLogger;
|
|
19
21
|
private readonly codec;
|
|
20
|
-
private readonly
|
|
22
|
+
private readonly oidcIssuer?;
|
|
23
|
+
private readonly currentNodeId?;
|
|
21
24
|
constructor(args: ProvisionPodCreatorArgs);
|
|
22
25
|
handle(input: PodCreatorInput): Promise<PodCreatorOutput>;
|
|
26
|
+
private targetsCurrentStorageProvider;
|
|
23
27
|
private handleStandardPodCreate;
|
|
28
|
+
private prepareWebIdLink;
|
|
29
|
+
private findExistingWebIdLink;
|
|
24
30
|
}
|