@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.3

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 (446) 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/{resources/ResourceInterfaceV2.js → components/Logger.js} +1 -1
  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 +17 -10
  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/ResourceInterface.d.ts +1 -1
  145. package/dist/resources/RocksIndexStore.d.ts +3 -3
  146. package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
  147. package/dist/resources/Table.d.ts +15 -6
  148. package/dist/resources/Table.js +12 -4
  149. package/dist/resources/Table.js.map +1 -1
  150. package/dist/resources/analytics/read.js +32 -22
  151. package/dist/resources/analytics/read.js.map +1 -1
  152. package/dist/resources/analytics/write.js +3 -6
  153. package/dist/resources/analytics/write.js.map +1 -1
  154. package/dist/resources/auditStore.d.ts +3 -3
  155. package/dist/resources/blob.d.ts +25 -2
  156. package/dist/resources/databases.d.ts +12 -2
  157. package/dist/resources/databases.js +22 -19
  158. package/dist/resources/databases.js.map +1 -1
  159. package/dist/resources/search.js +11 -5
  160. package/dist/resources/search.js.map +1 -1
  161. package/dist/resources/transaction.d.ts +2 -1
  162. package/dist/security/auth.js +1 -1
  163. package/dist/security/auth.js.map +1 -1
  164. package/dist/security/cryptoHash.d.ts +2 -2
  165. package/dist/security/jsLoader.js +265 -73
  166. package/dist/security/jsLoader.js.map +1 -1
  167. package/dist/security/keys.js +11 -12
  168. package/dist/security/keys.js.map +1 -1
  169. package/dist/security/user.js +3 -3
  170. package/dist/security/user.js.map +1 -1
  171. package/dist/server/REST.js +16 -2
  172. package/dist/server/REST.js.map +1 -1
  173. package/dist/server/Server.d.ts +2 -1
  174. package/dist/server/Server.js.map +1 -1
  175. package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
  176. package/dist/server/fastifyRoutes.js +2 -0
  177. package/dist/server/fastifyRoutes.js.map +1 -1
  178. package/dist/server/http.js +12 -6
  179. package/dist/server/http.js.map +1 -1
  180. package/dist/server/jobs/JobObject.d.ts +3 -3
  181. package/dist/server/loadRootComponents.js +1 -0
  182. package/dist/server/loadRootComponents.js.map +1 -1
  183. package/dist/server/operationsServer.js +3 -1
  184. package/dist/server/operationsServer.js.map +1 -1
  185. package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
  186. package/dist/server/serverHelpers/Request.d.ts +5 -5
  187. package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
  188. package/dist/server/threads/manageThreads.d.ts +2 -2
  189. package/dist/server/threads/manageThreads.js +52 -35
  190. package/dist/server/threads/manageThreads.js.map +1 -1
  191. package/dist/server/threads/socketRouter.d.ts +1 -1
  192. package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
  193. package/dist/utility/AWS/AWSConnector.d.ts +3 -2
  194. package/dist/utility/common_utils.d.ts +3 -3
  195. package/dist/utility/environment/systemInformation.d.ts +1 -0
  196. package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
  197. package/dist/utility/globalSchema.d.ts +1 -1
  198. package/dist/utility/hdbTerms.d.ts +3 -0
  199. package/dist/utility/hdbTerms.js +3 -0
  200. package/dist/utility/hdbTerms.js.map +1 -1
  201. package/dist/utility/installation.d.ts +2 -4
  202. package/dist/utility/installation.js.map +1 -1
  203. package/dist/utility/lmdb/commonUtility.d.ts +2 -1
  204. package/dist/utility/lmdb/commonUtility.js +20 -13
  205. package/dist/utility/lmdb/commonUtility.js.map +1 -1
  206. package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
  207. package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
  208. package/dist/utility/lmdb/searchUtility.d.ts +2 -1
  209. package/dist/utility/lmdb/writeUtility.d.ts +1 -0
  210. package/dist/utility/logging/harper_logger.d.ts +6 -6
  211. package/dist/utility/processManagement/processManagement.d.ts +1 -1
  212. package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
  213. package/dist/validation/common_validators.d.ts +4 -3
  214. package/dist/validation/configValidator.d.ts +3 -2
  215. package/index.d.ts +56 -0
  216. package/index.js +41 -0
  217. package/json/systemSchema.json +373 -0
  218. package/launchServiceScripts/launchHarperDB.js +3 -0
  219. package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
  220. package/package.json +35 -16
  221. package/resources/DatabaseTransaction.ts +378 -0
  222. package/resources/ErrorResource.ts +57 -0
  223. package/resources/IterableEventQueue.ts +94 -0
  224. package/resources/LMDBTransaction.ts +349 -0
  225. package/resources/RecordEncoder.ts +702 -0
  226. package/resources/RequestTarget.ts +134 -0
  227. package/resources/Resource.ts +789 -0
  228. package/resources/ResourceInterface.ts +221 -0
  229. package/resources/Resources.ts +162 -0
  230. package/resources/RocksIndexStore.ts +70 -0
  231. package/resources/RocksTransactionLogStore.ts +352 -0
  232. package/resources/Table.ts +4531 -0
  233. package/resources/analytics/hostnames.ts +72 -0
  234. package/resources/analytics/metadata.ts +10 -0
  235. package/resources/analytics/read.ts +252 -0
  236. package/resources/analytics/write.ts +803 -0
  237. package/resources/auditStore.ts +556 -0
  238. package/resources/blob.ts +1268 -0
  239. package/resources/crdt.ts +125 -0
  240. package/resources/dataLoader.ts +527 -0
  241. package/resources/databases.ts +1290 -0
  242. package/resources/graphql.ts +221 -0
  243. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
  244. package/resources/indexes/customIndexes.ts +7 -0
  245. package/resources/indexes/vector.ts +38 -0
  246. package/resources/jsResource.ts +86 -0
  247. package/resources/loadEnv.ts +22 -0
  248. package/resources/login.ts +18 -0
  249. package/resources/openApi.ts +409 -0
  250. package/resources/registrationDeprecated.ts +8 -0
  251. package/resources/replayLogs.ts +136 -0
  252. package/resources/roles.ts +98 -0
  253. package/resources/search.ts +1301 -0
  254. package/resources/tracked.ts +584 -0
  255. package/resources/transaction.ts +89 -0
  256. package/resources/transactionBroadcast.ts +258 -0
  257. package/security/auth.ts +376 -0
  258. package/security/certificateVerification/certificateVerificationSource.ts +84 -0
  259. package/security/certificateVerification/configValidation.ts +107 -0
  260. package/security/certificateVerification/crlVerification.ts +623 -0
  261. package/security/certificateVerification/index.ts +121 -0
  262. package/security/certificateVerification/ocspVerification.ts +148 -0
  263. package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
  264. package/security/certificateVerification/types.ts +128 -0
  265. package/security/certificateVerification/verificationConfig.ts +138 -0
  266. package/security/certificateVerification/verificationUtils.ts +447 -0
  267. package/security/cryptoHash.js +42 -0
  268. package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
  269. package/security/data_objects/PermissionResponseObject.js +115 -0
  270. package/security/data_objects/PermissionTableResponseObject.js +20 -0
  271. package/security/fastifyAuth.js +169 -0
  272. package/security/impersonation.ts +160 -0
  273. package/security/jsLoader.ts +733 -0
  274. package/security/keys.js +948 -0
  275. package/security/permissionsTranslator.js +300 -0
  276. package/security/role.js +218 -0
  277. package/security/tokenAuthentication.ts +228 -0
  278. package/security/user.ts +449 -0
  279. package/server/DurableSubscriptionsSession.ts +503 -0
  280. package/server/REST.ts +407 -0
  281. package/server/Server.ts +89 -0
  282. package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
  283. package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
  284. package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
  285. package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
  286. package/server/fastifyRoutes.ts +205 -0
  287. package/server/graphqlQuerying.ts +700 -0
  288. package/server/http.ts +640 -0
  289. package/server/itc/serverHandlers.js +161 -0
  290. package/server/itc/utility/ITCEventObject.js +10 -0
  291. package/server/jobs/JobObject.js +24 -0
  292. package/server/jobs/jobProcess.js +69 -0
  293. package/server/jobs/jobRunner.js +162 -0
  294. package/server/jobs/jobs.js +304 -0
  295. package/server/loadRootComponents.js +44 -0
  296. package/server/mqtt.ts +485 -0
  297. package/server/nodeName.ts +75 -0
  298. package/server/operationsServer.ts +313 -0
  299. package/server/serverHelpers/Headers.ts +108 -0
  300. package/server/serverHelpers/JSONStream.ts +269 -0
  301. package/server/serverHelpers/OperationFunctionObject.ts +13 -0
  302. package/server/serverHelpers/Request.ts +158 -0
  303. package/server/serverHelpers/contentTypes.ts +637 -0
  304. package/server/serverHelpers/requestTimePlugin.js +57 -0
  305. package/server/serverHelpers/serverHandlers.js +148 -0
  306. package/server/serverHelpers/serverUtilities.ts +473 -0
  307. package/server/serverRegistry.ts +8 -0
  308. package/server/static.ts +187 -0
  309. package/server/status/definitions.ts +37 -0
  310. package/server/status/index.ts +125 -0
  311. package/server/storageReclamation.ts +93 -0
  312. package/server/threads/itc.js +89 -0
  313. package/server/threads/manageThreads.js +596 -0
  314. package/server/threads/socketRouter.ts +360 -0
  315. package/server/threads/threadServer.js +279 -0
  316. package/server/throttle.ts +73 -0
  317. package/sqlTranslator/SelectValidator.js +330 -0
  318. package/sqlTranslator/alasqlFunctionImporter.js +62 -0
  319. package/sqlTranslator/deleteTranslator.js +67 -0
  320. package/sqlTranslator/index.js +242 -0
  321. package/sqlTranslator/sql_statement_bucket.js +472 -0
  322. package/static/defaultConfig.yaml +3 -0
  323. package/studio/web/HDBDogOnly.svg +78 -0
  324. package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
  325. package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
  326. package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
  327. package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
  328. package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
  329. package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
  330. package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
  331. package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
  332. package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
  333. package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
  334. package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
  335. package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
  336. package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
  337. package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
  338. package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
  339. package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
  340. package/studio/web/assets/index-C1G-Jo6n.js +37 -0
  341. package/studio/web/assets/index-C1G-Jo6n.js.map +1 -0
  342. package/studio/web/assets/index-D-CahN0-.js +2 -0
  343. package/studio/web/assets/index-D-CahN0-.js.map +1 -0
  344. package/studio/web/assets/index-DxlZI0PX.js +235 -0
  345. package/studio/web/assets/index-DxlZI0PX.js.map +1 -0
  346. package/studio/web/assets/index-Y2g_iFpU.css +1 -0
  347. package/studio/web/assets/index-jiPwkrsB.css +1 -0
  348. package/studio/web/assets/index.lazy-BUXDDqq9.js +266 -0
  349. package/studio/web/assets/index.lazy-BUXDDqq9.js.map +1 -0
  350. package/studio/web/assets/profiler-CU93QiSW.js +2 -0
  351. package/studio/web/assets/profiler-CU93QiSW.js.map +1 -0
  352. package/studio/web/assets/react-redux-B8k9Ep7e.js +6 -0
  353. package/studio/web/assets/react-redux-B8k9Ep7e.js.map +1 -0
  354. package/studio/web/assets/startRecording-DFeBXGk6.js +3 -0
  355. package/studio/web/assets/startRecording-DFeBXGk6.js.map +1 -0
  356. package/studio/web/fabric-signup-background.webp +0 -0
  357. package/studio/web/fabric-signup-text.png +0 -0
  358. package/studio/web/favicon_purple.png +0 -0
  359. package/studio/web/github-icon.svg +15 -0
  360. package/studio/web/harper-fabric_black.png +0 -0
  361. package/studio/web/harper-fabric_white.png +0 -0
  362. package/studio/web/harper-studio_white.png +0 -0
  363. package/studio/web/index.html +16 -0
  364. package/studio/web/running.css +148 -0
  365. package/studio/web/running.html +147 -0
  366. package/studio/web/running.js +111 -0
  367. package/upgrade/UpgradeObjects.js +13 -0
  368. package/upgrade/directives/directivesController.js +90 -0
  369. package/upgrade/directivesManager.js +139 -0
  370. package/upgrade/upgradePrompt.js +124 -0
  371. package/upgrade/upgradeUtilities.js +28 -0
  372. package/utility/AWS/AWSConnector.js +29 -0
  373. package/utility/OperationFunctionCaller.js +63 -0
  374. package/utility/assignCmdEnvVariables.js +62 -0
  375. package/utility/common_utils.js +867 -0
  376. package/utility/environment/environmentManager.js +208 -0
  377. package/utility/environment/systemInformation.js +355 -0
  378. package/utility/errors/commonErrors.js +267 -0
  379. package/utility/errors/hdbError.js +146 -0
  380. package/utility/functions/date/dateFunctions.js +65 -0
  381. package/utility/functions/geo.js +355 -0
  382. package/utility/functions/sql/alaSQLExtension.js +104 -0
  383. package/utility/globalSchema.js +35 -0
  384. package/utility/hdbTerms.ts +819 -0
  385. package/utility/install/checkJWTTokensExist.js +62 -0
  386. package/utility/install/harperdb.conf +15 -0
  387. package/utility/install/harperdb.service +14 -0
  388. package/utility/install/installer.js +635 -0
  389. package/utility/installation.ts +30 -0
  390. package/utility/lmdb/DBIDefinition.js +20 -0
  391. package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
  392. package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
  393. package/utility/lmdb/OpenDBIObject.js +31 -0
  394. package/utility/lmdb/OpenEnvironmentObject.js +41 -0
  395. package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
  396. package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
  397. package/utility/lmdb/cleanLMDBMap.js +65 -0
  398. package/utility/lmdb/commonUtility.js +130 -0
  399. package/utility/lmdb/deleteUtility.js +128 -0
  400. package/utility/lmdb/environmentUtility.js +477 -0
  401. package/utility/lmdb/searchCursorFunctions.js +187 -0
  402. package/utility/lmdb/searchUtility.js +918 -0
  403. package/utility/lmdb/terms.js +57 -0
  404. package/utility/lmdb/writeUtility.js +407 -0
  405. package/utility/logging/harper_logger.js +876 -0
  406. package/utility/logging/logRotator.js +157 -0
  407. package/utility/logging/logger.ts +24 -0
  408. package/utility/logging/readLog.js +355 -0
  409. package/utility/logging/transactionLog.js +57 -0
  410. package/utility/mount_hdb.js +59 -0
  411. package/utility/npmUtilities.js +102 -0
  412. package/utility/operationPermissions.ts +112 -0
  413. package/utility/operation_authorization.js +836 -0
  414. package/utility/packageUtils.js +55 -0
  415. package/utility/password.ts +99 -0
  416. package/utility/processManagement/processManagement.js +187 -0
  417. package/utility/processManagement/servicesConfig.js +56 -0
  418. package/utility/scripts/restartHdb.js +24 -0
  419. package/utility/scripts/user_data.sh +13 -0
  420. package/utility/signalling.js +36 -0
  421. package/utility/terms/certificates.js +81 -0
  422. package/utility/when.ts +20 -0
  423. package/validation/bulkDeleteValidator.js +24 -0
  424. package/validation/check_permissions.js +19 -0
  425. package/validation/common_validators.js +95 -0
  426. package/validation/configValidator.js +331 -0
  427. package/validation/deleteValidator.js +15 -0
  428. package/validation/fileLoadValidator.js +153 -0
  429. package/validation/insertValidator.js +40 -0
  430. package/validation/installValidator.js +37 -0
  431. package/validation/readLogValidator.js +64 -0
  432. package/validation/role_validation.js +320 -0
  433. package/validation/schemaMetadataValidator.js +42 -0
  434. package/validation/searchValidator.js +166 -0
  435. package/validation/statusValidator.ts +66 -0
  436. package/validation/transactionLogValidator.js +33 -0
  437. package/validation/user_validation.js +55 -0
  438. package/validation/validationWrapper.js +105 -0
  439. package/dist/resources/ResourceInterfaceV2.d.ts +0 -21
  440. package/dist/resources/ResourceInterfaceV2.js.map +0 -1
  441. package/dist/resources/ResourceV2.d.ts +0 -30
  442. package/dist/resources/ResourceV2.js +0 -27
  443. package/dist/resources/ResourceV2.js.map +0 -1
  444. package/dist/resources/analytics/profile.d.ts +0 -2
  445. package/dist/resources/analytics/profile.js +0 -144
  446. package/dist/resources/analytics/profile.js.map +0 -1
