@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.
Files changed (444) hide show
  1. package/bin/BinObjects.js +17 -0
  2. package/bin/cliOperations.js +157 -0
  3. package/bin/copyDb.ts +280 -0
  4. package/bin/harper.js +156 -0
  5. package/bin/install.js +15 -0
  6. package/bin/lite.js +5 -0
  7. package/bin/restart.js +201 -0
  8. package/bin/run.js +409 -0
  9. package/bin/status.js +65 -0
  10. package/bin/stop.js +22 -0
  11. package/bin/upgrade.js +134 -0
  12. package/components/Application.ts +646 -0
  13. package/components/ApplicationScope.ts +49 -0
  14. package/components/Component.ts +53 -0
  15. package/components/ComponentV1.ts +342 -0
  16. package/components/DEFAULT_CONFIG.ts +18 -0
  17. package/components/EntryHandler.ts +227 -0
  18. package/components/Logger.ts +14 -0
  19. package/components/OptionsWatcher.ts +354 -0
  20. package/components/PluginModule.ts +6 -0
  21. package/components/Scope.ts +329 -0
  22. package/components/componentLoader.ts +529 -0
  23. package/components/deriveCommonPatternBase.ts +31 -0
  24. package/components/deriveGlobOptions.ts +44 -0
  25. package/components/deriveURLPath.ts +57 -0
  26. package/components/operations.js +658 -0
  27. package/components/operationsValidation.js +246 -0
  28. package/components/packageComponent.ts +39 -0
  29. package/components/requestRestart.ts +26 -0
  30. package/components/resolveBaseURLPath.ts +38 -0
  31. package/components/status/ComponentStatus.ts +110 -0
  32. package/components/status/ComponentStatusRegistry.ts +251 -0
  33. package/components/status/api.ts +153 -0
  34. package/components/status/crossThread.ts +405 -0
  35. package/components/status/errors.ts +152 -0
  36. package/components/status/index.ts +44 -0
  37. package/components/status/internal.ts +65 -0
  38. package/components/status/registry.ts +12 -0
  39. package/components/status/types.ts +96 -0
  40. package/config/RootConfigWatcher.ts +59 -0
  41. package/config/configHelpers.ts +11 -0
  42. package/config/configUtils.js +967 -0
  43. package/config/harperConfigEnvVars.ts +641 -0
  44. package/dataLayer/CreateAttributeObject.js +25 -0
  45. package/dataLayer/CreateTableObject.js +11 -0
  46. package/dataLayer/DataLayerObjects.js +43 -0
  47. package/dataLayer/DeleteBeforeObject.js +22 -0
  48. package/dataLayer/DeleteObject.js +25 -0
  49. package/dataLayer/DropAttributeObject.js +11 -0
  50. package/dataLayer/GetBackupObject.js +22 -0
  51. package/dataLayer/InsertObject.js +24 -0
  52. package/dataLayer/ReadAuditLogObject.js +24 -0
  53. package/dataLayer/SQLSearch.js +1335 -0
  54. package/dataLayer/SearchByConditionsObject.js +61 -0
  55. package/dataLayer/SearchByHashObject.js +21 -0
  56. package/dataLayer/SearchObject.js +45 -0
  57. package/dataLayer/SqlSearchObject.js +14 -0
  58. package/dataLayer/UpdateObject.js +23 -0
  59. package/dataLayer/UpsertObject.js +23 -0
  60. package/dataLayer/bulkLoad.js +813 -0
  61. package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
  62. package/dataLayer/dataObjects/UpsertObject.js +23 -0
  63. package/dataLayer/delete.js +164 -0
  64. package/dataLayer/export.js +381 -0
  65. package/dataLayer/getBackup.js +40 -0
  66. package/dataLayer/harperBridge/BridgeMethods.js +81 -0
  67. package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
  68. package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
  69. package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
  70. package/dataLayer/harperBridge/harperBridge.js +21 -0
  71. package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
  72. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
  73. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
  74. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
  75. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
  76. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
  77. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
  78. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
  79. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
  80. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
  81. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
  82. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
  83. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
  84. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
  85. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
  86. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
  87. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
  88. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
  89. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
  90. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
  91. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
  92. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
  93. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
  94. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
  95. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
  96. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
  97. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
  98. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
  99. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
  100. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
  101. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
  102. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
  103. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
  104. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
  105. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
  106. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
  107. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
  108. package/dataLayer/hdbInfoController.js +254 -0
  109. package/dataLayer/insert.js +266 -0
  110. package/dataLayer/readAuditLog.js +59 -0
  111. package/dataLayer/schema.js +366 -0
  112. package/dataLayer/schemaDescribe.js +289 -0
  113. package/dataLayer/search.js +60 -0
  114. package/dataLayer/transaction.js +17 -0
  115. package/dataLayer/update.js +124 -0
  116. package/dist/components/Logger.d.ts +12 -0
  117. package/dist/components/Logger.js +3 -0
  118. package/dist/components/Logger.js.map +1 -0
  119. package/dist/components/Scope.d.ts +14 -4
  120. package/dist/components/Scope.js +18 -10
  121. package/dist/components/Scope.js.map +1 -1
  122. package/dist/components/componentLoader.js +16 -9
  123. package/dist/components/componentLoader.js.map +1 -1
  124. package/dist/components/operations.js +2 -2
  125. package/dist/components/operations.js.map +1 -1
  126. package/dist/config/configUtils.d.ts +1 -1
  127. package/dist/config/configUtils.js +1 -1
  128. package/dist/config/configUtils.js.map +1 -1
  129. package/dist/dataLayer/CreateTableObject.d.ts +2 -2
  130. package/dist/dataLayer/CreateTableObject.js +2 -2
  131. package/dist/dataLayer/CreateTableObject.js.map +1 -1
  132. package/dist/dataLayer/delete.d.ts +1 -1
  133. package/dist/dataLayer/schema.js +6 -5
  134. package/dist/dataLayer/schema.js.map +1 -1
  135. package/dist/dataLayer/schemaDescribe.js +1 -1
  136. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  137. package/dist/index.d.ts +1 -1
  138. package/dist/index.js +2 -0
  139. package/dist/index.js.map +1 -1
  140. package/dist/resources/DatabaseTransaction.d.ts +1 -1
  141. package/dist/resources/IterableEventQueue.d.ts +1 -1
  142. package/dist/resources/LMDBTransaction.d.ts +5 -1
  143. package/dist/resources/Resource.d.ts +1 -1
  144. package/dist/resources/RocksIndexStore.d.ts +3 -3
  145. package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
  146. package/dist/resources/Table.d.ts +15 -6
  147. package/dist/resources/Table.js +4 -1
  148. package/dist/resources/Table.js.map +1 -1
  149. package/dist/resources/analytics/read.js +32 -22
  150. package/dist/resources/analytics/read.js.map +1 -1
  151. package/dist/resources/analytics/write.js +3 -6
  152. package/dist/resources/analytics/write.js.map +1 -1
  153. package/dist/resources/auditStore.d.ts +3 -3
  154. package/dist/resources/blob.d.ts +25 -2
  155. package/dist/resources/databases.d.ts +12 -2
  156. package/dist/resources/databases.js +22 -19
  157. package/dist/resources/databases.js.map +1 -1
  158. package/dist/resources/search.js +11 -5
  159. package/dist/resources/search.js.map +1 -1
  160. package/dist/resources/transaction.d.ts +2 -1
  161. package/dist/security/auth.js +1 -1
  162. package/dist/security/auth.js.map +1 -1
  163. package/dist/security/cryptoHash.d.ts +2 -2
  164. package/dist/security/jsLoader.js +243 -66
  165. package/dist/security/jsLoader.js.map +1 -1
  166. package/dist/security/keys.js +4 -5
  167. package/dist/security/keys.js.map +1 -1
  168. package/dist/security/user.js +3 -3
  169. package/dist/security/user.js.map +1 -1
  170. package/dist/server/REST.js +16 -2
  171. package/dist/server/REST.js.map +1 -1
  172. package/dist/server/Server.d.ts +2 -1
  173. package/dist/server/Server.js.map +1 -1
  174. package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
  175. package/dist/server/fastifyRoutes.js +2 -0
  176. package/dist/server/fastifyRoutes.js.map +1 -1
  177. package/dist/server/http.js +12 -6
  178. package/dist/server/http.js.map +1 -1
  179. package/dist/server/jobs/JobObject.d.ts +3 -3
  180. package/dist/server/loadRootComponents.js +1 -0
  181. package/dist/server/loadRootComponents.js.map +1 -1
  182. package/dist/server/operationsServer.js +3 -1
  183. package/dist/server/operationsServer.js.map +1 -1
  184. package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
  185. package/dist/server/serverHelpers/Request.d.ts +5 -5
  186. package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
  187. package/dist/server/threads/manageThreads.d.ts +2 -2
  188. package/dist/server/threads/manageThreads.js +50 -35
  189. package/dist/server/threads/manageThreads.js.map +1 -1
  190. package/dist/server/threads/socketRouter.d.ts +1 -1
  191. package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
  192. package/dist/utility/AWS/AWSConnector.d.ts +3 -2
  193. package/dist/utility/common_utils.d.ts +3 -3
  194. package/dist/utility/environment/systemInformation.d.ts +1 -0
  195. package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
  196. package/dist/utility/globalSchema.d.ts +1 -1
  197. package/dist/utility/hdbTerms.d.ts +3 -0
  198. package/dist/utility/hdbTerms.js +3 -0
  199. package/dist/utility/hdbTerms.js.map +1 -1
  200. package/dist/utility/installation.d.ts +2 -4
  201. package/dist/utility/installation.js.map +1 -1
  202. package/dist/utility/lmdb/commonUtility.d.ts +1 -0
  203. package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
  204. package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
  205. package/dist/utility/lmdb/searchUtility.d.ts +2 -1
  206. package/dist/utility/lmdb/writeUtility.d.ts +1 -0
  207. package/dist/utility/logging/harper_logger.d.ts +6 -6
  208. package/dist/utility/processManagement/processManagement.d.ts +1 -1
  209. package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
  210. package/dist/validation/common_validators.d.ts +4 -3
  211. package/dist/validation/configValidator.d.ts +3 -2
  212. package/index.d.ts +56 -0
  213. package/index.js +41 -0
  214. package/json/systemSchema.json +373 -0
  215. package/launchServiceScripts/launchHarperDB.js +3 -0
  216. package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
  217. package/package.json +21 -3
  218. package/resources/DatabaseTransaction.ts +378 -0
  219. package/resources/ErrorResource.ts +57 -0
  220. package/resources/IterableEventQueue.ts +94 -0
  221. package/resources/LMDBTransaction.ts +349 -0
  222. package/resources/RecordEncoder.ts +702 -0
  223. package/resources/RequestTarget.ts +134 -0
  224. package/resources/Resource.ts +789 -0
  225. package/resources/ResourceInterface.ts +221 -0
  226. package/resources/ResourceInterfaceV2.ts +53 -0
  227. package/resources/ResourceV2.ts +67 -0
  228. package/resources/Resources.ts +162 -0
  229. package/resources/RocksIndexStore.ts +70 -0
  230. package/resources/RocksTransactionLogStore.ts +352 -0
  231. package/resources/Table.ts +4527 -0
  232. package/resources/analytics/hostnames.ts +72 -0
  233. package/resources/analytics/metadata.ts +10 -0
  234. package/resources/analytics/read.ts +252 -0
  235. package/resources/analytics/write.ts +803 -0
  236. package/resources/auditStore.ts +556 -0
  237. package/resources/blob.ts +1268 -0
  238. package/resources/crdt.ts +125 -0
  239. package/resources/dataLoader.ts +527 -0
  240. package/resources/databases.ts +1290 -0
  241. package/resources/graphql.ts +221 -0
  242. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
  243. package/resources/indexes/customIndexes.ts +7 -0
  244. package/resources/indexes/vector.ts +38 -0
  245. package/resources/jsResource.ts +86 -0
  246. package/resources/loadEnv.ts +22 -0
  247. package/resources/login.ts +18 -0
  248. package/resources/openApi.ts +409 -0
  249. package/resources/registrationDeprecated.ts +8 -0
  250. package/resources/replayLogs.ts +136 -0
  251. package/resources/roles.ts +98 -0
  252. package/resources/search.ts +1301 -0
  253. package/resources/tracked.ts +584 -0
  254. package/resources/transaction.ts +89 -0
  255. package/resources/transactionBroadcast.ts +258 -0
  256. package/security/auth.ts +376 -0
  257. package/security/certificateVerification/certificateVerificationSource.ts +84 -0
  258. package/security/certificateVerification/configValidation.ts +107 -0
  259. package/security/certificateVerification/crlVerification.ts +623 -0
  260. package/security/certificateVerification/index.ts +121 -0
  261. package/security/certificateVerification/ocspVerification.ts +148 -0
  262. package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
  263. package/security/certificateVerification/types.ts +128 -0
  264. package/security/certificateVerification/verificationConfig.ts +138 -0
  265. package/security/certificateVerification/verificationUtils.ts +447 -0
  266. package/security/cryptoHash.js +42 -0
  267. package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
  268. package/security/data_objects/PermissionResponseObject.js +115 -0
  269. package/security/data_objects/PermissionTableResponseObject.js +20 -0
  270. package/security/fastifyAuth.js +169 -0
  271. package/security/impersonation.ts +160 -0
  272. package/security/jsLoader.ts +716 -0
  273. package/security/keys.js +948 -0
  274. package/security/permissionsTranslator.js +300 -0
  275. package/security/role.js +218 -0
  276. package/security/tokenAuthentication.ts +228 -0
  277. package/security/user.ts +449 -0
  278. package/server/DurableSubscriptionsSession.ts +503 -0
  279. package/server/REST.ts +407 -0
  280. package/server/Server.ts +89 -0
  281. package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
  282. package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
  283. package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
  284. package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
  285. package/server/fastifyRoutes.ts +205 -0
  286. package/server/graphqlQuerying.ts +700 -0
  287. package/server/http.ts +640 -0
  288. package/server/itc/serverHandlers.js +161 -0
  289. package/server/itc/utility/ITCEventObject.js +10 -0
  290. package/server/jobs/JobObject.js +24 -0
  291. package/server/jobs/jobProcess.js +69 -0
  292. package/server/jobs/jobRunner.js +162 -0
  293. package/server/jobs/jobs.js +304 -0
  294. package/server/loadRootComponents.js +44 -0
  295. package/server/mqtt.ts +485 -0
  296. package/server/nodeName.ts +75 -0
  297. package/server/operationsServer.ts +313 -0
  298. package/server/serverHelpers/Headers.ts +108 -0
  299. package/server/serverHelpers/JSONStream.ts +269 -0
  300. package/server/serverHelpers/OperationFunctionObject.ts +13 -0
  301. package/server/serverHelpers/Request.ts +158 -0
  302. package/server/serverHelpers/contentTypes.ts +637 -0
  303. package/server/serverHelpers/requestTimePlugin.js +57 -0
  304. package/server/serverHelpers/serverHandlers.js +148 -0
  305. package/server/serverHelpers/serverUtilities.ts +473 -0
  306. package/server/serverRegistry.ts +8 -0
  307. package/server/static.ts +187 -0
  308. package/server/status/definitions.ts +37 -0
  309. package/server/status/index.ts +125 -0
  310. package/server/storageReclamation.ts +93 -0
  311. package/server/threads/itc.js +89 -0
  312. package/server/threads/manageThreads.js +594 -0
  313. package/server/threads/socketRouter.ts +360 -0
  314. package/server/threads/threadServer.js +279 -0
  315. package/server/throttle.ts +73 -0
  316. package/sqlTranslator/SelectValidator.js +330 -0
  317. package/sqlTranslator/alasqlFunctionImporter.js +62 -0
  318. package/sqlTranslator/deleteTranslator.js +67 -0
  319. package/sqlTranslator/index.js +242 -0
  320. package/sqlTranslator/sql_statement_bucket.js +472 -0
  321. package/static/defaultConfig.yaml +3 -0
  322. package/studio/web/HDBDogOnly.svg +78 -0
  323. package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
  324. package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
  325. package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
  326. package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
  327. package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
  328. package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
  329. package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
  330. package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
  331. package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
  332. package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
  333. package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
  334. package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
  335. package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
  336. package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
  337. package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
  338. package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
  339. package/studio/web/assets/index-BTgXJX9d.js +235 -0
  340. package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
  341. package/studio/web/assets/index-C-GXfcup.js +37 -0
  342. package/studio/web/assets/index-C-GXfcup.js.map +1 -0
  343. package/studio/web/assets/index-PFlNdimM.js +2 -0
  344. package/studio/web/assets/index-PFlNdimM.js.map +1 -0
  345. package/studio/web/assets/index-Y2g_iFpU.css +1 -0
  346. package/studio/web/assets/index-jiPwkrsB.css +1 -0
  347. package/studio/web/assets/index.lazy-C3TJZJ4o.js +266 -0
  348. package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
  349. package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
  350. package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
  351. package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
  352. package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
  353. package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
  354. package/studio/web/assets/startRecording-B_9J9Csd.js.map +1 -0
  355. package/studio/web/fabric-signup-background.webp +0 -0
  356. package/studio/web/fabric-signup-text.png +0 -0
  357. package/studio/web/favicon_purple.png +0 -0
  358. package/studio/web/github-icon.svg +15 -0
  359. package/studio/web/harper-fabric_black.png +0 -0
  360. package/studio/web/harper-fabric_white.png +0 -0
  361. package/studio/web/harper-studio_white.png +0 -0
  362. package/studio/web/index.html +16 -0
  363. package/studio/web/running.css +148 -0
  364. package/studio/web/running.html +147 -0
  365. package/studio/web/running.js +111 -0
  366. package/upgrade/UpgradeObjects.js +13 -0
  367. package/upgrade/directives/directivesController.js +90 -0
  368. package/upgrade/directivesManager.js +139 -0
  369. package/upgrade/upgradePrompt.js +124 -0
  370. package/upgrade/upgradeUtilities.js +28 -0
  371. package/utility/AWS/AWSConnector.js +29 -0
  372. package/utility/OperationFunctionCaller.js +63 -0
  373. package/utility/assignCmdEnvVariables.js +62 -0
  374. package/utility/common_utils.js +867 -0
  375. package/utility/environment/environmentManager.js +208 -0
  376. package/utility/environment/systemInformation.js +355 -0
  377. package/utility/errors/commonErrors.js +267 -0
  378. package/utility/errors/hdbError.js +146 -0
  379. package/utility/functions/date/dateFunctions.js +65 -0
  380. package/utility/functions/geo.js +355 -0
  381. package/utility/functions/sql/alaSQLExtension.js +104 -0
  382. package/utility/globalSchema.js +35 -0
  383. package/utility/hdbTerms.ts +819 -0
  384. package/utility/install/checkJWTTokensExist.js +62 -0
  385. package/utility/install/harperdb.conf +15 -0
  386. package/utility/install/harperdb.service +14 -0
  387. package/utility/install/installer.js +635 -0
  388. package/utility/installation.ts +30 -0
  389. package/utility/lmdb/DBIDefinition.js +20 -0
  390. package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
  391. package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
  392. package/utility/lmdb/OpenDBIObject.js +31 -0
  393. package/utility/lmdb/OpenEnvironmentObject.js +41 -0
  394. package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
  395. package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
  396. package/utility/lmdb/cleanLMDBMap.js +65 -0
  397. package/utility/lmdb/commonUtility.js +119 -0
  398. package/utility/lmdb/deleteUtility.js +128 -0
  399. package/utility/lmdb/environmentUtility.js +477 -0
  400. package/utility/lmdb/searchCursorFunctions.js +187 -0
  401. package/utility/lmdb/searchUtility.js +918 -0
  402. package/utility/lmdb/terms.js +57 -0
  403. package/utility/lmdb/writeUtility.js +407 -0
  404. package/utility/logging/harper_logger.js +876 -0
  405. package/utility/logging/logRotator.js +157 -0
  406. package/utility/logging/logger.ts +24 -0
  407. package/utility/logging/readLog.js +355 -0
  408. package/utility/logging/transactionLog.js +57 -0
  409. package/utility/mount_hdb.js +59 -0
  410. package/utility/npmUtilities.js +102 -0
  411. package/utility/operationPermissions.ts +112 -0
  412. package/utility/operation_authorization.js +836 -0
  413. package/utility/packageUtils.js +55 -0
  414. package/utility/password.ts +99 -0
  415. package/utility/processManagement/processManagement.js +187 -0
  416. package/utility/processManagement/servicesConfig.js +56 -0
  417. package/utility/scripts/restartHdb.js +24 -0
  418. package/utility/scripts/user_data.sh +13 -0
  419. package/utility/signalling.js +36 -0
  420. package/utility/terms/certificates.js +81 -0
  421. package/utility/when.ts +20 -0
  422. package/v1.d.ts +39 -0
  423. package/v1.js +41 -0
  424. package/v2.d.ts +39 -0
  425. package/v2.js +41 -0
  426. package/validation/bulkDeleteValidator.js +24 -0
  427. package/validation/check_permissions.js +19 -0
  428. package/validation/common_validators.js +95 -0
  429. package/validation/configValidator.js +331 -0
  430. package/validation/deleteValidator.js +15 -0
  431. package/validation/fileLoadValidator.js +153 -0
  432. package/validation/insertValidator.js +40 -0
  433. package/validation/installValidator.js +37 -0
  434. package/validation/readLogValidator.js +64 -0
  435. package/validation/role_validation.js +320 -0
  436. package/validation/schemaMetadataValidator.js +42 -0
  437. package/validation/searchValidator.js +166 -0
  438. package/validation/statusValidator.ts +66 -0
  439. package/validation/transactionLogValidator.js +33 -0
  440. package/validation/user_validation.js +55 -0
  441. package/validation/validationWrapper.js +105 -0
  442. package/dist/resources/analytics/profile.d.ts +0 -2
  443. package/dist/resources/analytics/profile.js +0 -144
  444. 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,6 @@
1
+ import { Scope } from './Scope';
2
+
3
+ export interface PluginModule {
4
+ handleApplication: (scope: Scope) => void | Promise<void>;
5
+ defaultTimeout?: number;
6
+ }
@@ -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
+ }