@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.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/BinObjects.js +17 -0
- package/bin/cliOperations.js +157 -0
- package/bin/copyDb.ts +280 -0
- package/bin/harper.js +156 -0
- package/bin/install.js +15 -0
- package/bin/lite.js +5 -0
- package/bin/restart.js +201 -0
- package/bin/run.js +409 -0
- package/bin/status.js +65 -0
- package/bin/stop.js +22 -0
- package/bin/upgrade.js +134 -0
- package/components/Application.ts +646 -0
- package/components/ApplicationScope.ts +49 -0
- package/components/Component.ts +53 -0
- package/components/ComponentV1.ts +342 -0
- package/components/DEFAULT_CONFIG.ts +18 -0
- package/components/EntryHandler.ts +227 -0
- package/components/Logger.ts +14 -0
- package/components/OptionsWatcher.ts +354 -0
- package/components/PluginModule.ts +6 -0
- package/components/Scope.ts +329 -0
- package/components/componentLoader.ts +529 -0
- package/components/deriveCommonPatternBase.ts +31 -0
- package/components/deriveGlobOptions.ts +44 -0
- package/components/deriveURLPath.ts +57 -0
- package/components/operations.js +658 -0
- package/components/operationsValidation.js +246 -0
- package/components/packageComponent.ts +39 -0
- package/components/requestRestart.ts +26 -0
- package/components/resolveBaseURLPath.ts +38 -0
- package/components/status/ComponentStatus.ts +110 -0
- package/components/status/ComponentStatusRegistry.ts +251 -0
- package/components/status/api.ts +153 -0
- package/components/status/crossThread.ts +405 -0
- package/components/status/errors.ts +152 -0
- package/components/status/index.ts +44 -0
- package/components/status/internal.ts +65 -0
- package/components/status/registry.ts +12 -0
- package/components/status/types.ts +96 -0
- package/config/RootConfigWatcher.ts +59 -0
- package/config/configHelpers.ts +11 -0
- package/config/configUtils.js +967 -0
- package/config/harperConfigEnvVars.ts +641 -0
- package/dataLayer/CreateAttributeObject.js +25 -0
- package/dataLayer/CreateTableObject.js +11 -0
- package/dataLayer/DataLayerObjects.js +43 -0
- package/dataLayer/DeleteBeforeObject.js +22 -0
- package/dataLayer/DeleteObject.js +25 -0
- package/dataLayer/DropAttributeObject.js +11 -0
- package/dataLayer/GetBackupObject.js +22 -0
- package/dataLayer/InsertObject.js +24 -0
- package/dataLayer/ReadAuditLogObject.js +24 -0
- package/dataLayer/SQLSearch.js +1335 -0
- package/dataLayer/SearchByConditionsObject.js +61 -0
- package/dataLayer/SearchByHashObject.js +21 -0
- package/dataLayer/SearchObject.js +45 -0
- package/dataLayer/SqlSearchObject.js +14 -0
- package/dataLayer/UpdateObject.js +23 -0
- package/dataLayer/UpsertObject.js +23 -0
- package/dataLayer/bulkLoad.js +813 -0
- package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
- package/dataLayer/dataObjects/UpsertObject.js +23 -0
- package/dataLayer/delete.js +164 -0
- package/dataLayer/export.js +381 -0
- package/dataLayer/getBackup.js +40 -0
- package/dataLayer/harperBridge/BridgeMethods.js +81 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
- package/dataLayer/harperBridge/harperBridge.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
- package/dataLayer/hdbInfoController.js +254 -0
- package/dataLayer/insert.js +266 -0
- package/dataLayer/readAuditLog.js +59 -0
- package/dataLayer/schema.js +366 -0
- package/dataLayer/schemaDescribe.js +289 -0
- package/dataLayer/search.js +60 -0
- package/dataLayer/transaction.js +17 -0
- package/dataLayer/update.js +124 -0
- package/dist/components/Logger.d.ts +12 -0
- package/dist/components/Logger.js +3 -0
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/Scope.d.ts +14 -4
- package/dist/components/Scope.js +18 -10
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +16 -9
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +2 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -1
- package/dist/config/configUtils.js +1 -1
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/CreateTableObject.d.ts +2 -2
- package/dist/dataLayer/CreateTableObject.js +2 -2
- package/dist/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/dataLayer/delete.d.ts +1 -1
- package/dist/dataLayer/schema.js +6 -5
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +1 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -1
- package/dist/resources/IterableEventQueue.d.ts +1 -1
- package/dist/resources/LMDBTransaction.d.ts +5 -1
- package/dist/resources/Resource.d.ts +1 -1
- package/dist/resources/RocksIndexStore.d.ts +3 -3
- package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
- package/dist/resources/Table.d.ts +15 -6
- package/dist/resources/Table.js +4 -1
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/read.js +32 -22
- package/dist/resources/analytics/read.js.map +1 -1
- package/dist/resources/analytics/write.js +3 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +3 -3
- package/dist/resources/blob.d.ts +25 -2
- package/dist/resources/databases.d.ts +12 -2
- package/dist/resources/databases.js +22 -19
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/search.js +11 -5
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.d.ts +2 -1
- package/dist/security/auth.js +1 -1
- package/dist/security/auth.js.map +1 -1
- package/dist/security/cryptoHash.d.ts +2 -2
- package/dist/security/jsLoader.js +243 -66
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +4 -5
- package/dist/security/keys.js.map +1 -1
- package/dist/security/user.js +3 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +16 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +2 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
- package/dist/server/fastifyRoutes.js +2 -0
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.js +12 -6
- package/dist/server/http.js.map +1 -1
- package/dist/server/jobs/JobObject.d.ts +3 -3
- package/dist/server/loadRootComponents.js +1 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/operationsServer.js +3 -1
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
- package/dist/server/serverHelpers/Request.d.ts +5 -5
- package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
- package/dist/server/threads/manageThreads.d.ts +2 -2
- package/dist/server/threads/manageThreads.js +50 -35
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -1
- package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
- package/dist/utility/AWS/AWSConnector.d.ts +3 -2
- package/dist/utility/common_utils.d.ts +3 -3
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
- package/dist/utility/globalSchema.d.ts +1 -1
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/installation.d.ts +2 -4
- package/dist/utility/installation.js.map +1 -1
- package/dist/utility/lmdb/commonUtility.d.ts +1 -0
- package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
- package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
- package/dist/utility/lmdb/searchUtility.d.ts +2 -1
- package/dist/utility/lmdb/writeUtility.d.ts +1 -0
- package/dist/utility/logging/harper_logger.d.ts +6 -6
- package/dist/utility/processManagement/processManagement.d.ts +1 -1
- package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
- package/dist/validation/common_validators.d.ts +4 -3
- package/dist/validation/configValidator.d.ts +3 -2
- package/index.d.ts +56 -0
- package/index.js +41 -0
- package/json/systemSchema.json +373 -0
- package/launchServiceScripts/launchHarperDB.js +3 -0
- package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
- package/package.json +21 -3
- package/resources/DatabaseTransaction.ts +378 -0
- package/resources/ErrorResource.ts +57 -0
- package/resources/IterableEventQueue.ts +94 -0
- package/resources/LMDBTransaction.ts +349 -0
- package/resources/RecordEncoder.ts +702 -0
- package/resources/RequestTarget.ts +134 -0
- package/resources/Resource.ts +789 -0
- package/resources/ResourceInterface.ts +221 -0
- package/resources/ResourceInterfaceV2.ts +53 -0
- package/resources/ResourceV2.ts +67 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4527 -0
- package/resources/analytics/hostnames.ts +72 -0
- package/resources/analytics/metadata.ts +10 -0
- package/resources/analytics/read.ts +252 -0
- package/resources/analytics/write.ts +803 -0
- package/resources/auditStore.ts +556 -0
- package/resources/blob.ts +1268 -0
- package/resources/crdt.ts +125 -0
- package/resources/dataLoader.ts +527 -0
- package/resources/databases.ts +1290 -0
- package/resources/graphql.ts +221 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
- package/resources/indexes/customIndexes.ts +7 -0
- package/resources/indexes/vector.ts +38 -0
- package/resources/jsResource.ts +86 -0
- package/resources/loadEnv.ts +22 -0
- package/resources/login.ts +18 -0
- package/resources/openApi.ts +409 -0
- package/resources/registrationDeprecated.ts +8 -0
- package/resources/replayLogs.ts +136 -0
- package/resources/roles.ts +98 -0
- package/resources/search.ts +1301 -0
- package/resources/tracked.ts +584 -0
- package/resources/transaction.ts +89 -0
- package/resources/transactionBroadcast.ts +258 -0
- package/security/auth.ts +376 -0
- package/security/certificateVerification/certificateVerificationSource.ts +84 -0
- package/security/certificateVerification/configValidation.ts +107 -0
- package/security/certificateVerification/crlVerification.ts +623 -0
- package/security/certificateVerification/index.ts +121 -0
- package/security/certificateVerification/ocspVerification.ts +148 -0
- package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
- package/security/certificateVerification/types.ts +128 -0
- package/security/certificateVerification/verificationConfig.ts +138 -0
- package/security/certificateVerification/verificationUtils.ts +447 -0
- package/security/cryptoHash.js +42 -0
- package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
- package/security/data_objects/PermissionResponseObject.js +115 -0
- package/security/data_objects/PermissionTableResponseObject.js +20 -0
- package/security/fastifyAuth.js +169 -0
- package/security/impersonation.ts +160 -0
- package/security/jsLoader.ts +716 -0
- package/security/keys.js +948 -0
- package/security/permissionsTranslator.js +300 -0
- package/security/role.js +218 -0
- package/security/tokenAuthentication.ts +228 -0
- package/security/user.ts +449 -0
- package/server/DurableSubscriptionsSession.ts +503 -0
- package/server/REST.ts +407 -0
- package/server/Server.ts +89 -0
- package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
- package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
- package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
- package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
- package/server/fastifyRoutes.ts +205 -0
- package/server/graphqlQuerying.ts +700 -0
- package/server/http.ts +640 -0
- package/server/itc/serverHandlers.js +161 -0
- package/server/itc/utility/ITCEventObject.js +10 -0
- package/server/jobs/JobObject.js +24 -0
- package/server/jobs/jobProcess.js +69 -0
- package/server/jobs/jobRunner.js +162 -0
- package/server/jobs/jobs.js +304 -0
- package/server/loadRootComponents.js +44 -0
- package/server/mqtt.ts +485 -0
- package/server/nodeName.ts +75 -0
- package/server/operationsServer.ts +313 -0
- package/server/serverHelpers/Headers.ts +108 -0
- package/server/serverHelpers/JSONStream.ts +269 -0
- package/server/serverHelpers/OperationFunctionObject.ts +13 -0
- package/server/serverHelpers/Request.ts +158 -0
- package/server/serverHelpers/contentTypes.ts +637 -0
- package/server/serverHelpers/requestTimePlugin.js +57 -0
- package/server/serverHelpers/serverHandlers.js +148 -0
- package/server/serverHelpers/serverUtilities.ts +473 -0
- package/server/serverRegistry.ts +8 -0
- package/server/static.ts +187 -0
- package/server/status/definitions.ts +37 -0
- package/server/status/index.ts +125 -0
- package/server/storageReclamation.ts +93 -0
- package/server/threads/itc.js +89 -0
- package/server/threads/manageThreads.js +594 -0
- package/server/threads/socketRouter.ts +360 -0
- package/server/threads/threadServer.js +279 -0
- package/server/throttle.ts +73 -0
- package/sqlTranslator/SelectValidator.js +330 -0
- package/sqlTranslator/alasqlFunctionImporter.js +62 -0
- package/sqlTranslator/deleteTranslator.js +67 -0
- package/sqlTranslator/index.js +242 -0
- package/sqlTranslator/sql_statement_bucket.js +472 -0
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/HDBDogOnly.svg +78 -0
- package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
- package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
- package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
- package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
- package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
- package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
- package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
- package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
- package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
- package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
- package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
- package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
- package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
- package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
- package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
- package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
- package/studio/web/assets/index-BTgXJX9d.js +235 -0
- package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
- package/studio/web/assets/index-C-GXfcup.js +37 -0
- package/studio/web/assets/index-C-GXfcup.js.map +1 -0
- package/studio/web/assets/index-PFlNdimM.js +2 -0
- package/studio/web/assets/index-PFlNdimM.js.map +1 -0
- package/studio/web/assets/index-Y2g_iFpU.css +1 -0
- package/studio/web/assets/index-jiPwkrsB.css +1 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js +266 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
- package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
- package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js.map +1 -0
- package/studio/web/fabric-signup-background.webp +0 -0
- package/studio/web/fabric-signup-text.png +0 -0
- package/studio/web/favicon_purple.png +0 -0
- package/studio/web/github-icon.svg +15 -0
- package/studio/web/harper-fabric_black.png +0 -0
- package/studio/web/harper-fabric_white.png +0 -0
- package/studio/web/harper-studio_white.png +0 -0
- package/studio/web/index.html +16 -0
- package/studio/web/running.css +148 -0
- package/studio/web/running.html +147 -0
- package/studio/web/running.js +111 -0
- package/upgrade/UpgradeObjects.js +13 -0
- package/upgrade/directives/directivesController.js +90 -0
- package/upgrade/directivesManager.js +139 -0
- package/upgrade/upgradePrompt.js +124 -0
- package/upgrade/upgradeUtilities.js +28 -0
- package/utility/AWS/AWSConnector.js +29 -0
- package/utility/OperationFunctionCaller.js +63 -0
- package/utility/assignCmdEnvVariables.js +62 -0
- package/utility/common_utils.js +867 -0
- package/utility/environment/environmentManager.js +208 -0
- package/utility/environment/systemInformation.js +355 -0
- package/utility/errors/commonErrors.js +267 -0
- package/utility/errors/hdbError.js +146 -0
- package/utility/functions/date/dateFunctions.js +65 -0
- package/utility/functions/geo.js +355 -0
- package/utility/functions/sql/alaSQLExtension.js +104 -0
- package/utility/globalSchema.js +35 -0
- package/utility/hdbTerms.ts +819 -0
- package/utility/install/checkJWTTokensExist.js +62 -0
- package/utility/install/harperdb.conf +15 -0
- package/utility/install/harperdb.service +14 -0
- package/utility/install/installer.js +635 -0
- package/utility/installation.ts +30 -0
- package/utility/lmdb/DBIDefinition.js +20 -0
- package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
- package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/OpenDBIObject.js +31 -0
- package/utility/lmdb/OpenEnvironmentObject.js +41 -0
- package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
- package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/cleanLMDBMap.js +65 -0
- package/utility/lmdb/commonUtility.js +119 -0
- package/utility/lmdb/deleteUtility.js +128 -0
- package/utility/lmdb/environmentUtility.js +477 -0
- package/utility/lmdb/searchCursorFunctions.js +187 -0
- package/utility/lmdb/searchUtility.js +918 -0
- package/utility/lmdb/terms.js +57 -0
- package/utility/lmdb/writeUtility.js +407 -0
- package/utility/logging/harper_logger.js +876 -0
- package/utility/logging/logRotator.js +157 -0
- package/utility/logging/logger.ts +24 -0
- package/utility/logging/readLog.js +355 -0
- package/utility/logging/transactionLog.js +57 -0
- package/utility/mount_hdb.js +59 -0
- package/utility/npmUtilities.js +102 -0
- package/utility/operationPermissions.ts +112 -0
- package/utility/operation_authorization.js +836 -0
- package/utility/packageUtils.js +55 -0
- package/utility/password.ts +99 -0
- package/utility/processManagement/processManagement.js +187 -0
- package/utility/processManagement/servicesConfig.js +56 -0
- package/utility/scripts/restartHdb.js +24 -0
- package/utility/scripts/user_data.sh +13 -0
- package/utility/signalling.js +36 -0
- package/utility/terms/certificates.js +81 -0
- package/utility/when.ts +20 -0
- package/v1.d.ts +39 -0
- package/v1.js +41 -0
- package/v2.d.ts +39 -0
- package/v2.js +41 -0
- package/validation/bulkDeleteValidator.js +24 -0
- package/validation/check_permissions.js +19 -0
- package/validation/common_validators.js +95 -0
- package/validation/configValidator.js +331 -0
- package/validation/deleteValidator.js +15 -0
- package/validation/fileLoadValidator.js +153 -0
- package/validation/insertValidator.js +40 -0
- package/validation/installValidator.js +37 -0
- package/validation/readLogValidator.js +64 -0
- package/validation/role_validation.js +320 -0
- package/validation/schemaMetadataValidator.js +42 -0
- package/validation/searchValidator.js +166 -0
- package/validation/statusValidator.ts +66 -0
- package/validation/transactionLogValidator.js +33 -0
- package/validation/user_validation.js +55 -0
- package/validation/validationWrapper.js +105 -0
- package/dist/resources/analytics/profile.d.ts +0 -2
- package/dist/resources/analytics/profile.js +0 -144
- package/dist/resources/analytics/profile.js.map +0 -1
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { type Logger } from '../utility/logging/logger.ts';
|
|
2
|
+
import { loggerWithTag } from '../utility/logging/harper_logger.js';
|
|
3
|
+
import { EventEmitter, once } from 'events';
|
|
4
|
+
import yaml from 'yaml';
|
|
5
|
+
import chokidar, { type FSWatcher } from 'chokidar';
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
7
|
+
import { isDeepStrictEqual } from 'util';
|
|
8
|
+
import { DEFAULT_CONFIG } from './DEFAULT_CONFIG.js';
|
|
9
|
+
import { cloneDeep } from 'lodash';
|
|
10
|
+
|
|
11
|
+
export interface Config {
|
|
12
|
+
[key: string]: ConfigValue;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ConfigValue = undefined | null | string | number | boolean | Array<ConfigValue> | Config;
|
|
16
|
+
|
|
17
|
+
export type OptionsWatcherEventMap = {
|
|
18
|
+
ready: [config?: ConfigValue];
|
|
19
|
+
change: [key: string[], value: ConfigValue, config: ConfigValue];
|
|
20
|
+
remove: [];
|
|
21
|
+
error: [error: unknown];
|
|
22
|
+
close: [];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// This is uniquely for errors coming from the chokidar watcher of the config file.
|
|
26
|
+
export class OptionsWatcherConfigFileError extends Error {
|
|
27
|
+
constructor(configFilePath: string, error: unknown) {
|
|
28
|
+
super(
|
|
29
|
+
`Error watching config file ${configFilePath}: ${typeof error === 'object' && error !== null && 'message' in error ? error.message : error}`
|
|
30
|
+
);
|
|
31
|
+
this.name = 'OptionsWatcherConfigFileError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class UninitializedOptionsWatcherError extends Error {
|
|
36
|
+
constructor() {
|
|
37
|
+
super(
|
|
38
|
+
'OptionsWatcher has not been initialized yet. Await `ready()` or the `ready` event of the respective OptionsWatcher instance.'
|
|
39
|
+
);
|
|
40
|
+
this.name = 'UninitializedOptionsWatcherError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class InvariantUninitializedOptionsWatcherError extends Error {
|
|
45
|
+
constructor() {
|
|
46
|
+
super('Invariant: OptionsWatcher has not been initialized yet. This should never happen.');
|
|
47
|
+
this.name = 'InvariantUninitializedOptionsWatcherError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class InvalidValueTypeError extends Error {
|
|
52
|
+
constructor(keys: string[], value: unknown) {
|
|
53
|
+
super(
|
|
54
|
+
`Invalid value type for key ${keys.join('.')}. Expected object, string, array, number, boolean, or undefined. Received ${typeof value}.`
|
|
55
|
+
);
|
|
56
|
+
this.name = 'InvalidValueTypeError';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class KeyDoesNotExistError extends Error {
|
|
61
|
+
constructor(keys: string[], key: string) {
|
|
62
|
+
super(`Cannot set property ${keys.join('.')} as ${key} does not exist.`);
|
|
63
|
+
this.name = 'KeyDoesNotExistError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class CannotSetPropertyError extends Error {
|
|
68
|
+
constructor(keys: string[]) {
|
|
69
|
+
super(`Cannot set property ${keys.join('.')} as parent is not an object.`);
|
|
70
|
+
this.name = 'CannotSetPropertyError';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Watches a YAML configuration file for changes and provides methods to access the configuration.
|
|
76
|
+
*
|
|
77
|
+
* @emits ready - When the configuration file is initially loaded and values are available
|
|
78
|
+
* @emits change - When any value in the configuration changes (with key, new value, and full config)
|
|
79
|
+
* @emits remove - When the configuration file is removed or the extension is removed from the config
|
|
80
|
+
* @emits error - When an error occurs reading or parsing the file
|
|
81
|
+
* @emits close - When the watcher is closed
|
|
82
|
+
*/
|
|
83
|
+
export class OptionsWatcher extends EventEmitter<OptionsWatcherEventMap> {
|
|
84
|
+
#filePath: string;
|
|
85
|
+
#watcher: FSWatcher;
|
|
86
|
+
#scopedConfig?: ConfigValue;
|
|
87
|
+
#rootConfig?: Config;
|
|
88
|
+
#name: string;
|
|
89
|
+
#logger: Logger;
|
|
90
|
+
ready: Promise<any[]>;
|
|
91
|
+
|
|
92
|
+
constructor(name: string, filePath: string, logger?: Logger) {
|
|
93
|
+
super();
|
|
94
|
+
this.#name = name;
|
|
95
|
+
this.#filePath = filePath;
|
|
96
|
+
this.#logger = logger || loggerWithTag(name);
|
|
97
|
+
this.ready = once(this, 'ready');
|
|
98
|
+
this.#watcher = chokidar
|
|
99
|
+
.watch(filePath, { persistent: false })
|
|
100
|
+
.on('add', this.#handleChange.bind(this))
|
|
101
|
+
.on('change', this.#handleChange.bind(this))
|
|
102
|
+
.on('error', this.#handleError.bind(this))
|
|
103
|
+
.on('unlink', this.#handleUnlink.bind(this))
|
|
104
|
+
.on('ready', this.#handleChange.bind(this));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#handleChange() {
|
|
108
|
+
readFile(this.#filePath, 'utf-8')
|
|
109
|
+
.then((contents) => {
|
|
110
|
+
this.#rootConfig = yaml.parse(contents);
|
|
111
|
+
// If the extension is in the config file
|
|
112
|
+
if (this.#rootConfig && this.#name in this.#rootConfig) {
|
|
113
|
+
// If a config object does not exist
|
|
114
|
+
if (!this.#scopedConfig) {
|
|
115
|
+
// set it
|
|
116
|
+
this.#scopedConfig = this.#rootConfig[this.#name];
|
|
117
|
+
// and emit a ready event
|
|
118
|
+
this.emit('ready', this.#scopedConfig);
|
|
119
|
+
} else {
|
|
120
|
+
// Otherwise, merge the new config with the old config
|
|
121
|
+
this.#merge(this.#rootConfig[this.#name], this.#scopedConfig);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Otherwise, if the extension is not in the config file
|
|
125
|
+
// This means the plugin was removed from the config file
|
|
126
|
+
if (this.#scopedConfig) {
|
|
127
|
+
// and a config exists, remove it
|
|
128
|
+
this.#scopedConfig = undefined;
|
|
129
|
+
this.emit('remove');
|
|
130
|
+
}
|
|
131
|
+
// Otherwise do nothing - the user may add the config back in later
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.catch((error) => {
|
|
135
|
+
// If the config file does not exist
|
|
136
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
137
|
+
// And a config already exists, reset it to the default
|
|
138
|
+
if (this.#rootConfig) {
|
|
139
|
+
this.#resetConfig();
|
|
140
|
+
this.emit('remove');
|
|
141
|
+
} else {
|
|
142
|
+
// Otherwise, if no config exists, then just set to default and emit ready
|
|
143
|
+
this.#resetConfig();
|
|
144
|
+
this.emit('ready');
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.emit('error', error);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#handleError(error: unknown) {
|
|
153
|
+
this.emit('error', new OptionsWatcherConfigFileError(this.#filePath, error));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#handleUnlink(path: string) {
|
|
157
|
+
this.#logger.warn?.(
|
|
158
|
+
`Configuration file ${path} was deleted. Reverting to default configuration. Recreate it to restore the options watcher.`
|
|
159
|
+
);
|
|
160
|
+
this.#resetConfig();
|
|
161
|
+
this.emit('remove');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#resetConfig() {
|
|
165
|
+
this.#rootConfig = DEFAULT_CONFIG;
|
|
166
|
+
this.#scopedConfig = this.#rootConfig[this.#name];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* This merge algorithm is best thought off as a diff and overwrite.
|
|
171
|
+
* The new config object will completely overwrite the old config object,
|
|
172
|
+
* but we need to recursively iterate over the new entries and emit the
|
|
173
|
+
* necessary change events.
|
|
174
|
+
*
|
|
175
|
+
* All events are considered to be a `change`.
|
|
176
|
+
*/
|
|
177
|
+
#merge(newConfigValue: ConfigValue, currentConfigValue: ConfigValue, prevKeys: string[] = []) {
|
|
178
|
+
// First, ensure current and new config values are Config objects (not null, undefined, or a primitive)
|
|
179
|
+
if (!this.#isConfig(currentConfigValue) || !this.#isConfig(newConfigValue)) {
|
|
180
|
+
// If either is not a config, then just set as there is no need to diff/merge
|
|
181
|
+
this.#setValue(prevKeys, newConfigValue);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check for any missing keys (new config has removed keys from current config)
|
|
186
|
+
for (const key of Object.keys(currentConfigValue)) {
|
|
187
|
+
if (!(key in newConfigValue)) {
|
|
188
|
+
this.#setValue(prevKeys.concat(key), undefined);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Then, iterate of the keys in the new config and check for any changes to the current config
|
|
193
|
+
for (const [key, newValue] of Object.entries(newConfigValue)) {
|
|
194
|
+
const keys = prevKeys.concat(key);
|
|
195
|
+
const currentValue = this.#getValue(keys);
|
|
196
|
+
|
|
197
|
+
// If the new value is not the same type as the current value, then no equivalency check is necessary
|
|
198
|
+
// Just set the value and continue
|
|
199
|
+
if (
|
|
200
|
+
typeof newValue !== typeof currentValue ||
|
|
201
|
+
// one exception to the above rule is if the `currentValue` is being changed from an array to an object or vice versa
|
|
202
|
+
// Check for this and shortcut as it can be treated as a type change
|
|
203
|
+
(Array.isArray(newValue) && !Array.isArray(currentValue)) ||
|
|
204
|
+
(!Array.isArray(newValue) && Array.isArray(currentValue))
|
|
205
|
+
) {
|
|
206
|
+
this.#setValue(keys, newValue);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// If the new value is an object (non null nor an array), now merge it with the current value
|
|
211
|
+
if (!Array.isArray(newValue) && typeof newValue === 'object' && newValue !== null) {
|
|
212
|
+
if (this.#isConfig(currentValue)) {
|
|
213
|
+
// Now we're sure currentValue is a Config
|
|
214
|
+
this.#merge(newValue, currentValue, keys);
|
|
215
|
+
} else {
|
|
216
|
+
// If currentValue is not a Config, just set newValue
|
|
217
|
+
this.#setValue(keys, newValue);
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!isDeepStrictEqual(newValue, currentValue)) {
|
|
223
|
+
this.#setValue(keys, newValue);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
#isConfig(value: ConfigValue): value is Config {
|
|
229
|
+
return typeof value === 'object' && value !== null && value !== undefined && !Array.isArray(value);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
#getValue(keys: string[]): undefined | ConfigValue {
|
|
233
|
+
let value: ConfigValue = this.#scopedConfig;
|
|
234
|
+
|
|
235
|
+
for (const key of keys) {
|
|
236
|
+
if (value === null || value === undefined || typeof value !== 'object' || !(key in value)) return undefined;
|
|
237
|
+
|
|
238
|
+
value = value[key];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return cloneDeep(value);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#setValue(keys: string[], value: ConfigValue) {
|
|
245
|
+
// This method is only called by `merge`, which is only called by `changeHandler` if `this.#config` is defined.
|
|
246
|
+
// So this should never happen, but just in case, throw an error.
|
|
247
|
+
// If this ever does get triggered:
|
|
248
|
+
// - Did something else other than `merge` call this method?
|
|
249
|
+
// - Did the `merge` method get called differently?
|
|
250
|
+
// - Did the `merge` method become async and the `this.#config` get set to undefined sometime in between?
|
|
251
|
+
if (!this.#scopedConfig) {
|
|
252
|
+
throw new InvariantUninitializedOptionsWatcherError();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!['object', 'string', 'array', 'number', 'boolean', 'undefined'].includes(typeof value)) {
|
|
256
|
+
throw new InvalidValueTypeError(keys, value);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
let obj: ConfigValue = this.#scopedConfig;
|
|
260
|
+
|
|
261
|
+
for (const key of keys.slice(0, -1)) {
|
|
262
|
+
if (obj === null || obj === undefined || typeof obj !== 'object' || !(key in obj)) {
|
|
263
|
+
throw new KeyDoesNotExistError(keys, key);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
obj = obj[key];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (obj === null || obj === undefined || typeof obj !== 'object') {
|
|
270
|
+
throw new CannotSetPropertyError(keys);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
obj[keys[keys.length - 1]] = value;
|
|
274
|
+
|
|
275
|
+
this.emit('change', keys, value, this.#scopedConfig);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Closes the underlying file watcher, emits the `close` event, and removes any listeners on the OptionsWatcher instance
|
|
280
|
+
*/
|
|
281
|
+
close() {
|
|
282
|
+
this.#watcher.close();
|
|
283
|
+
|
|
284
|
+
this.emit('close');
|
|
285
|
+
|
|
286
|
+
this.removeAllListeners();
|
|
287
|
+
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Get a value from the configuration using an array of strings representing the key.
|
|
293
|
+
*
|
|
294
|
+
* For example, if the configuration is:
|
|
295
|
+
* ```yaml
|
|
296
|
+
* foo:
|
|
297
|
+
* bar:
|
|
298
|
+
* baz: 42
|
|
299
|
+
* ```
|
|
300
|
+
* Then `get(['foo','bar','baz'])` will return `42`.
|
|
301
|
+
*
|
|
302
|
+
* If the key does not exist, `undefined` will be returned.
|
|
303
|
+
* @param key an array of strings representing the key.
|
|
304
|
+
* @returns
|
|
305
|
+
*/
|
|
306
|
+
get(key: string[]): ConfigValue | undefined {
|
|
307
|
+
return this.#scopedConfig ? this.#getValue(key) : undefined;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get the entire configuration object.
|
|
312
|
+
*
|
|
313
|
+
* @returns A deep clone of the entire configuration object.
|
|
314
|
+
*/
|
|
315
|
+
getAll(): ConfigValue | undefined {
|
|
316
|
+
return cloneDeep(this.#scopedConfig);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get the entire root configuration object from the config file.
|
|
321
|
+
*/
|
|
322
|
+
getRoot(): Config | undefined {
|
|
323
|
+
return this.#rootConfig;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Not sure if we want to enable runtime changes to the config - any changes to the config should be done in the config file.
|
|
327
|
+
// /**
|
|
328
|
+
// * Set a value in the configuration using a dot-separated key. Any existing value can be replaced with any new value, regardless of type.
|
|
329
|
+
// *
|
|
330
|
+
// * For example, with the configuration:
|
|
331
|
+
// *
|
|
332
|
+
// * ```yaml
|
|
333
|
+
// * foo:
|
|
334
|
+
// * bar:
|
|
335
|
+
// * baz: 42
|
|
336
|
+
// * ```
|
|
337
|
+
// *
|
|
338
|
+
// * The call `set('foo.bar.baz', 'harper')` will set `foo.bar.baz` to `'harper'`.
|
|
339
|
+
// *
|
|
340
|
+
// * This method will allow you to set new values in the configuration, but it will not generate nested objects.
|
|
341
|
+
// *
|
|
342
|
+
// * For example, using the configuration above, `set('foo.fuzz', 'buzz')`, will work fine.
|
|
343
|
+
// *
|
|
344
|
+
// * But `set('foo.x.y', 0)` will throw an error, because it is attempting to set `y` on the non-existent `x`.
|
|
345
|
+
// *
|
|
346
|
+
// * This method will emit a `change` event when the value is set.
|
|
347
|
+
// *
|
|
348
|
+
// * @param key Dot-separated key to set the value for.
|
|
349
|
+
// * @param value Value to set.
|
|
350
|
+
// */
|
|
351
|
+
// set(key: string, value: any) {
|
|
352
|
+
// this.setValue(key.split('.'), cloneDeep(value));
|
|
353
|
+
// }
|
|
354
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { type Logger } from '../utility/logging/logger.ts';
|
|
2
|
+
import { loggerWithTag } from '../utility/logging/harper_logger.js';
|
|
3
|
+
import { EventEmitter, once } from 'node:events';
|
|
4
|
+
import { databaseEventsEmitter } from '../resources/databases.ts';
|
|
5
|
+
import { server, type Server } from '../server/Server.ts';
|
|
6
|
+
import { EntryHandler, type EntryHandlerEventMap, type onEntryEventHandler } from './EntryHandler.ts';
|
|
7
|
+
import { OptionsWatcher, OptionsWatcherEventMap } from './OptionsWatcher.ts';
|
|
8
|
+
import { resources, type Resources } from '../resources/Resources.ts';
|
|
9
|
+
import type { FileAndURLPathConfig } from './Component.ts';
|
|
10
|
+
import { FilesOption } from './deriveGlobOptions.ts';
|
|
11
|
+
import { requestRestart } from './requestRestart.ts';
|
|
12
|
+
import { ApplicationScope } from './ApplicationScope.ts';
|
|
13
|
+
|
|
14
|
+
export class MissingDefaultFilesOptionError extends Error {
|
|
15
|
+
constructor() {
|
|
16
|
+
super('No default files option exists. Ensure `files` is specified in config.yaml');
|
|
17
|
+
this.name = 'MissingDefaultFilesOptionError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ScopeEventsMap = {
|
|
22
|
+
all: [...args: unknown[]];
|
|
23
|
+
close: [];
|
|
24
|
+
error: [error: unknown];
|
|
25
|
+
ready: [];
|
|
26
|
+
[record: string]: [...args: unknown[]];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* This class is what is passed to the `handleApplication` function of an extension.
|
|
31
|
+
*
|
|
32
|
+
* It is imperative that the instance is "ready" before it's passed to the `handleApplication` function
|
|
33
|
+
* so that the developer can immediately start using `scope.options`, etc.
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
export class Scope extends EventEmitter<ScopeEventsMap> {
|
|
37
|
+
#configFilePath: string;
|
|
38
|
+
#directory: string;
|
|
39
|
+
#appName: string;
|
|
40
|
+
#pluginName: string;
|
|
41
|
+
#entryHandler?: EntryHandler;
|
|
42
|
+
#entryHandlers: EntryHandler[];
|
|
43
|
+
#logger: Logger;
|
|
44
|
+
#pendingInitialLoads: Set<Promise<void>>;
|
|
45
|
+
applicationScope?: ApplicationScope;
|
|
46
|
+
|
|
47
|
+
options: OptionsWatcher;
|
|
48
|
+
resources?: Resources;
|
|
49
|
+
server?: Server;
|
|
50
|
+
ready: Promise<any[]>;
|
|
51
|
+
databaseEvents: typeof databaseEventsEmitter;
|
|
52
|
+
|
|
53
|
+
constructor(
|
|
54
|
+
appName: string,
|
|
55
|
+
pluginName: string,
|
|
56
|
+
directory: string,
|
|
57
|
+
configFilePath: string,
|
|
58
|
+
applicationScope: ApplicationScope
|
|
59
|
+
) {
|
|
60
|
+
super();
|
|
61
|
+
|
|
62
|
+
this.#appName = appName;
|
|
63
|
+
this.#pluginName = pluginName;
|
|
64
|
+
this.#directory = directory;
|
|
65
|
+
this.#configFilePath = configFilePath;
|
|
66
|
+
this.#logger = logger || loggerWithTag(this.#appName);
|
|
67
|
+
|
|
68
|
+
this.databaseEvents = databaseEventsEmitter;
|
|
69
|
+
this.applicationScope = applicationScope;
|
|
70
|
+
this.resources = applicationScope?.resources ?? resources;
|
|
71
|
+
this.server = applicationScope?.server ?? server;
|
|
72
|
+
|
|
73
|
+
this.#entryHandlers = [];
|
|
74
|
+
this.#pendingInitialLoads = new Set();
|
|
75
|
+
|
|
76
|
+
this.ready = once(this, 'ready');
|
|
77
|
+
|
|
78
|
+
// Create the options instance for the scope immediately
|
|
79
|
+
this.options = new OptionsWatcher(pluginName, configFilePath, this.#logger)
|
|
80
|
+
.on('error', this.#handleError.bind(this))
|
|
81
|
+
.on('change', this.#optionsWatcherChangeListener.bind(this)())
|
|
82
|
+
.on('ready', this.#handleOptionsWatcherReady.bind(this));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get logger(): Logger {
|
|
86
|
+
return this.#logger;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get appName(): string {
|
|
90
|
+
return this.#appName;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get pluginName(): string {
|
|
94
|
+
return this.#pluginName;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get directory(): string {
|
|
98
|
+
return this.#directory;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get configFilePath(): string {
|
|
102
|
+
return this.#configFilePath;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#handleOptionsWatcherReady(): void {
|
|
106
|
+
// This previously created the default entry handler immediately, but now we wait for the user to call `handleEntry`
|
|
107
|
+
// The issue was that since the component loader was awaiting `scope.ready()` and then calling `pluginModule.handleApplication(scope)`,
|
|
108
|
+
// the default entry handler could start receiving events before the plugin provided its own handler.
|
|
109
|
+
// We could make the user call `await scope.ready()` in their `handleApplication` function, but that could lead to the same issue and it'd
|
|
110
|
+
// be harder for the user to understand why.
|
|
111
|
+
|
|
112
|
+
this.emit('ready');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#handleError(error: unknown): void {
|
|
116
|
+
this.emit('error', error);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
close() {
|
|
120
|
+
for (const entryHandler of this.#entryHandlers) {
|
|
121
|
+
entryHandler.close();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.options.close();
|
|
125
|
+
|
|
126
|
+
this.emit('close');
|
|
127
|
+
|
|
128
|
+
this.removeAllListeners();
|
|
129
|
+
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#createEntryHandler(config: FilesOption | FileAndURLPathConfig): EntryHandler {
|
|
134
|
+
const entryHandler = new EntryHandler(this.#pluginName, this.#directory, config, this.#logger)
|
|
135
|
+
.on('error', this.#handleError.bind(this))
|
|
136
|
+
.on('add', this.#defaultEntryHandlerListener('add'))
|
|
137
|
+
.on('change', this.#defaultEntryHandlerListener('change'))
|
|
138
|
+
.on('unlink', this.#defaultEntryHandlerListener('unlink'))
|
|
139
|
+
.on('addDir', this.#defaultEntryHandlerListener('addDir'))
|
|
140
|
+
.on('unlinkDir', this.#defaultEntryHandlerListener('unlinkDir'));
|
|
141
|
+
|
|
142
|
+
this.#entryHandlers.push(entryHandler);
|
|
143
|
+
|
|
144
|
+
return entryHandler;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#defaultEntryHandlerListener(event: keyof EntryHandlerEventMap) {
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
149
|
+
const scope = this;
|
|
150
|
+
return function (this: EntryHandler) {
|
|
151
|
+
if (this.listenerCount('all') > 0 || this.listenerCount(event) > 1) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
scope.requestRestart();
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#optionsWatcherChangeListener() {
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
161
|
+
const scope = this;
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
163
|
+
return function handleOptionsWatcherChange(
|
|
164
|
+
this: OptionsWatcher,
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
166
|
+
...[key, _, config]: OptionsWatcherEventMap['change']
|
|
167
|
+
) {
|
|
168
|
+
if (key[0] === 'files' || key[0] === 'urlPath') {
|
|
169
|
+
// TODO: validate options
|
|
170
|
+
|
|
171
|
+
// If not entry handler exists then likely the config did not have `files` initially
|
|
172
|
+
// Now, it does, so create a default entry handler.
|
|
173
|
+
if (!scope.#entryHandler) {
|
|
174
|
+
scope.#entryHandler = scope.#createEntryHandler(config as FileAndURLPathConfig);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Otherwise, if an entry handler exists, update it with the new config
|
|
179
|
+
scope.#entryHandler.update(config as FileAndURLPathConfig);
|
|
180
|
+
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// If the user isn't handling option changes, request a restart
|
|
185
|
+
if (this.listenerCount('change') > 1) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
scope.#logger.debug?.(`Options changed: ${key.join('.')}, requesting restart`);
|
|
190
|
+
scope.requestRestart();
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#getFilesOption(): FileAndURLPathConfig | undefined {
|
|
195
|
+
const config = this.options.getAll();
|
|
196
|
+
if (
|
|
197
|
+
config &&
|
|
198
|
+
typeof config === 'object' &&
|
|
199
|
+
config !== null &&
|
|
200
|
+
!Array.isArray(config) &&
|
|
201
|
+
'files' in config /*&& validate config.files*/
|
|
202
|
+
) {
|
|
203
|
+
return {
|
|
204
|
+
files: config.files as FilesOption,
|
|
205
|
+
urlPath: config.urlPath as string | undefined,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
handleEntry(files: FilesOption | FileAndURLPathConfig, handler: onEntryEventHandler): EntryHandler;
|
|
212
|
+
handleEntry(handler: onEntryEventHandler): EntryHandler;
|
|
213
|
+
handleEntry(): EntryHandler;
|
|
214
|
+
handleEntry(
|
|
215
|
+
filesOrHandler?: FilesOption | FileAndURLPathConfig | onEntryEventHandler,
|
|
216
|
+
handler?: onEntryEventHandler
|
|
217
|
+
): EntryHandler {
|
|
218
|
+
let entryHandler: EntryHandler;
|
|
219
|
+
|
|
220
|
+
// Helper to wrap async handlers for tracking
|
|
221
|
+
const wrapHandler = (
|
|
222
|
+
targetEntryHandler: EntryHandler,
|
|
223
|
+
entryEventHandler: onEntryEventHandler
|
|
224
|
+
): onEntryEventHandler => {
|
|
225
|
+
const pendingOperations = new Set<Promise<void>>();
|
|
226
|
+
|
|
227
|
+
const wrapped: onEntryEventHandler = (entry) => {
|
|
228
|
+
const result = entryEventHandler(entry);
|
|
229
|
+
if (result instanceof Promise) {
|
|
230
|
+
const tracked = result
|
|
231
|
+
.catch((error) => {
|
|
232
|
+
this.#logger.error?.('Error in async entry handler:', error);
|
|
233
|
+
this.#handleError(error);
|
|
234
|
+
throw error;
|
|
235
|
+
})
|
|
236
|
+
.finally(() => pendingOperations.delete(tracked));
|
|
237
|
+
pendingOperations.add(tracked);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// When the entry handler's initial scan completes, wait for all pending async operations
|
|
242
|
+
const initialLoadPromise = once(targetEntryHandler, 'ready').then(async () => {
|
|
243
|
+
if (pendingOperations.size > 0) {
|
|
244
|
+
await Promise.all(pendingOperations);
|
|
245
|
+
}
|
|
246
|
+
targetEntryHandler.emit('initialLoadComplete');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Track this promise so the component loader can await it
|
|
250
|
+
this.#pendingInitialLoads.add(initialLoadPromise);
|
|
251
|
+
initialLoadPromise.finally(() => this.#pendingInitialLoads.delete(initialLoadPromise));
|
|
252
|
+
|
|
253
|
+
return wrapped;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// No arguments
|
|
257
|
+
if (filesOrHandler === undefined) {
|
|
258
|
+
// If entry handler already exists, return it
|
|
259
|
+
if (this.#entryHandler) {
|
|
260
|
+
entryHandler = this.#entryHandler;
|
|
261
|
+
} else {
|
|
262
|
+
// Otherwise, try to create a default entry handler using the files option
|
|
263
|
+
const filesOption = this.#getFilesOption();
|
|
264
|
+
if (filesOption) {
|
|
265
|
+
this.#entryHandler = this.#createEntryHandler(filesOption);
|
|
266
|
+
entryHandler = this.#entryHandler;
|
|
267
|
+
} else {
|
|
268
|
+
this.emit('error', new MissingDefaultFilesOptionError());
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Provided a handler function
|
|
274
|
+
else if (typeof filesOrHandler === 'function') {
|
|
275
|
+
// If an entry handler already exists, return it with the handler attached
|
|
276
|
+
if (this.#entryHandler) {
|
|
277
|
+
entryHandler = this.#entryHandler;
|
|
278
|
+
} else {
|
|
279
|
+
// Otherwise, try to create a default entry handler using the files option
|
|
280
|
+
const filesOption = this.#getFilesOption();
|
|
281
|
+
if (filesOption) {
|
|
282
|
+
this.#entryHandler = this.#createEntryHandler(filesOption);
|
|
283
|
+
entryHandler = this.#entryHandler;
|
|
284
|
+
} else {
|
|
285
|
+
this.emit('error', new MissingDefaultFilesOptionError());
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const wrappedHandler = wrapHandler(entryHandler, filesOrHandler);
|
|
291
|
+
entryHandler.on('all', wrappedHandler);
|
|
292
|
+
}
|
|
293
|
+
// otherwise this is a custom config entry handler
|
|
294
|
+
else {
|
|
295
|
+
entryHandler = this.#createEntryHandler(filesOrHandler);
|
|
296
|
+
if (handler) {
|
|
297
|
+
const wrappedHandler = wrapHandler(entryHandler, handler);
|
|
298
|
+
entryHandler.on('all', wrappedHandler);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return entryHandler;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
requestRestart() {
|
|
306
|
+
this.#logger.debug?.(`Restart requested from ${this.#pluginName} scope for ${this.#appName}`);
|
|
307
|
+
requestRestart();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Wait for all entry handlers' initial loads to complete.
|
|
312
|
+
* This includes waiting for any async operations in entry handler callbacks.
|
|
313
|
+
* Called by the component loader after handleApplication completes.
|
|
314
|
+
*/
|
|
315
|
+
async waitForInitialLoads(): Promise<void> {
|
|
316
|
+
if (this.#pendingInitialLoads.size > 0) {
|
|
317
|
+
await Promise.all(this.#pendingInitialLoads);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Import a file into the scope's sandbox.
|
|
323
|
+
* @param filePath - The path of the file to import.
|
|
324
|
+
* @returns A promise that resolves with the imported module or value.
|
|
325
|
+
*/
|
|
326
|
+
async import(filePath: string): Promise<unknown> {
|
|
327
|
+
return this.applicationScope ? this.applicationScope.import(filePath) : import(filePath);
|
|
328
|
+
}
|
|
329
|
+
}
|