@@ -0,0 +1,503 @@
1
+ import { table } from '../resources/databases.ts';
2
+ import { keyArrayToString, resources } from '../resources/Resources.ts';
3
+ import { getNextMonotonicTime } from '../utility/lmdb/commonUtility.js';
4
+ import { warn, trace } from '../utility/logging/harper_logger.js';
5
+ import { transaction } from '../resources/transaction.ts';
6
+ import { getWorkerIndex } from '../server/threads/manageThreads.js';
7
+ import { whenComponentsLoaded } from '../server/threads/threadServer.js';
8
+ import { server } from '../server/Server.ts';
9
+ import { RequestTarget } from '../resources/RequestTarget';
10
+ import { cloneDeep } from 'lodash';
11
+
12
+ const AWAITING_ACKS_HIGH_WATER_MARK = 100;
13
+ const DurableSession = table({
14
+ database: 'system',
15
+ table: 'hdb_durable_session',
16
+ attributes: [
17
+ { name: 'id', isPrimaryKey: true },
18
+ {
19
+ name: 'subscriptions',
20
+ type: 'array',
21
+ elements: {
22
+ attributes: [{ name: 'topic' }, { name: 'qos' }, { name: 'startTime' }, { name: 'acks' }],
23
+ },
24
+ },
25
+ ],
26
+ });
27
+ const LastWill = table({
28
+ database: 'system',
29
+ table: 'hdb_session_will',
30
+ attributes: [
31
+ { name: 'id', isPrimaryKey: true },
32
+ { name: 'topic', type: 'string' },
33
+ { name: 'data' },
34
+ { name: 'qos', type: 'number' },
35
+ { name: 'retain', type: 'boolean' },
36
+ { name: 'user', type: 'any' },
37
+ ],
38
+ });
39
+ if (getWorkerIndex() === 0) {
40
+ (async () => {
41
+ await whenComponentsLoaded;
42
+ await new Promise((resolve) => setTimeout(resolve, 2000));
43
+ for await (const will of LastWill.search({})) {
44
+ const data = will.data;
45
+ const message = { ...will };
46
+ if (message.user?.username) message.user = await server.getUser(message.user.username);
47
+ try {
48
+ await publish(message, data, message);
49
+ } catch {
50
+ warn('Failed to publish will', data);
51
+ }
52
+ LastWill.delete(will.id);
53
+ }
54
+ })();
55
+ }
56
+
57
+ /**
58
+ * This is used for durable sessions, that is sessions in MQTT that are not "clean" sessions (and with QoS >= 1
59
+ * subscriptions) and durable AMQP queues, with real-time communication and reliable delivery that requires tracking
60
+ * delivery and acknowledgement. This particular function is used to start or retrieve such a session.
61
+ * A session can be durable (maintains state) or clean (no state). A durable session is stored in a system table as a
62
+ * record that holds a list of subscriptions (topic and QoS), the timestamp of last message, and any unacked messages
63
+ * before the timestamp. Once this is returned, it makes the subscription "live", actively routing data through it. Any
64
+ * catch-up from topics, that is subscriptions to records, need to be performed first.
65
+ * The structure is designed such that no changes need to be made to it while it is at "rest". That means that if there
66
+ * are no active listeners to this session, no active processing of subscriptions and matching messages needs to be
67
+ * performed. All subscription handling can be resumed when the session is reconnected, and can be performed on the
68
+ * node that is active. The timestamps indicate all updates that need to be retrieved prior to being live again.
69
+ * Note, that this could be contrasted with a continuously active session or queue, that is continually monitoring
70
+ * for published messages on subscribed topics. This would require a continuous process to perform routing, and on
71
+ * a distributed network, it could be extremely difficult and unclear who should manage and handle this. This would also
72
+ * involve extra overhead when sessions are not active, and may never be accessed again. With our approach, an
73
+ * abandoned durable session can simply sit idle with no resources taken, and optionally expired by simply deleting the
74
+ * session record at some point.
75
+ * However, because resuming durable sessions requires catch-up on subscriptions, this means we must have facilities in
76
+ * place for being able to query for the log of changes/messages on each of the subscribed records of interest. We do
77
+ * this by querying the audit log, but we will need to ensure the audit log is enabled on any tables/records that receive
78
+ * subscriptions.
79
+ * @param sessionId
80
+ * @param user
81
+ * @param nonDurable
82
+ */
83
+ export async function getSession({
84
+ clientId: sessionId,
85
+ user,
86
+ clean: nonDurable,
87
+ will,
88
+ keepalive,
89
+ }: {
90
+ clientId;
91
+ user;
92
+ listener: Function;
93
+ clean?: boolean;
94
+ will: any;
95
+ keepalive?: number;
96
+ }) {
97
+ let session;
98
+ if (sessionId && !nonDurable) {
99
+ const sessionResource = await DurableSession.get(sessionId, { returnNonexistent: true });
100
+ session = new DurableSubscriptionsSession(sessionId, user, sessionResource);
101
+ if (sessionResource) session.sessionWasPresent = true;
102
+ } else {
103
+ if (sessionId) {
104
+ // connecting with a clean session and session id is how durable sessions are deleted
105
+ const sessionResource = await DurableSession.get(sessionId);
106
+ if (sessionResource) DurableSession.delete(sessionId);
107
+ }
108
+ session = new SubscriptionsSession(sessionId, user);
109
+ }
110
+ if (will) {
111
+ will.id = sessionId;
112
+ will.user = { username: user?.username };
113
+ LastWill.put(will);
114
+ }
115
+ if (keepalive) {
116
+ // keep alive is the interval in seconds that the client will send a ping to the server
117
+ // if the server does not receive a ping within 1.5 times the keep alive interval, it will
118
+ // disconnect the client
119
+ session.keepalive = keepalive;
120
+ session.receivedPacket(); // start the keepalive timer
121
+ }
122
+ return session;
123
+ }
124
+ let nextMessageId = 1;
125
+ function getNextMessageId() {
126
+ nextMessageId++;
127
+ // MQTT only supports 16-bit message ids, so must roll over before getting beyond 16-bit ids.
128
+ if (nextMessageId > 65500) nextMessageId = 1;
129
+ return nextMessageId;
130
+ }
131
+ type Acknowledgement = {
132
+ topic?: string;
133
+ timestamp?: number;
134
+ acknowledge?: () => any;
135
+ };
136
+
137
+ class SubscriptionsSession {
138
+ listener: (message, subscription, timestamp, qos) => any;
139
+ sessionId: any;
140
+ user: any;
141
+ request: any;
142
+ socket: any;
143
+ subscriptions = [];
144
+ awaitingAcks: Map<number, Acknowledgement>;
145
+ sessionWasPresent: boolean;
146
+ keepalive: number;
147
+ keepaliveTimer: any;
148
+ constructor(sessionId, user) {
149
+ this.sessionId = sessionId;
150
+ this.user = user;
151
+ }
152
+ async addSubscription(subscriptionRequest, needsAck, filter?) {
153
+ const { topic, rh: retainHandling, startTime } = subscriptionRequest;
154
+ const searchIndex = topic.indexOf('?');
155
+ let path;
156
+ if (searchIndex > -1) {
157
+ path = topic.slice(0, searchIndex);
158
+ } else path = topic;
159
+ if (!path) throw new Error('No topic provided');
160
+ if (path.indexOf('.') > -1) throw new Error('Dots are not allowed in topic names');
161
+ // might be faster to somehow modify existing subscription and re-get the retained record, but this should work for now
162
+ const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
163
+ let omitCurrent;
164
+ if (existingSubscription) {
165
+ omitCurrent = retainHandling > 0;
166
+ existingSubscription.end();
167
+ this.subscriptions.splice(this.subscriptions.indexOf(existingSubscription), 1);
168
+ } else {
169
+ omitCurrent = retainHandling === 2;
170
+ }
171
+ if (startTime) trace('Resuming subscription from', topic, 'from', startTime);
172
+ const entry = resources.getMatch(path, 'mqtt');
173
+ if (!entry) {
174
+ const notFoundError = new Error(
175
+ `The topic ${topic} does not exist, no resource has been defined to handle this topic`
176
+ );
177
+ notFoundError.statusCode = 404;
178
+ throw notFoundError;
179
+ }
180
+ let url = entry.relativeURL;
181
+ let isCollection;
182
+ let onlyChildren;
183
+ let hashIndex: number;
184
+ if (url.indexOf('+') > -1 || (hashIndex = url.indexOf('#')) > -1) {
185
+ const path = url.slice(1); // remove leading slash
186
+ hashIndex--; // adjust accordingly
187
+ if (hashIndex > -1 && hashIndex !== path.length - 1)
188
+ throw new Error('Multi-level wildcards can only be used at the end of a topic');
189
+ // treat as a collection to get all children, but we will need to filter out any that are not direct children or matching the pattern
190
+ isCollection = true; // used by Resource to determine if the resource should be treated as a collection
191
+ if (path.indexOf('+') === path.length - 1) {
192
+ // if it is only a trailing single-level wildcard, we can treat it as a shallow wildcard
193
+ // and use the optimized onlyChildren option, which will be faster, and does not require any filtering
194
+ onlyChildren = true;
195
+ url = '/' + path.slice(0, path.length - 1);
196
+ } else {
197
+ // otherwise we have a potentially complex wildcard, so we will need to filter out any that are not direct children or matching the pattern
198
+ const matchingPath = path.split('/');
199
+ let needsFilter;
200
+ for (let i = 0; i < matchingPath.length; i++) {
201
+ if (matchingPath[i].indexOf('+') > -1) {
202
+ if (matchingPath[i] === '+') needsFilter = true;
203
+ else throw new Error('Single-level wildcards can only be used as a topic level (between or after slashes)');
204
+ }
205
+ }
206
+ if (filter && needsFilter) throw new Error('Filters can not be combined');
207
+
208
+ let mustMatchLength = true;
209
+ if (matchingPath[matchingPath.length - 1] === '#') {
210
+ // only for any extra topic levels beyond the matching path
211
+ matchingPath.length--;
212
+ mustMatchLength = false;
213
+ }
214
+ if (needsFilter) {
215
+ filter = (update) => {
216
+ let updatePath = update.id;
217
+ if (!Array.isArray(updatePath)) {
218
+ if (updatePath?.indexOf?.('/') > -1) {
219
+ // if it is a string with slashes, we can split it into an array
220
+ updatePath = updatePath.split('/');
221
+ } else {
222
+ return false;
223
+ }
224
+ }
225
+ if (mustMatchLength && updatePath.length !== matchingPath.length) return false;
226
+ for (let i = 0; i < matchingPath.length; i++) {
227
+ if (matchingPath[i] !== '+' && matchingPath[i] !== updatePath[i]) return false;
228
+ }
229
+ return true;
230
+ };
231
+ }
232
+ const firstWildcard = matchingPath.indexOf('+');
233
+ url = '/' + (firstWildcard > -1 ? matchingPath.slice(0, firstWildcard) : matchingPath).concat('').join('/');
234
+ }
235
+ } else isCollection = false; // must explicitly turn this off so topics that end in a slash are not treated as collections
236
+ const request = new RequestTarget(url);
237
+ Object.assign(request, {
238
+ isCollection,
239
+ onlyChildren,
240
+ startTime,
241
+ omitCurrent,
242
+ checkPermission: this.user?.role?.permission ?? {},
243
+ });
244
+ const resourcePath = entry.path;
245
+ const resource = entry.Resource;
246
+ const context = this.createContext();
247
+ context.topic = topic;
248
+ context.retainHandling = retainHandling;
249
+ context.isCollection = request.isCollection;
250
+ const subscription = await transaction(context, async () => {
251
+ const subscription = await resource.subscribe(request, context);
252
+ if (!subscription) {
253
+ return; // if no subscription, nothing to return
254
+ }
255
+ if (!subscription[Symbol.asyncIterator])
256
+ throw new Error(`Subscription is not (async) iterable for topic ${topic}`);
257
+ const _result = (async () => {
258
+ for await (const update of subscription) {
259
+ try {
260
+ let messageId;
261
+ if (
262
+ update.type &&
263
+ update.type !== 'put' &&
264
+ update.type !== 'delete' &&
265
+ update.type !== 'message' &&
266
+ update.type !== 'patch'
267
+ )
268
+ continue;
269
+ if (filter && !filter(update)) continue;
270
+ if (needsAck) {
271
+ update.topic = topic;
272
+ messageId = this.needsAcknowledge(update);
273
+ } else {
274
+ // There is no ack to wait for. We can immediately notify any interested source
275
+ // that we have sent the message
276
+ update.acknowledge?.();
277
+ messageId = getNextMessageId();
278
+ }
279
+ let path = update.id;
280
+ if (Array.isArray(path)) path = keyArrayToString(path);
281
+ if (path == null) path = '';
282
+ const result = await this.listener(resourcePath + '/' + path, update.value, messageId, subscriptionRequest);
283
+ if (result === false) break;
284
+ if (this.awaitingAcks?.size > AWAITING_ACKS_HIGH_WATER_MARK) {
285
+ // slow it down if we are getting too far ahead in acks
286
+ await new Promise((resolve) =>
287
+ setTimeout(resolve, this.awaitingAcks.size - AWAITING_ACKS_HIGH_WATER_MARK)
288
+ );
289
+ } else await new Promise(setImmediate); // yield event turn
290
+ } catch (error) {
291
+ warn(error);
292
+ }
293
+ }
294
+ })();
295
+ return subscription;
296
+ });
297
+ if (!subscription) return;
298
+ subscription.topic = topic;
299
+ subscription.qos = subscriptionRequest.qos;
300
+ this.subscriptions.push(subscription);
301
+ return subscription;
302
+ }
303
+ resume() {
304
+ // nothing to do in a clean session
305
+ }
306
+ needsAcknowledge(update) {
307
+ const messageId = getNextMessageId();
308
+ if (update.acknowledge) {
309
+ // only need to track if the source wants acknowledgements
310
+ if (!this.awaitingAcks) this.awaitingAcks = new Map();
311
+ this.awaitingAcks.set(messageId, { acknowledge: update.acknowledge });
312
+ }
313
+ return messageId;
314
+ }
315
+ acknowledge(messageId) {
316
+ const acknowledgement = this.awaitingAcks?.get(messageId);
317
+ if (acknowledgement) {
318
+ this.awaitingAcks.delete(messageId);
319
+ acknowledgement.acknowledge();
320
+ }
321
+ }
322
+ async removeSubscription(topic) {
323
+ // might be faster to somehow modify existing subscription and re-get the retained record, but this should work for now
324
+ const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
325
+ if (existingSubscription) {
326
+ // end the subscription, cleanup
327
+ existingSubscription.end();
328
+ // remove from our list of subscriptions
329
+ this.subscriptions.splice(this.subscriptions.indexOf(existingSubscription), 1);
330
+ return true;
331
+ }
332
+ }
333
+ async publish(message, data) {
334
+ // each publish gets it own context so that each publish gets it own transaction
335
+ return publish(message, data, this.createContext());
336
+ }
337
+ createContext(): any {
338
+ const context = {
339
+ session: this,
340
+ socket: this.socket,
341
+ user: this.user,
342
+ authorize: true, // authorize each action
343
+ };
344
+ if (this.request) {
345
+ context.request = this.request;
346
+ context.url = this.request.url;
347
+ context.headers = this.request.headers;
348
+ }
349
+ return context;
350
+ }
351
+ setListener(listener: (message) => any) {
352
+ this.listener = listener;
353
+ }
354
+ disconnect(clientTerminated) {
355
+ if (this.keepaliveTimer) clearTimeout(this.keepaliveTimer);
356
+ const context = this.createContext();
357
+ transaction(context, async () => {
358
+ try {
359
+ if (!clientTerminated) {
360
+ const will = await LastWill.get(this.sessionId);
361
+ if (will) {
362
+ await publish(will, will.data, context);
363
+ }
364
+ }
365
+ } finally {
366
+ await LastWill.delete(this.sessionId);
367
+ }
368
+ }).catch((error) => {
369
+ warn(`Error publishing MQTT will for ${this.sessionId}`, error);
370
+ });
371
+
372
+ for (const subscription of this.subscriptions) {
373
+ subscription.end();
374
+ }
375
+ this.subscriptions = [];
376
+ }
377
+ receivedPacket() {
378
+ if (this.keepalive) {
379
+ clearTimeout(this.keepaliveTimer);
380
+ this.keepaliveTimer = setTimeout(() => {
381
+ if (this.socket?.destroy) this.socket.destroy(new Error('Keepalive timeout'));
382
+ else this.socket?.terminate();
383
+ }, this.keepalive * 1500);
384
+ }
385
+ }
386
+ }
387
+ function publish(message, data, context) {
388
+ const { topic, retain } = message;
389
+ message = { ...message, data, async: true };
390
+ context.authorize = true;
391
+ const entry = resources.getMatch(topic, 'mqtt');
392
+ if (!entry)
393
+ throw new Error(
394
+ `Can not publish to topic ${topic} as it does not exist, no resource has been defined to handle this topic`
395
+ );
396
+ message.url = entry.relativeURL;
397
+ const target = new RequestTarget(entry.relativeURL);
398
+ target.checkPermission = context.user?.role?.permission ?? {};
399
+
400
+ const resource = entry.Resource;
401
+
402
+ return transaction(context, () => {
403
+ return retain
404
+ ? data === undefined
405
+ ? resource.delete(target, context)
406
+ : resource.put(target, message.data, context)
407
+ : resource.publish(target, message.data, context);
408
+ });
409
+ }
410
+ export class DurableSubscriptionsSession extends SubscriptionsSession {
411
+ sessionRecord: any;
412
+ constructor(sessionId, user, record?) {
413
+ super(sessionId, user);
414
+ this.sessionRecord = cloneDeep(record) || { id: sessionId, subscriptions: [] };
415
+ }
416
+ async resume() {
417
+ // resuming a session, we need to resume each subscription
418
+ for (const subscription of this.sessionRecord.subscriptions || []) {
419
+ await this.resumeSubscription(
420
+ { omitCurrent: true, topic: subscription.topic, qos: subscription.qos, startTime: subscription.startTime },
421
+ true,
422
+ subscription.acks
423
+ ? (update) => {
424
+ return !subscription.acks.includes(update.localTime);
425
+ }
426
+ : null
427
+ );
428
+ }
429
+ }
430
+ resumeSubscription(subscription, needsAck, filter?) {
431
+ return super.addSubscription(subscription, needsAck, filter);
432
+ }
433
+ needsAcknowledge(update) {
434
+ if (!this.awaitingAcks) this.awaitingAcks = new Map();
435
+ const messageId = getNextMessageId();
436
+ const ackInfo: Acknowledgement = {
437
+ topic: update.topic,
438
+ timestamp: update.localTime,
439
+ };
440
+ if (update.acknowledge) ackInfo.acknowledge = update.acknowledge;
441
+ this.awaitingAcks.set(messageId, ackInfo);
442
+ return messageId;
443
+ }
444
+ acknowledge(messageId) {
445
+ const update = this.awaitingAcks?.get(messageId);
446
+ if (!update) return;
447
+ this.awaitingAcks?.delete(messageId);
448
+ update.acknowledge?.();
449
+ const topic = update.topic;
450
+ for (const [, remainingUpdate] of this.awaitingAcks) {
451
+ if (remainingUpdate.topic === topic) {
452
+ if (remainingUpdate.timestamp < update.timestamp) {
453
+ // this is an out of order ack, so instead of updating the timestamp, we record as an out-of-order ack
454
+ for (const subscription of this.sessionRecord.subscriptions) {
455
+ if (subscription.topic === topic) {
456
+ if (!subscription.acks) {
457
+ subscription.acks = [];
458
+ }
459
+ subscription.acks.push(update.timestamp);
460
+ trace('Received ack', topic, update.timestamp);
461
+ DurableSession.put(this.sessionRecord);
462
+ return;
463
+ }
464
+ }
465
+ }
466
+ }
467
+ }
468
+
469
+ for (const subscription of this.sessionRecord.subscriptions) {
470
+ if (subscription.topic === topic) {
471
+ subscription.startTime = update.timestamp;
472
+ }
473
+ }
474
+ DurableSession.put(this.sessionRecord);
475
+ // TODO: Increment the timestamp for the corresponding subscription, possibly recording any interim unacked messages
476
+ }
477
+
478
+ async addSubscription(subscription, needsAck) {
479
+ await this.resumeSubscription(subscription, needsAck);
480
+ const { qos, startTime } = subscription;
481
+ if (qos > 0 && !startTime) this.saveSubscriptions();
482
+ return subscription.qos;
483
+ }
484
+ removeSubscription(topic) {
485
+ const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
486
+ const result = super.removeSubscription(topic);
487
+ if (existingSubscription.qos > 0) this.saveSubscriptions();
488
+ return result;
489
+ }
490
+ saveSubscriptions() {
491
+ this.sessionRecord.subscriptions = this.subscriptions.map((subscription) => {
492
+ let startTime = subscription.startTime;
493
+ if (!startTime) startTime = subscription.startTime = getNextMonotonicTime();
494
+ trace('Added durable subscription', subscription.topic, startTime);
495
+ return {
496
+ qos: subscription.qos,
497
+ topic: subscription.topic,
498
+ startTime,
499
+ };
500
+ });
501
+ DurableSession.put(this.sessionRecord);
502
+ }
503
+ }