@harperfast/harper 5.2.0-beta.4 → 5.2.1
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/bin/backup.ts +169 -0
- package/bin/cliOperations.ts +92 -73
- package/bin/copyDb.ts +21 -4
- package/bin/harper.ts +43 -55
- package/bin/help.ts +216 -0
- package/components/Application.ts +236 -46
- package/components/ApplicationScope.ts +26 -0
- package/components/EntryHandler.ts +410 -105
- package/components/RuntimeModuleTracker.ts +189 -0
- package/components/Scope.ts +120 -30
- package/components/componentLoader.ts +177 -25
- package/components/deployLifecycle.ts +119 -33
- package/components/mcp/toolRegistry.ts +10 -0
- package/components/mcp/tools/application.ts +12 -5
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +3 -0
- package/components/mcp/tools/schemas/operations.ts +9 -0
- package/components/operations.js +5 -6
- package/components/operationsValidation.js +32 -2
- package/components/scopeMount.ts +150 -0
- package/config/configUtils.ts +12 -9
- package/config-root.schema.json +14 -0
- package/dataLayer/backupManifest.ts +102 -0
- package/dataLayer/blobBackup.ts +286 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +69 -5
- package/dataLayer/hdbInfoController.ts +8 -0
- package/dataLayer/restoreMarker.ts +276 -0
- package/dataLayer/rocksdbBackup.ts +1100 -0
- package/dataLayer/schemaDescribe.ts +2 -1
- package/dist/bin/backup.d.ts +9 -0
- package/dist/bin/backup.js +192 -0
- package/dist/bin/backup.js.map +1 -0
- package/dist/bin/cliOperations.d.ts +13 -0
- package/dist/bin/cliOperations.js +89 -70
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.js +13 -2
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/harper.d.ts +13 -0
- package/dist/bin/harper.js +45 -56
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.d.ts +8 -0
- package/dist/bin/help.js +192 -0
- package/dist/bin/help.js.map +1 -0
- package/dist/components/Application.d.ts +16 -1
- package/dist/components/Application.js +210 -38
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +7 -0
- package/dist/components/ApplicationScope.js +22 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.d.ts +4 -4
- package/dist/components/EntryHandler.js +386 -95
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.d.ts +11 -0
- package/dist/components/RuntimeModuleTracker.js +189 -0
- package/dist/components/RuntimeModuleTracker.js.map +1 -0
- package/dist/components/Scope.d.ts +38 -1
- package/dist/components/Scope.js +117 -28
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.d.ts +2 -6
- package/dist/components/componentLoader.js +160 -18
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deployLifecycle.d.ts +6 -2
- package/dist/components/deployLifecycle.js +109 -31
- package/dist/components/deployLifecycle.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +7 -0
- package/dist/components/mcp/toolRegistry.js +10 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/application.js +11 -5
- package/dist/components/mcp/tools/application.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -0
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operations.js +9 -0
- package/dist/components/mcp/tools/schemas/operations.js.map +1 -1
- package/dist/components/operations.js +6 -6
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +34 -2
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/scopeMount.d.ts +86 -0
- package/dist/components/scopeMount.js +131 -0
- package/dist/components/scopeMount.js.map +1 -0
- package/dist/config/configUtils.js +13 -9
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/backupManifest.d.ts +26 -0
- package/dist/dataLayer/backupManifest.js +97 -0
- package/dist/dataLayer/backupManifest.js.map +1 -0
- package/dist/dataLayer/blobBackup.d.ts +87 -0
- package/dist/dataLayer/blobBackup.js +282 -0
- package/dist/dataLayer/blobBackup.js.map +1 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +3 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js +45 -5
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.js +4 -0
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/restoreMarker.d.ts +122 -0
- package/dist/dataLayer/restoreMarker.js +261 -0
- package/dist/dataLayer/restoreMarker.js.map +1 -0
- package/dist/dataLayer/rocksdbBackup.d.ts +127 -0
- package/dist/dataLayer/rocksdbBackup.js +1039 -0
- package/dist/dataLayer/rocksdbBackup.js.map +1 -0
- package/dist/dataLayer/schemaDescribe.js +2 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +55 -0
- package/dist/resources/DatabaseTransaction.js +282 -109
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -5
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Resources.js +22 -4
- package/dist/resources/Resources.js.map +1 -1
- package/dist/resources/Table.d.ts +6 -5
- package/dist/resources/Table.js +114 -37
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/blob.d.ts +8 -1
- package/dist/resources/blob.js +31 -14
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/databases.d.ts +59 -1
- package/dist/resources/databases.js +386 -41
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/jsResource.d.ts +4 -26
- package/dist/resources/jsResource.js +5 -59
- package/dist/resources/jsResource.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -1
- package/dist/resources/models/Models.js +10 -1
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +9 -0
- package/dist/resources/models/backendRegistry.js +10 -0
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/openaiStream.d.ts +16 -1
- package/dist/resources/models/openaiStream.js +113 -21
- package/dist/resources/models/openaiStream.js.map +1 -1
- package/dist/resources/models/v1/chatCompletions.d.ts +54 -0
- package/dist/resources/models/v1/chatCompletions.js +115 -0
- package/dist/resources/models/v1/chatCompletions.js.map +1 -0
- package/dist/resources/models/v1/embeddings.d.ts +11 -0
- package/dist/resources/models/v1/embeddings.js +71 -0
- package/dist/resources/models/v1/embeddings.js.map +1 -0
- package/dist/resources/models/v1/errors.d.ts +54 -0
- package/dist/resources/models/v1/errors.js +130 -0
- package/dist/resources/models/v1/errors.js.map +1 -0
- package/dist/resources/models/v1/index.d.ts +36 -0
- package/dist/resources/models/v1/index.js +75 -0
- package/dist/resources/models/v1/index.js.map +1 -0
- package/dist/resources/models/v1/models.d.ts +26 -0
- package/dist/resources/models/v1/models.js +44 -0
- package/dist/resources/models/v1/models.js.map +1 -0
- package/dist/resources/models/v1/translation.d.ts +133 -0
- package/dist/resources/models/v1/translation.js +298 -0
- package/dist/resources/models/v1/translation.js.map +1 -0
- package/dist/resources/roles.d.ts +1 -1
- package/dist/resources/roles.js +54 -7
- package/dist/resources/roles.js.map +1 -1
- package/dist/resources/transaction.js +0 -3
- package/dist/resources/transaction.js.map +1 -1
- package/dist/security/jsLoader.js +84 -33
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/role.js +4 -0
- package/dist/security/role.js.map +1 -1
- package/dist/security/superUserGuard.d.ts +7 -0
- package/dist/security/superUserGuard.js +23 -0
- package/dist/security/superUserGuard.js.map +1 -0
- package/dist/security/tokenAuthentication.d.ts +0 -1
- package/dist/security/tokenAuthentication.js +6 -2
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.d.ts +6 -1
- package/dist/security/user.js +23 -1
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +25 -9
- package/dist/server/REST.js.map +1 -1
- package/dist/server/fastifyRoutes.js +15 -1
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.d.ts +23 -2
- package/dist/server/http.js +99 -12
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +7 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +20 -1
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobRunner.js +10 -0
- package/dist/server/jobs/jobRunner.js.map +1 -1
- package/dist/server/jobs/jobs.js +11 -0
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/middlewareChain.d.ts +10 -1
- package/dist/server/middlewareChain.js +81 -21
- package/dist/server/middlewareChain.js.map +1 -1
- package/dist/server/operationsServer.d.ts +0 -2
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/multipartParser.js +9 -0
- package/dist/server/serverHelpers/multipartParser.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +2 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +13 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -0
- package/dist/server/serverHelpers/registeredOperations.d.ts +3 -2
- package/dist/server/serverHelpers/registeredOperations.js +14 -13
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +27 -7
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +21 -7
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/static.js +68 -21
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +17 -0
- package/dist/server/storageReclamation.js +90 -6
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/socketRouter.js +20 -0
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +12 -0
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/diff/differential.js +7 -3
- package/dist/sqlEngine/diff/differential.js.map +1 -1
- package/dist/sqlTranslator/index.js +6 -1
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/upgradePrompt.d.ts +2 -2
- package/dist/upgrade/upgradePrompt.js +22 -3
- package/dist/upgrade/upgradePrompt.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +25 -6
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +1 -0
- package/dist/utility/errors/commonErrors.js +1 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +13 -1
- package/dist/utility/hdbTerms.js +13 -1
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/install/installer.js +32 -0
- package/dist/utility/install/installer.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +47 -0
- package/dist/utility/logging/harper_logger.js +803 -38
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/operation_authorization.js +13 -3
- package/dist/utility/operation_authorization.js.map +1 -1
- package/npm-shrinkwrap.json +198 -193
- package/package.json +12 -7
- package/resources/DESIGN.md +2 -0
- package/resources/DatabaseTransaction.ts +310 -104
- package/resources/ResourceInterface.ts +8 -5
- package/resources/Resources.ts +22 -4
- package/resources/Table.ts +341 -263
- package/resources/analytics/write.ts +22 -20
- package/resources/blob.ts +31 -14
- package/resources/databases.ts +387 -46
- package/resources/jsResource.ts +5 -62
- package/resources/models/Models.ts +14 -1
- package/resources/models/backendRegistry.ts +10 -0
- package/resources/models/openaiStream.ts +131 -19
- package/resources/models/v1/chatCompletions.ts +128 -0
- package/resources/models/v1/embeddings.ts +70 -0
- package/resources/models/v1/errors.ts +141 -0
- package/resources/models/v1/index.ts +72 -0
- package/resources/models/v1/models.ts +53 -0
- package/resources/models/v1/translation.ts +362 -0
- package/resources/roles.ts +67 -7
- package/resources/transaction.ts +0 -3
- package/security/jsLoader.ts +84 -30
- package/security/role.ts +7 -0
- package/security/superUserGuard.ts +20 -0
- package/security/tokenAuthentication.ts +6 -3
- package/security/user.ts +26 -1
- package/server/DESIGN.md +61 -34
- package/server/REST.ts +25 -9
- package/server/fastifyRoutes.ts +20 -1
- package/server/http.ts +100 -13
- package/server/itc/serverHandlers.js +7 -1
- package/server/jobs/jobProcess.ts +18 -1
- package/server/jobs/jobRunner.ts +10 -0
- package/server/jobs/jobs.ts +11 -0
- package/server/middlewareChain.ts +79 -20
- package/server/operationsServer.ts +0 -2
- package/server/serverHelpers/multipartParser.ts +9 -0
- package/server/serverHelpers/operationAuthorizationState.ts +11 -0
- package/server/serverHelpers/registeredOperations.ts +19 -15
- package/server/serverHelpers/serverHandlers.js +28 -7
- package/server/serverHelpers/serverUtilities.ts +29 -7
- package/server/static.ts +87 -23
- package/server/storageReclamation.ts +104 -8
- package/server/threads/socketRouter.ts +20 -0
- package/server/threads/threadServer.js +11 -0
- package/sqlTranslator/index.ts +6 -1
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/assets/{Chat-DK3GlWEb.js → Chat-aApwhRmz.js} +2 -2
- package/studio/web/assets/{Chat-DK3GlWEb.js.map → Chat-aApwhRmz.js.map} +1 -1
- package/studio/web/assets/{FloatingChat-fBcC1Ew_.js → FloatingChat-sC0H91n9.js} +4 -4
- package/studio/web/assets/{FloatingChat-fBcC1Ew_.js.map → FloatingChat-sC0H91n9.js.map} +1 -1
- package/studio/web/assets/{apiToken-DJo1nakA.js → apiToken-DZ8JhHOI.js} +2 -2
- package/studio/web/assets/{apiToken-DJo1nakA.js.map → apiToken-DZ8JhHOI.js.map} +1 -1
- package/studio/web/assets/{applications-BDfH8urd.js → applications-9SEVLIO5.js} +2 -2
- package/studio/web/assets/{applications-BDfH8urd.js.map → applications-9SEVLIO5.js.map} +1 -1
- package/studio/web/assets/{index-BHo3c2Gk.js → index-Dy3uDGXb.js} +6 -6
- package/studio/web/assets/index-Dy3uDGXb.js.map +1 -0
- package/studio/web/assets/{index.lazy-BTo0y6UM.js → index.lazy-CN1zq4I4.js} +4 -4
- package/studio/web/assets/{index.lazy-BTo0y6UM.js.map → index.lazy-CN1zq4I4.js.map} +1 -1
- package/studio/web/assets/{notifications-CMxvWNnz.js → notifications-BFAF07xr.js} +2 -2
- package/studio/web/assets/{notifications-CMxvWNnz.js.map → notifications-BFAF07xr.js.map} +1 -1
- package/studio/web/assets/{notifications-D3GoB26g.js → notifications-CKlYVvVN.js} +2 -2
- package/studio/web/assets/{notifications-D3GoB26g.js.map → notifications-CKlYVvVN.js.map} +1 -1
- package/studio/web/assets/{profile-Doj5FVDE.js → profile-A1zhEdFG.js} +2 -2
- package/studio/web/assets/{profile-Doj5FVDE.js.map → profile-A1zhEdFG.js.map} +1 -1
- package/studio/web/assets/{setComponentFile-yinsqJy0.js → setComponentFile-SEtBt_GV.js} +2 -2
- package/studio/web/assets/{setComponentFile-yinsqJy0.js.map → setComponentFile-SEtBt_GV.js.map} +1 -1
- package/studio/web/assets/{setup-DJwR0BHd.js → setup-BisINqdH.js} +2 -2
- package/studio/web/assets/{setup-DJwR0BHd.js.map → setup-BisINqdH.js.map} +1 -1
- package/studio/web/assets/{status-Br_AbsJs.js → status-BuQoCc7l.js} +2 -2
- package/studio/web/assets/{status-Br_AbsJs.js.map → status-BuQoCc7l.js.map} +1 -1
- package/studio/web/assets/{swagger-ui-react-02XH5sVf.js → swagger-ui-react-CAi_s1PC.js} +2 -2
- package/studio/web/assets/{swagger-ui-react-02XH5sVf.js.map → swagger-ui-react-CAi_s1PC.js.map} +1 -1
- package/studio/web/assets/{tsMode-D1DMKY7h.js → tsMode-DT74tlkM.js} +2 -2
- package/studio/web/assets/{tsMode-D1DMKY7h.js.map → tsMode-DT74tlkM.js.map} +1 -1
- package/studio/web/assets/{useEntityRestURL-DtRblRgw.js → useEntityRestURL-CGRGc1n7.js} +2 -2
- package/studio/web/assets/{useEntityRestURL-DtRblRgw.js.map → useEntityRestURL-CGRGc1n7.js.map} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/upgradePrompt.ts +22 -3
- package/utility/OperationFunctionCaller.ts +24 -3
- package/utility/errors/commonErrors.ts +2 -0
- package/utility/hdbTerms.ts +13 -1
- package/utility/install/installer.ts +37 -0
- package/utility/logging/harper_logger.ts +786 -41
- package/utility/operation_authorization.ts +31 -3
- package/studio/web/assets/index-BHo3c2Gk.js.map +0 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstatSync, readFileSync, readlinkSync } from 'node:fs';
|
|
3
|
+
import { lstat, readFile, readlink } from 'node:fs/promises';
|
|
4
|
+
import { createRequire, Module } from 'node:module';
|
|
5
|
+
import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
|
+
|
|
8
|
+
type Source = string | Buffer;
|
|
9
|
+
|
|
10
|
+
const MODULE_COMPARE_CONCURRENCY = 16;
|
|
11
|
+
const RESOLUTION_EXTENSIONS = ['', '.js', '.json', '.node', '.ts', '.tsx', '.cjs', '.mjs'];
|
|
12
|
+
|
|
13
|
+
type Resolution = {
|
|
14
|
+
resolvedUrl: string;
|
|
15
|
+
higherPriorityCandidates?: Map<string, string>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export class RuntimeModuleTracker {
|
|
19
|
+
#getRoot: () => string | undefined;
|
|
20
|
+
#modules = new Map<string, string>();
|
|
21
|
+
#resolutions = new Map<string, Resolution>();
|
|
22
|
+
#nativeRuntime = false;
|
|
23
|
+
#deployInFlight = false;
|
|
24
|
+
#loadedDuringDeploy = false;
|
|
25
|
+
#comparison?: Promise<boolean>;
|
|
26
|
+
|
|
27
|
+
constructor(getRoot: () => string | undefined) {
|
|
28
|
+
this.#getRoot = getRoot;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
beginDeploy(): void {
|
|
32
|
+
if (this.#deployInFlight) return;
|
|
33
|
+
this.#deployInFlight = true;
|
|
34
|
+
this.#loadedDuringDeploy = false;
|
|
35
|
+
this.#comparison = undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
markNativeRuntime(): void {
|
|
39
|
+
this.#nativeRuntime = true;
|
|
40
|
+
if (this.#deployInFlight) this.#loadedDuringDeploy = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
recordModule(moduleUrl: string, source: Source): void {
|
|
44
|
+
const modulePath = this.#localPath(moduleUrl);
|
|
45
|
+
if (!modulePath) return;
|
|
46
|
+
if (!this.#modules.has(modulePath)) this.#modules.set(modulePath, digest(source));
|
|
47
|
+
if (this.#deployInFlight) this.#loadedDuringDeploy = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
recordResolution(specifier: string, referrer: string, resolvedUrl: string): void {
|
|
51
|
+
const referrerPath = this.#localPath(referrer);
|
|
52
|
+
const resolvedPath = this.#localPath(resolvedUrl);
|
|
53
|
+
if (!referrerPath || !resolvedPath) return;
|
|
54
|
+
const key = `${referrerPath}\0${specifier}`;
|
|
55
|
+
if (!this.#resolutions.has(key)) {
|
|
56
|
+
const candidates = higherPriorityResolutionCandidates(specifier, referrerPath, resolvedPath);
|
|
57
|
+
this.#resolutions.set(key, {
|
|
58
|
+
resolvedUrl,
|
|
59
|
+
higherPriorityCandidates: candidates
|
|
60
|
+
? new Map(candidates.map((candidate) => [candidate, candidateState(candidate)]))
|
|
61
|
+
: undefined,
|
|
62
|
+
});
|
|
63
|
+
if (this.#deployInFlight) this.#loadedDuringDeploy = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
finishDeploy(): Promise<boolean> {
|
|
68
|
+
if (!this.#deployInFlight) return this.#comparison ?? Promise.resolve(false);
|
|
69
|
+
this.#deployInFlight = false;
|
|
70
|
+
this.#comparison = this.#compare();
|
|
71
|
+
return this.#comparison;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async #compare(): Promise<boolean> {
|
|
75
|
+
if (this.#nativeRuntime || this.#loadedDuringDeploy) return true;
|
|
76
|
+
const modules = [...this.#modules];
|
|
77
|
+
for (let start = 0; start < modules.length; start += MODULE_COMPARE_CONCURRENCY) {
|
|
78
|
+
const changed = await Promise.all(
|
|
79
|
+
modules.slice(start, start + MODULE_COMPARE_CONCURRENCY).map(async ([modulePath, previousDigest]) => {
|
|
80
|
+
try {
|
|
81
|
+
return digest(await readFile(modulePath)) !== previousDigest;
|
|
82
|
+
} catch {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
if (changed.includes(true)) return true;
|
|
88
|
+
}
|
|
89
|
+
for (const [key, resolution] of this.#resolutions) {
|
|
90
|
+
const separator = key.indexOf('\0');
|
|
91
|
+
const referrerPath = key.slice(0, separator);
|
|
92
|
+
const specifier = key.slice(separator + 1);
|
|
93
|
+
if (
|
|
94
|
+
resolution.higherPriorityCandidates &&
|
|
95
|
+
(
|
|
96
|
+
await Promise.all(
|
|
97
|
+
[...resolution.higherPriorityCandidates].map(
|
|
98
|
+
async ([candidate, previousState]) => (await candidateStateAsync(candidate)) !== previousState
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
).includes(true)
|
|
102
|
+
)
|
|
103
|
+
return true;
|
|
104
|
+
try {
|
|
105
|
+
// Node does not invalidate this cache when a component tree is replaced in place.
|
|
106
|
+
if (!invalidateResolutionCache(specifier, referrerPath, resolution.resolvedUrl)) return true;
|
|
107
|
+
const resolved = createRequire(pathToFileURL(referrerPath)).resolve(specifier);
|
|
108
|
+
const resolvedUrl = isAbsolute(resolved) ? pathToFileURL(resolved).toString() : resolved;
|
|
109
|
+
if (resolvedUrl !== resolution.resolvedUrl) return true;
|
|
110
|
+
} catch {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#localPath(moduleUrl: string): string | undefined {
|
|
118
|
+
if (!moduleUrl.startsWith('file:')) return;
|
|
119
|
+
const root = this.#getRoot();
|
|
120
|
+
if (!root) return;
|
|
121
|
+
const modulePath = fileURLToPath(moduleUrl);
|
|
122
|
+
const relativePath = relative(resolve(root), modulePath);
|
|
123
|
+
if (
|
|
124
|
+
relativePath === '' ||
|
|
125
|
+
(!relativePath.startsWith(`..${sep}`) && relativePath !== '..' && !isAbsolute(relativePath))
|
|
126
|
+
)
|
|
127
|
+
return modulePath;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function higherPriorityResolutionCandidates(
|
|
132
|
+
specifier: string,
|
|
133
|
+
referrerPath: string,
|
|
134
|
+
resolvedPath: string
|
|
135
|
+
): string[] | undefined {
|
|
136
|
+
if (!specifier.startsWith('.')) return;
|
|
137
|
+
const basePath = resolve(dirname(referrerPath), specifier);
|
|
138
|
+
const candidates = [...new Set(RESOLUTION_EXTENSIONS.map((extension) => basePath + extension))];
|
|
139
|
+
candidates.push(resolve(basePath, 'package.json'));
|
|
140
|
+
for (const extension of RESOLUTION_EXTENSIONS.slice(1)) candidates.push(resolve(basePath, `index${extension}`));
|
|
141
|
+
const resolvedIndex = candidates.indexOf(resolvedPath);
|
|
142
|
+
if (resolvedIndex === -1) return;
|
|
143
|
+
return candidates.slice(0, resolvedIndex);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function candidateState(path: string): string {
|
|
147
|
+
try {
|
|
148
|
+
const stats = lstatSync(path);
|
|
149
|
+
if (stats.isSymbolicLink()) return `link:${readlinkSync(path)}`;
|
|
150
|
+
if (stats.isDirectory()) return 'directory';
|
|
151
|
+
if (!stats.isFile()) return 'other';
|
|
152
|
+
return path.endsWith('package.json') ? `file:${digest(readFileSync(path))}` : 'file';
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';
|
|
155
|
+
return `error:${(error as NodeJS.ErrnoException).code ?? 'unknown'}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function candidateStateAsync(path: string): Promise<string> {
|
|
160
|
+
try {
|
|
161
|
+
const stats = await lstat(path);
|
|
162
|
+
if (stats.isSymbolicLink()) return `link:${await readlink(path)}`;
|
|
163
|
+
if (stats.isDirectory()) return 'directory';
|
|
164
|
+
if (!stats.isFile()) return 'other';
|
|
165
|
+
return path.endsWith('package.json') ? `file:${digest(await readFile(path))}` : 'file';
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';
|
|
168
|
+
return `error:${(error as NodeJS.ErrnoException).code ?? 'unknown'}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function invalidateResolutionCache(specifier: string, referrerPath: string, previousResolvedUrl: string): boolean {
|
|
173
|
+
const pathCache = (Module as unknown as { _pathCache?: Record<string, string> })._pathCache;
|
|
174
|
+
if (!pathCache) return false;
|
|
175
|
+
const previousPath = previousResolvedUrl.startsWith('file:')
|
|
176
|
+
? fileURLToPath(previousResolvedUrl)
|
|
177
|
+
: previousResolvedUrl;
|
|
178
|
+
const relativeKey = `${specifier}\0${dirname(referrerPath)}`;
|
|
179
|
+
if (pathCache[relativeKey] === previousPath) delete pathCache[relativeKey];
|
|
180
|
+
if (specifier.startsWith('.')) return true;
|
|
181
|
+
for (const cacheKey of Object.keys(pathCache)) {
|
|
182
|
+
if (cacheKey.startsWith(`${specifier}\0`) && pathCache[cacheKey] === previousPath) delete pathCache[cacheKey];
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function digest(source: Source): string {
|
|
188
|
+
return createHash('sha256').update(source).digest('base64');
|
|
189
|
+
}
|
package/components/Scope.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { FileAndURLPathConfig } from './Component.ts';
|
|
|
11
11
|
import { FilesOption } from './deriveGlobOptions.ts';
|
|
12
12
|
import { requestRestart } from './requestRestart.ts';
|
|
13
13
|
import { resolveBaseURLPath } from './resolveBaseURLPath.ts';
|
|
14
|
+
import { composeMountedUrlPath, type ScopeMount } from './scopeMount.ts';
|
|
14
15
|
import { ApplicationScope } from './ApplicationScope.ts';
|
|
15
16
|
import {
|
|
16
17
|
getSecretsForComponent,
|
|
@@ -37,8 +38,10 @@ export type ScopeEventsMap = {
|
|
|
37
38
|
// file-driven work to avoid acting on intermediate states.
|
|
38
39
|
'deploy:start': [componentName: string];
|
|
39
40
|
// Fired after deploy I/O completes (success or failure). The scope's
|
|
40
|
-
// EntryHandlers have been
|
|
41
|
-
//
|
|
41
|
+
// EntryHandlers have been resumed by this point; their replacement watcher
|
|
42
|
+
// generation compares the post-deploy scan with the retained pre-deploy
|
|
43
|
+
// snapshot, so subsequent events are the logical differences of that tree,
|
|
44
|
+
// not a replay of every surviving file as an `add`.
|
|
42
45
|
'deploy:end': [componentName: string];
|
|
43
46
|
[record: string]: [...args: unknown[]];
|
|
44
47
|
};
|
|
@@ -63,11 +66,8 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
63
66
|
#pendingInitialLoads: Set<Promise<void>>;
|
|
64
67
|
#deployStartHandler: (name: string) => void;
|
|
65
68
|
#deployEndHandler: (name: string) => void;
|
|
66
|
-
// While a deploy of this component is in flight, EntryHandler events do not
|
|
67
|
-
// drive requestRestart() — the deploy itself produces hundreds of file
|
|
68
|
-
// changes that would otherwise pile up. A single coalesced restart is
|
|
69
|
-
// triggered by the post-deploy re-scan instead.
|
|
70
69
|
#deployInFlight: boolean = false;
|
|
70
|
+
#restartRequestedDuringDeploy: boolean = false;
|
|
71
71
|
applicationScope?: ApplicationScope;
|
|
72
72
|
|
|
73
73
|
options: OptionsWatcher;
|
|
@@ -81,6 +81,18 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
81
81
|
// process-global side effects should validate fully but skip activation.
|
|
82
82
|
isTransientValidation?: boolean;
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Routing the operator declared for this application in the root config. Applied automatically
|
|
86
|
+
* to handlers registered through `scope.server`, so plugins normally don't touch it — the
|
|
87
|
+
* router strips the mount before a handler runs and everything inside the application
|
|
88
|
+
* addresses itself mount-relative.
|
|
89
|
+
*
|
|
90
|
+
* Read it only when a plugin emits an absolute URL back to the client (e.g. a redirect
|
|
91
|
+
* `Location`, via `externalBasePath()`) or bypasses the routed chain entirely (legacy
|
|
92
|
+
* fastify routes register on the bare server).
|
|
93
|
+
*/
|
|
94
|
+
mount?: ScopeMount;
|
|
95
|
+
|
|
84
96
|
constructor(
|
|
85
97
|
appName: string,
|
|
86
98
|
pluginName: string,
|
|
@@ -88,16 +100,19 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
88
100
|
configFilePath: string,
|
|
89
101
|
applicationScope: ApplicationScope,
|
|
90
102
|
origin: string = appName,
|
|
91
|
-
isRootConfig?: boolean
|
|
103
|
+
isRootConfig?: boolean,
|
|
104
|
+
mount?: ScopeMount
|
|
92
105
|
) {
|
|
93
106
|
super();
|
|
94
107
|
|
|
108
|
+
this.mount = mount;
|
|
95
109
|
this.#appName = appName;
|
|
96
110
|
this.#pluginName = pluginName;
|
|
97
111
|
this.#origin = typeof origin === 'string' ? origin : appName;
|
|
98
112
|
this.#directory = directory;
|
|
99
113
|
this.#configFilePath = configFilePath;
|
|
100
114
|
this.#logger = loggerWithTag(this.#appName);
|
|
115
|
+
this.#deployInFlight = deployLifecycle.isDeployInFlight(this.#appName);
|
|
101
116
|
|
|
102
117
|
this.databaseEvents = databaseEventsEmitter;
|
|
103
118
|
this.applicationScope = applicationScope;
|
|
@@ -117,14 +132,10 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
117
132
|
const method = Reflect.get(target, prop, receiver);
|
|
118
133
|
if (typeof method === 'function') {
|
|
119
134
|
return (listener: any, options?: any) => {
|
|
120
|
-
const scopeConfig = (scopeRef.options?.getAll() as any) ?? {};
|
|
121
135
|
return method.call(target, listener, {
|
|
122
136
|
name: pluginName,
|
|
123
|
-
// resolve to the same base the entry pipeline uses ('assets' -> '/assets/',
|
|
124
|
-
// './x' -> '/<name>/x/') so route matching sees a real pathname prefix (#1583)
|
|
125
|
-
urlPath: scopeConfig.urlPath ? resolveBaseURLPath(pluginName, scopeConfig.urlPath) : undefined,
|
|
126
|
-
host: scopeConfig.host || undefined,
|
|
127
137
|
...options,
|
|
138
|
+
...scopeRef.routeFor(options),
|
|
128
139
|
});
|
|
129
140
|
};
|
|
130
141
|
}
|
|
@@ -145,6 +156,7 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
145
156
|
this.options = new OptionsWatcher(pluginName, configFilePath, this.#logger, isRootConfig)
|
|
146
157
|
.on('error', this.#handleError.bind(this))
|
|
147
158
|
.on('change', this.#optionsWatcherChangeListener.bind(this)())
|
|
159
|
+
.on('remove', this.#optionsWatcherRemoveListener())
|
|
148
160
|
.on('ready', this.#handleOptionsWatcherReady.bind(this));
|
|
149
161
|
|
|
150
162
|
// Bridge cross-thread deploy lifecycle events for this component. The
|
|
@@ -184,6 +196,41 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
184
196
|
return this.#pluginName;
|
|
185
197
|
}
|
|
186
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Turns a mount-relative base path into the absolute path a client sees, by prefixing the
|
|
201
|
+
* application's mount. Use it for anything sent back to the client — a redirect `Location`, a
|
|
202
|
+
* generated link — since the router strips the mount before a handler runs and a handler's own
|
|
203
|
+
* view of the path therefore excludes it.
|
|
204
|
+
*/
|
|
205
|
+
externalBasePath(baseURLPath: string): string {
|
|
206
|
+
return this.mount?.urlPath ? `${this.mount.urlPath}${baseURLPath}` : baseURLPath;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* The route a handler registered through `scope.server` with these options will answer on — the
|
|
211
|
+
* single place the application mount is applied. `scope.server` uses it, and a plugin that must
|
|
212
|
+
* identify its own route (e.g. REST deduplicating registration per mount) calls it rather than
|
|
213
|
+
* recomposing the parts, so there is one definition of "which route is this".
|
|
214
|
+
*
|
|
215
|
+
* An explicit call option wins over config, but either way `urlPath` is *resolved* rather than
|
|
216
|
+
* passed through: plugins that spread their whole config section into these options (REST does)
|
|
217
|
+
* would otherwise hand the router a raw value — './' became the literal, unmatchable route '/.'.
|
|
218
|
+
*/
|
|
219
|
+
routeFor(options?: { urlPath?: string; host?: string }): { host?: string; urlPath?: string } {
|
|
220
|
+
const scopeConfig = (this.options?.getAll() as any) ?? {};
|
|
221
|
+
const rawUrlPath = options?.urlPath ?? scopeConfig.urlPath;
|
|
222
|
+
// resolve to the same base the entry pipeline uses ('assets' -> '/assets/', './x' ->
|
|
223
|
+
// '/<name>/x/') so route matching sees a real pathname prefix (#1583), then prefix the
|
|
224
|
+
// application's mount. The mount is applied ONLY here, at the routing boundary: the router
|
|
225
|
+
// strips it before the handler runs, so entry URL paths — and the resource paths
|
|
226
|
+
// graphqlSchema/jsResource derive from them — stay mount-relative.
|
|
227
|
+
const pluginUrlPath = rawUrlPath ? resolveBaseURLPath(this.#pluginName, rawUrlPath) : undefined;
|
|
228
|
+
return {
|
|
229
|
+
host: this.mount?.host || options?.host || scopeConfig.host || undefined,
|
|
230
|
+
urlPath: composeMountedUrlPath(this.mount?.urlPath, this.#pluginName, pluginUrlPath) || undefined,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
187
234
|
get directory(): string {
|
|
188
235
|
return this.#directory;
|
|
189
236
|
}
|
|
@@ -208,7 +255,8 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
208
255
|
}
|
|
209
256
|
|
|
210
257
|
#handleError(error: unknown): void {
|
|
211
|
-
this.emit('error', error);
|
|
258
|
+
if (this.listenerCount('error') > 0) this.emit('error', error);
|
|
259
|
+
else this.#logger.error?.('Error in component scope:', error);
|
|
212
260
|
}
|
|
213
261
|
|
|
214
262
|
async close(): Promise<this> {
|
|
@@ -255,6 +303,8 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
255
303
|
|
|
256
304
|
#onDeployStart(componentName: string): void {
|
|
257
305
|
this.#deployInFlight = true;
|
|
306
|
+
this.#restartRequestedDuringDeploy = false;
|
|
307
|
+
this.applicationScope?.beginDeploy();
|
|
258
308
|
// Pause each EntryHandler so it stops emitting events for the
|
|
259
309
|
// intermediate filesystem state the deploy is writing, and so it
|
|
260
310
|
// releases its inotify handles while npm install is unpacking
|
|
@@ -269,25 +319,27 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
269
319
|
|
|
270
320
|
#onDeployEnd(componentName: string): void {
|
|
271
321
|
this.#deployInFlight = false;
|
|
322
|
+
const restartRequestedDuringDeploy = this.#restartRequestedDuringDeploy;
|
|
323
|
+
this.#restartRequestedDuringDeploy = false;
|
|
272
324
|
|
|
273
|
-
// Resume
|
|
274
|
-
// throwing in its deploy:end handler would abort this function and
|
|
275
|
-
// leave the watchers permanently paused (surfaced by Gemini review).
|
|
276
|
-
// The fresh chokidar watcher does an initial scan and emits add events
|
|
277
|
-
// for the post-deploy tree; the existing per-event listener calls
|
|
278
|
-
// scope.requestRestart() for each, and the restart debounce in
|
|
279
|
-
// componentLoader collapses them into a single restart cycle. Plugin
|
|
280
|
-
// handlers stay attached across the pause.
|
|
325
|
+
// Resume before notifying plugins so a throwing deploy:end listener cannot strand the watchers.
|
|
281
326
|
for (const entryHandler of this.#entryHandlers) {
|
|
282
|
-
void entryHandler.resume();
|
|
327
|
+
void entryHandler.resume().catch(() => {});
|
|
283
328
|
}
|
|
329
|
+
if (restartRequestedDuringDeploy) this.requestRestart();
|
|
330
|
+
void this.applicationScope
|
|
331
|
+
?.finishDeploy()
|
|
332
|
+
.then((runtimeChanged) => {
|
|
333
|
+
if (runtimeChanged) this.requestRestart();
|
|
334
|
+
})
|
|
335
|
+
.catch((error) => {
|
|
336
|
+
this.#logger.error?.(`Could not verify the loaded runtime after deploying ${this.#appName}:`, error);
|
|
337
|
+
this.requestRestart();
|
|
338
|
+
});
|
|
284
339
|
|
|
285
340
|
this.#safeEmit('deploy:end', componentName);
|
|
286
341
|
}
|
|
287
342
|
|
|
288
|
-
// Swallow and log listener exceptions so one buggy plugin can't stop us
|
|
289
|
-
// from running the rest of the deploy-lifecycle bookkeeping. EventEmitter
|
|
290
|
-
// by default rethrows from synchronous listeners.
|
|
291
343
|
#safeEmit(event: 'deploy:start' | 'deploy:end', componentName: string): void {
|
|
292
344
|
try {
|
|
293
345
|
this.emit(event, componentName);
|
|
@@ -304,6 +356,7 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
304
356
|
.on('unlink', this.#defaultEntryHandlerListener('unlink'))
|
|
305
357
|
.on('addDir', this.#defaultEntryHandlerListener('addDir'))
|
|
306
358
|
.on('unlinkDir', this.#defaultEntryHandlerListener('unlinkDir'));
|
|
359
|
+
if (this.#deployInFlight) entryHandler.pause();
|
|
307
360
|
|
|
308
361
|
this.#entryHandlers.push(entryHandler);
|
|
309
362
|
|
|
@@ -345,8 +398,7 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
345
398
|
return;
|
|
346
399
|
}
|
|
347
400
|
|
|
348
|
-
|
|
349
|
-
scope.#entryHandler.update(config as FileAndURLPathConfig);
|
|
401
|
+
void scope.#entryHandler.update(config as FileAndURLPathConfig).catch(() => {});
|
|
350
402
|
|
|
351
403
|
return;
|
|
352
404
|
}
|
|
@@ -361,6 +413,23 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
361
413
|
};
|
|
362
414
|
}
|
|
363
415
|
|
|
416
|
+
#optionsWatcherRemoveListener() {
|
|
417
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
418
|
+
const scope = this;
|
|
419
|
+
// Deleting a component's config block emits `remove` (not `change`), so without
|
|
420
|
+
// this listener a running component keeps serving until some unrelated restart —
|
|
421
|
+
// even though absence is the canonical disabled state for opt-in built-ins like
|
|
422
|
+
// the /v1 models gateway. Mirrors the change listener: a plugin that registers
|
|
423
|
+
// its own `remove` handler owns the response and no restart is requested.
|
|
424
|
+
return function handleOptionsWatcherRemove(this: OptionsWatcher) {
|
|
425
|
+
if (this.listenerCount('remove') > 1) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
scope.#logger.debug?.('Options removed, requesting restart');
|
|
429
|
+
scope.requestRestart();
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
364
433
|
#getFilesOption(): FileAndURLPathConfig | undefined {
|
|
365
434
|
const config = this.options.getAll();
|
|
366
435
|
if (
|
|
@@ -474,9 +543,7 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
474
543
|
|
|
475
544
|
requestRestart() {
|
|
476
545
|
if (this.#deployInFlight) {
|
|
477
|
-
|
|
478
|
-
// post-deploy re-scan in #onDeployEnd will trigger the coalesced
|
|
479
|
-
// restart instead.
|
|
546
|
+
this.#restartRequestedDuringDeploy = true;
|
|
480
547
|
this.#logger.debug?.(`Restart suppressed (deploy in flight) for ${this.#appName}`);
|
|
481
548
|
return;
|
|
482
549
|
}
|
|
@@ -495,6 +562,29 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
|
495
562
|
}
|
|
496
563
|
}
|
|
497
564
|
|
|
565
|
+
waitForDeployCompletion(timeoutMs = 6 * 60 * 60 * 1000): Promise<void> {
|
|
566
|
+
if (!this.#deployInFlight) return Promise.resolve();
|
|
567
|
+
return new Promise((resolve, reject) => {
|
|
568
|
+
const timer = setTimeout(() => {
|
|
569
|
+
deployLifecycle.off('deploy:end', handleDeployEnd);
|
|
570
|
+
reject(new Error(`Timed out waiting for deployment of ${this.#appName} to complete`));
|
|
571
|
+
}, timeoutMs);
|
|
572
|
+
timer.unref?.();
|
|
573
|
+
const handleDeployEnd = (componentName: string) => {
|
|
574
|
+
if (componentName !== this.#appName || this.#deployInFlight) return;
|
|
575
|
+
deployLifecycle.off('deploy:end', handleDeployEnd);
|
|
576
|
+
clearTimeout(timer);
|
|
577
|
+
resolve();
|
|
578
|
+
};
|
|
579
|
+
deployLifecycle.on('deploy:end', handleDeployEnd);
|
|
580
|
+
if (!this.#deployInFlight) {
|
|
581
|
+
deployLifecycle.off('deploy:end', handleDeployEnd);
|
|
582
|
+
clearTimeout(timer);
|
|
583
|
+
resolve();
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
498
588
|
/**
|
|
499
589
|
* Import a file into the scope's sandbox.
|
|
500
590
|
* @param filePath - The path of the file to import.
|