@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
|
@@ -13,13 +13,41 @@
|
|
|
13
13
|
* GET /provision/status - Local 端 SP 状态查询(公开)
|
|
14
14
|
* 返回 SP 配置状态,供 Linx 查询
|
|
15
15
|
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
16
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
40
|
exports.registerProvisionRoutes = registerProvisionRoutes;
|
|
18
41
|
exports.registerProvisionStatusRoute = registerProvisionStatusRoute;
|
|
42
|
+
exports.createLocalSetupProvisionStateWriter = createLocalSetupProvisionStateWriter;
|
|
43
|
+
const fs = __importStar(require("node:fs"));
|
|
44
|
+
const path = __importStar(require("node:path"));
|
|
45
|
+
const node_crypto_1 = require("node:crypto");
|
|
19
46
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
20
47
|
const ProvisionCodeCodec_1 = require("../../provision/ProvisionCodeCodec");
|
|
21
48
|
/** 默认 24 小时 */
|
|
22
49
|
const DEFAULT_TTL = 24 * 60 * 60;
|
|
50
|
+
const PROVISION_STATUS_REFRESH_GRACE_SECONDS = 5 * 60;
|
|
23
51
|
function registerProvisionRoutes(server, options) {
|
|
24
52
|
const logger = (0, global_logger_factory_1.getLoggerFor)('ProvisionHandler');
|
|
25
53
|
const { repository, baseUrl, baseStorageDomain } = options;
|
|
@@ -32,7 +60,7 @@ function registerProvisionRoutes(server, options) {
|
|
|
32
60
|
*
|
|
33
61
|
* Request:
|
|
34
62
|
* {
|
|
35
|
-
* publicUrl
|
|
63
|
+
* publicUrl?: string,
|
|
36
64
|
* nodeId?: string,
|
|
37
65
|
* displayName?: string,
|
|
38
66
|
* ipv4?: string,
|
|
@@ -55,41 +83,70 @@ function registerProvisionRoutes(server, options) {
|
|
|
55
83
|
sendJson(response, 400, { error: 'Invalid JSON body' });
|
|
56
84
|
return;
|
|
57
85
|
}
|
|
58
|
-
if (!body.publicUrl) {
|
|
59
|
-
sendJson(response, 400, { error: 'publicUrl is required' });
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
new URL(body.publicUrl);
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
sendJson(response, 400, { error: 'Invalid publicUrl format' });
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
86
|
try {
|
|
87
|
+
const domainMode = body.domainMode === 'self-managed' ? 'self-managed' : 'managed';
|
|
88
|
+
const requestedManagedDomain = normalizeRequestedManagedDomain(body.spDomain, baseStorageDomain);
|
|
89
|
+
const shouldAllocateManagedPublicUrl = !body.publicUrl && domainMode === 'managed' && Boolean(baseStorageDomain);
|
|
90
|
+
const preallocatedNodeId = shouldAllocateManagedPublicUrl
|
|
91
|
+
? (body.nodeId ?? (0, node_crypto_1.randomUUID)())
|
|
92
|
+
: undefined;
|
|
93
|
+
const preallocatedSubdomainPrefix = preallocatedNodeId
|
|
94
|
+
? resolveManagedSubdomainPrefix({
|
|
95
|
+
domainMode,
|
|
96
|
+
baseStorageDomain,
|
|
97
|
+
requestedManagedDomain,
|
|
98
|
+
nodeId: preallocatedNodeId,
|
|
99
|
+
})
|
|
100
|
+
: undefined;
|
|
101
|
+
const preallocatedSpDomain = preallocatedSubdomainPrefix
|
|
102
|
+
? `${preallocatedSubdomainPrefix}.${baseStorageDomain}`
|
|
103
|
+
: undefined;
|
|
104
|
+
const effectivePublicUrl = body.publicUrl ?? derivePublicUrlFromSpDomain(preallocatedSpDomain);
|
|
105
|
+
if (!effectivePublicUrl) {
|
|
106
|
+
sendJson(response, 400, { error: 'publicUrl is required' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (preallocatedSubdomainPrefix && baseStorageDomain && options.ddnsRepo) {
|
|
110
|
+
const existing = await options.ddnsRepo.getRecord(preallocatedSubdomainPrefix);
|
|
111
|
+
if (existing?.nodeId && existing.nodeId !== preallocatedNodeId) {
|
|
112
|
+
sendJson(response, 409, {
|
|
113
|
+
error: 'spDomain already allocated',
|
|
114
|
+
spDomain: preallocatedSpDomain,
|
|
115
|
+
});
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
new URL(effectivePublicUrl);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
sendJson(response, 400, { error: 'Invalid publicUrl format' });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
70
126
|
const result = await repository.registerSpNode({
|
|
71
|
-
publicUrl:
|
|
127
|
+
publicUrl: effectivePublicUrl,
|
|
72
128
|
displayName: body.displayName,
|
|
73
|
-
nodeId: body.nodeId,
|
|
129
|
+
nodeId: preallocatedNodeId ?? body.nodeId,
|
|
74
130
|
nodeToken: body.nodeToken,
|
|
75
131
|
serviceToken: body.serviceToken,
|
|
76
132
|
});
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
133
|
+
const subdomainPrefix = preallocatedSubdomainPrefix
|
|
134
|
+
?? resolveManagedSubdomainPrefix({
|
|
135
|
+
domainMode,
|
|
136
|
+
baseStorageDomain,
|
|
137
|
+
requestedManagedDomain,
|
|
138
|
+
nodeId: result.nodeId,
|
|
139
|
+
});
|
|
85
140
|
const spDomain = subdomainPrefix
|
|
86
141
|
? `${subdomainPrefix}.${baseStorageDomain}`
|
|
87
142
|
: undefined;
|
|
143
|
+
const managedPublicUrl = derivePublicUrlFromSpDomain(spDomain);
|
|
144
|
+
const provisionSpUrl = body.publicUrl ?? managedPublicUrl ?? effectivePublicUrl;
|
|
88
145
|
const tunnelState = await ensureManagedTunnelState({
|
|
89
146
|
repository,
|
|
90
147
|
nodeId: result.nodeId,
|
|
91
148
|
subdomainPrefix,
|
|
92
|
-
publicUrl:
|
|
149
|
+
publicUrl: provisionSpUrl,
|
|
93
150
|
localPort: body.localPort,
|
|
94
151
|
ipv4: body.ipv4,
|
|
95
152
|
tunnelToken: body.tunnelToken,
|
|
@@ -107,19 +164,22 @@ function registerProvisionRoutes(server, options) {
|
|
|
107
164
|
}
|
|
108
165
|
// 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)
|
|
109
166
|
const provisionCode = codec.encode({
|
|
110
|
-
spUrl:
|
|
167
|
+
spUrl: provisionSpUrl,
|
|
111
168
|
serviceToken: result.serviceToken,
|
|
112
169
|
nodeId: result.nodeId,
|
|
113
170
|
spDomain,
|
|
114
171
|
exp: Math.floor(Date.now() / 1000) + ttl,
|
|
115
172
|
});
|
|
116
|
-
logger.info(`Registered SP node ${result.nodeId} at ${
|
|
173
|
+
logger.info(`Registered SP node ${result.nodeId} at ${provisionSpUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);
|
|
117
174
|
const responseBody = {
|
|
118
175
|
nodeId: result.nodeId,
|
|
119
176
|
nodeToken: result.nodeToken,
|
|
120
177
|
serviceToken: result.serviceToken,
|
|
121
178
|
provisionCode,
|
|
122
179
|
};
|
|
180
|
+
if (managedPublicUrl) {
|
|
181
|
+
responseBody.publicUrl = managedPublicUrl;
|
|
182
|
+
}
|
|
123
183
|
if (spDomain) {
|
|
124
184
|
responseBody.spDomain = spDomain;
|
|
125
185
|
}
|
|
@@ -222,7 +282,6 @@ async function ensureManagedTunnelState(options) {
|
|
|
222
282
|
localPort,
|
|
223
283
|
configuredAt: new Date().toISOString(),
|
|
224
284
|
},
|
|
225
|
-
publicAddress: tunnelConfig.endpoint || publicUrl,
|
|
226
285
|
});
|
|
227
286
|
return {
|
|
228
287
|
mode,
|
|
@@ -285,7 +344,6 @@ async function ensureManagedTokenTunnelState(options) {
|
|
|
285
344
|
configuredAt: new Date().toISOString(),
|
|
286
345
|
source: 'client-token',
|
|
287
346
|
},
|
|
288
|
-
publicAddress: endpoint || publicUrl,
|
|
289
347
|
});
|
|
290
348
|
return config;
|
|
291
349
|
}
|
|
@@ -344,20 +402,79 @@ function readManagedTunnelConfig(metadata) {
|
|
|
344
402
|
}
|
|
345
403
|
function registerProvisionStatusRoute(server, options) {
|
|
346
404
|
const logger = (0, global_logger_factory_1.getLoggerFor)('ProvisionStatusHandler');
|
|
405
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
406
|
+
const now = options.now ?? (() => Date.now());
|
|
407
|
+
const refreshGraceSeconds = options.refreshGraceSeconds ?? PROVISION_STATUS_REFRESH_GRACE_SECONDS;
|
|
408
|
+
const state = {
|
|
409
|
+
provisionCode: options.provisionCode,
|
|
410
|
+
nodeId: options.nodeId,
|
|
411
|
+
nodeToken: options.nodeToken,
|
|
412
|
+
serviceToken: options.serviceToken,
|
|
413
|
+
publicUrl: normalizeUrl(options.publicUrl),
|
|
414
|
+
spDomain: options.spDomain,
|
|
415
|
+
};
|
|
416
|
+
let refreshPromise;
|
|
347
417
|
server.get('/provision/status', async (_request, response) => {
|
|
348
418
|
const registered = Boolean(options.nodeId && options.cloudUrl);
|
|
349
419
|
const body = {
|
|
350
420
|
registered,
|
|
351
421
|
};
|
|
352
422
|
if (registered) {
|
|
423
|
+
const canRefresh = canRefreshProvisionStatus(options, state);
|
|
424
|
+
const currentNow = now();
|
|
425
|
+
const fresh = isProvisionCodeFresh(state.provisionCode, currentNow, refreshGraceSeconds);
|
|
426
|
+
const codeState = inspectProvisionCodeExpiration(state.provisionCode);
|
|
427
|
+
if (!canRefresh && codeState.kind !== 'missing' && !isProvisionCodeUsable(state.provisionCode, currentNow)) {
|
|
428
|
+
sendJson(response, 503, {
|
|
429
|
+
registered: true,
|
|
430
|
+
error: 'provision_refresh_unavailable',
|
|
431
|
+
message: 'Local provision state is expired and cannot be refreshed. Please restart Local or try again.',
|
|
432
|
+
});
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (canRefresh && !fresh) {
|
|
436
|
+
let didRefresh = false;
|
|
437
|
+
refreshPromise ??= refreshProvisionStatus({
|
|
438
|
+
options,
|
|
439
|
+
state,
|
|
440
|
+
fetchImpl,
|
|
441
|
+
logger,
|
|
442
|
+
}).finally(() => {
|
|
443
|
+
refreshPromise = undefined;
|
|
444
|
+
});
|
|
445
|
+
try {
|
|
446
|
+
await refreshPromise;
|
|
447
|
+
didRefresh = true;
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
logger.warn(`Failed to refresh provisionCode for ${state.nodeId}: ${error}`);
|
|
451
|
+
if (!isProvisionCodeUsable(state.provisionCode, now())) {
|
|
452
|
+
sendJson(response, 503, {
|
|
453
|
+
registered: true,
|
|
454
|
+
error: 'provision_refresh_failed',
|
|
455
|
+
message: 'Local provision state could not be refreshed. Please restart Local or try again.',
|
|
456
|
+
});
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (didRefresh) {
|
|
461
|
+
await persistProvisionStatusState(options, state, logger);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
353
464
|
body.cloudUrl = options.cloudUrl;
|
|
354
|
-
body.nodeId = options.nodeId;
|
|
355
|
-
if (
|
|
356
|
-
body.spDomain =
|
|
465
|
+
body.nodeId = state.nodeId ?? options.nodeId;
|
|
466
|
+
if (state.spDomain) {
|
|
467
|
+
body.spDomain = state.spDomain;
|
|
468
|
+
}
|
|
469
|
+
if (state.publicUrl) {
|
|
470
|
+
body.publicUrl = state.publicUrl;
|
|
471
|
+
}
|
|
472
|
+
if (state.provisionCode) {
|
|
473
|
+
body.provisionCode = state.provisionCode;
|
|
357
474
|
}
|
|
358
475
|
if (options.cloudBaseUrl) {
|
|
359
|
-
const provisionUrl =
|
|
360
|
-
? `${options.cloudBaseUrl.replace(/\/$/, '')}/.account/?provisionCode=${encodeURIComponent(
|
|
476
|
+
const provisionUrl = state.provisionCode
|
|
477
|
+
? `${options.cloudBaseUrl.replace(/\/$/, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`
|
|
361
478
|
: `${options.cloudBaseUrl.replace(/\/$/, '')}/.account/`;
|
|
362
479
|
body.provisionUrl = provisionUrl;
|
|
363
480
|
}
|
|
@@ -366,6 +483,193 @@ function registerProvisionStatusRoute(server, options) {
|
|
|
366
483
|
}, { public: true });
|
|
367
484
|
logger.info('Provision status route registered');
|
|
368
485
|
}
|
|
486
|
+
function createLocalSetupProvisionStateWriter(setupPath, providerId) {
|
|
487
|
+
if (!setupPath?.trim() || !providerId?.trim()) {
|
|
488
|
+
return undefined;
|
|
489
|
+
}
|
|
490
|
+
const targetPath = path.resolve(setupPath);
|
|
491
|
+
const targetProviderId = providerId.trim();
|
|
492
|
+
return async (state) => {
|
|
493
|
+
upsertLocalSetupFile(targetPath, targetProviderId, state);
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
async function persistProvisionStatusState(options, state, logger) {
|
|
497
|
+
if (!options.persistState || !state.nodeId || !state.nodeToken || !state.serviceToken || !state.provisionCode) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
await options.persistState({
|
|
502
|
+
nodeId: state.nodeId,
|
|
503
|
+
nodeToken: state.nodeToken,
|
|
504
|
+
serviceToken: state.serviceToken,
|
|
505
|
+
provisionCode: state.provisionCode,
|
|
506
|
+
publicUrl: state.publicUrl,
|
|
507
|
+
spDomain: state.spDomain,
|
|
508
|
+
cloudUrl: options.cloudUrl,
|
|
509
|
+
cloudBaseUrl: options.cloudBaseUrl,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
logger.warn(`Failed to persist refreshed local provision state: ${error}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
function upsertLocalSetupFile(filePath, providerId, state) {
|
|
517
|
+
const existing = readJsonObjectFile(filePath);
|
|
518
|
+
const previous = readJsonObject(existing[providerId]);
|
|
519
|
+
const cloudIdentityUrl = normalizeUrl(state.cloudBaseUrl);
|
|
520
|
+
const cloudApiUrl = normalizeUrl(state.cloudUrl);
|
|
521
|
+
const provisionUrl = cloudIdentityUrl
|
|
522
|
+
? `${cloudIdentityUrl.replace(/\/+$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`
|
|
523
|
+
: readString(previous.provisionUrl);
|
|
524
|
+
existing[providerId] = {
|
|
525
|
+
...previous,
|
|
526
|
+
nodeId: state.nodeId,
|
|
527
|
+
nodeToken: state.nodeToken,
|
|
528
|
+
serviceToken: state.serviceToken,
|
|
529
|
+
provisionCode: state.provisionCode,
|
|
530
|
+
publicUrl: normalizeUrl(state.publicUrl),
|
|
531
|
+
spDomain: readString(state.spDomain),
|
|
532
|
+
provisionUrl,
|
|
533
|
+
cloudIdentityUrl,
|
|
534
|
+
cloudApiUrl,
|
|
535
|
+
registeredAt: typeof previous.registeredAt === 'number' && Number.isFinite(previous.registeredAt)
|
|
536
|
+
? previous.registeredAt
|
|
537
|
+
: Date.now(),
|
|
538
|
+
};
|
|
539
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
540
|
+
fs.writeFileSync(filePath, `${JSON.stringify(existing, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
541
|
+
try {
|
|
542
|
+
fs.chmodSync(filePath, 0o600);
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
// Some filesystems do not support chmod; the local runtime can still proceed.
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function readJsonObjectFile(filePath) {
|
|
549
|
+
try {
|
|
550
|
+
if (!fs.existsSync(filePath)) {
|
|
551
|
+
return {};
|
|
552
|
+
}
|
|
553
|
+
return readJsonObject(JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
return {};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function readJsonObject(value) {
|
|
560
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
561
|
+
? value
|
|
562
|
+
: {};
|
|
563
|
+
}
|
|
564
|
+
function readString(value) {
|
|
565
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
566
|
+
}
|
|
567
|
+
function canRefreshProvisionStatus(options, state) {
|
|
568
|
+
return Boolean(options.cloudUrl
|
|
569
|
+
&& state.nodeId
|
|
570
|
+
&& state.nodeToken
|
|
571
|
+
&& state.serviceToken
|
|
572
|
+
&& state.publicUrl);
|
|
573
|
+
}
|
|
574
|
+
async function refreshProvisionStatus(options) {
|
|
575
|
+
const { options: statusOptions, state, fetchImpl, logger } = options;
|
|
576
|
+
const endpoint = new URL('/provision/nodes', ensureTrailingSlash(statusOptions.cloudUrl)).toString();
|
|
577
|
+
const requestBody = {
|
|
578
|
+
publicUrl: state.publicUrl,
|
|
579
|
+
nodeId: state.nodeId,
|
|
580
|
+
nodeToken: state.nodeToken,
|
|
581
|
+
serviceToken: state.serviceToken,
|
|
582
|
+
domainMode: state.spDomain ? 'managed' : 'self-managed',
|
|
583
|
+
spDomain: state.spDomain,
|
|
584
|
+
};
|
|
585
|
+
if (statusOptions.localPort && statusOptions.localPort > 0) {
|
|
586
|
+
requestBody.localPort = statusOptions.localPort;
|
|
587
|
+
}
|
|
588
|
+
if (statusOptions.tunnelToken) {
|
|
589
|
+
requestBody.tunnelToken = statusOptions.tunnelToken;
|
|
590
|
+
requestBody.tunnelMode = 'client';
|
|
591
|
+
}
|
|
592
|
+
const result = await fetchImpl(endpoint, {
|
|
593
|
+
method: 'POST',
|
|
594
|
+
headers: {
|
|
595
|
+
Accept: 'application/json',
|
|
596
|
+
'Content-Type': 'application/json',
|
|
597
|
+
},
|
|
598
|
+
body: JSON.stringify(requestBody),
|
|
599
|
+
});
|
|
600
|
+
if (!result.ok) {
|
|
601
|
+
const detail = await result.text().catch(() => '');
|
|
602
|
+
throw new Error(detail || `HTTP ${result.status}`);
|
|
603
|
+
}
|
|
604
|
+
const payload = await result.json().catch(() => undefined);
|
|
605
|
+
if (!payload
|
|
606
|
+
|| typeof payload.nodeId !== 'string'
|
|
607
|
+
|| typeof payload.nodeToken !== 'string'
|
|
608
|
+
|| typeof payload.serviceToken !== 'string'
|
|
609
|
+
|| typeof payload.provisionCode !== 'string') {
|
|
610
|
+
throw new Error('Cloud returned an incomplete provision refresh response.');
|
|
611
|
+
}
|
|
612
|
+
state.nodeId = payload.nodeId;
|
|
613
|
+
state.nodeToken = payload.nodeToken;
|
|
614
|
+
state.serviceToken = payload.serviceToken;
|
|
615
|
+
state.provisionCode = payload.provisionCode;
|
|
616
|
+
state.publicUrl = normalizeUrl(payload.publicUrl) ?? state.publicUrl;
|
|
617
|
+
state.spDomain = typeof payload.spDomain === 'string' ? payload.spDomain : state.spDomain;
|
|
618
|
+
process.env.XPOD_NODE_ID = state.nodeId;
|
|
619
|
+
process.env.XPOD_NODE_TOKEN = state.nodeToken;
|
|
620
|
+
process.env.XPOD_SERVICE_TOKEN = state.serviceToken;
|
|
621
|
+
process.env.XPOD_PROVISION_CODE = state.provisionCode;
|
|
622
|
+
if (statusOptions.cloudBaseUrl) {
|
|
623
|
+
process.env.XPOD_PROVISION_URL = `${statusOptions.cloudBaseUrl.replace(/\/$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`;
|
|
624
|
+
}
|
|
625
|
+
if (state.spDomain) {
|
|
626
|
+
process.env.XPOD_SP_DOMAIN = state.spDomain;
|
|
627
|
+
}
|
|
628
|
+
logger.info(`Refreshed provisionCode for ${state.nodeId}`);
|
|
629
|
+
}
|
|
630
|
+
function isProvisionCodeFresh(code, nowMs, graceSeconds) {
|
|
631
|
+
const state = inspectProvisionCodeExpiration(code);
|
|
632
|
+
return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000) + graceSeconds;
|
|
633
|
+
}
|
|
634
|
+
function isProvisionCodeUsable(code, nowMs) {
|
|
635
|
+
const state = inspectProvisionCodeExpiration(code);
|
|
636
|
+
if (state.kind === 'legacy') {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000);
|
|
640
|
+
}
|
|
641
|
+
function inspectProvisionCodeExpiration(code) {
|
|
642
|
+
if (!code) {
|
|
643
|
+
return { kind: 'missing' };
|
|
644
|
+
}
|
|
645
|
+
const dotIndex = code.indexOf('.');
|
|
646
|
+
if (dotIndex <= 0) {
|
|
647
|
+
return { kind: 'legacy' };
|
|
648
|
+
}
|
|
649
|
+
try {
|
|
650
|
+
const payload = JSON.parse(Buffer.from(code.slice(0, dotIndex), 'base64url').toString('utf8'));
|
|
651
|
+
return typeof payload.exp === 'number' && Number.isFinite(payload.exp)
|
|
652
|
+
? { kind: 'self-contained', expiresAt: payload.exp }
|
|
653
|
+
: { kind: 'invalid' };
|
|
654
|
+
}
|
|
655
|
+
catch {
|
|
656
|
+
return { kind: 'invalid' };
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function ensureTrailingSlash(value) {
|
|
660
|
+
return value.endsWith('/') ? value : `${value}/`;
|
|
661
|
+
}
|
|
662
|
+
function normalizeUrl(value) {
|
|
663
|
+
if (!value?.trim()) {
|
|
664
|
+
return undefined;
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
return new URL(value.trim()).toString().replace(/\/+$/u, '') + '/';
|
|
668
|
+
}
|
|
669
|
+
catch {
|
|
670
|
+
return value.trim().replace(/\/+$/u, '') + '/';
|
|
671
|
+
}
|
|
672
|
+
}
|
|
369
673
|
async function readJsonBody(request) {
|
|
370
674
|
return new Promise((resolve, reject) => {
|
|
371
675
|
let data = '';
|
|
@@ -393,6 +697,9 @@ function sendJson(response, status, data) {
|
|
|
393
697
|
response.setHeader('Content-Type', 'application/json');
|
|
394
698
|
response.end(JSON.stringify(data));
|
|
395
699
|
}
|
|
700
|
+
function derivePublicUrlFromSpDomain(spDomain) {
|
|
701
|
+
return spDomain ? `https://${spDomain}/` : undefined;
|
|
702
|
+
}
|
|
396
703
|
function normalizeRequestedManagedDomain(value, baseStorageDomain) {
|
|
397
704
|
if (!value || !baseStorageDomain) {
|
|
398
705
|
return undefined;
|