@harperfast/harper 5.2.13 → 5.3.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 (655) hide show
  1. package/agent/mcpTools.ts +1 -1
  2. package/agent/session.ts +25 -14
  3. package/bin/cliOperations.ts +58 -9
  4. package/bin/copyDb.ts +282 -59
  5. package/bin/deploySetup.ts +16 -5
  6. package/bin/harper.ts +1 -1
  7. package/bin/help.ts +4 -1
  8. package/bin/lite.ts +4 -1
  9. package/bin/restart.ts +120 -4
  10. package/bin/run.ts +6 -11
  11. package/bin/upgrade.js +7 -3
  12. package/bin/workloadIdentity.ts +119 -0
  13. package/components/Application.ts +3436 -242
  14. package/components/ApplicationScope.ts +8 -0
  15. package/components/EntryHandler.ts +59 -39
  16. package/components/OptionsWatcher.ts +440 -98
  17. package/components/RuntimeModuleTracker.ts +38 -7
  18. package/components/Scope.ts +56 -15
  19. package/components/awaitRestart.ts +84 -0
  20. package/components/componentLoader.ts +381 -32
  21. package/components/componentPreparationLock.ts +16 -5
  22. package/components/deploymentOperations.ts +4 -1
  23. package/components/deploymentRecorder.ts +9 -2
  24. package/components/mcp/adapters/harperHttp.ts +4 -0
  25. package/components/mcp/listChanged.ts +4 -0
  26. package/components/mcp/toolRegistry.ts +2 -0
  27. package/components/mcp/tools/operations.ts +9 -0
  28. package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
  29. package/components/operations.js +537 -113
  30. package/components/operationsValidation.js +98 -3
  31. package/components/packageComponent.ts +25 -1
  32. package/components/requestRestart.ts +11 -0
  33. package/components/status/ComponentStatusRegistry.ts +59 -0
  34. package/config/RootConfigWatcher.ts +240 -40
  35. package/config/configReadRetry.ts +62 -0
  36. package/config/configUtils.ts +357 -48
  37. package/config/harperConfigEnvVars.ts +170 -27
  38. package/config/parseConfigFile.ts +34 -0
  39. package/config/readConfigFileSync.ts +44 -0
  40. package/config/watcherArming.ts +59 -0
  41. package/config-root.schema.json +33 -0
  42. package/dataLayer/blobBackup.ts +160 -50
  43. package/dataLayer/delete.ts +6 -1
  44. package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
  45. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  46. package/dataLayer/hdbInfoController.ts +34 -1
  47. package/dataLayer/insert.ts +44 -1
  48. package/dataLayer/rocksdbBackup.ts +53 -10
  49. package/dataLayer/schema.ts +11 -1
  50. package/dataLayer/schemaDescribe.ts +8 -1
  51. package/dist/agent/mcpTools.js +1 -1
  52. package/dist/agent/mcpTools.js.map +1 -1
  53. package/dist/agent/session.d.ts +22 -0
  54. package/dist/agent/session.js +26 -15
  55. package/dist/agent/session.js.map +1 -1
  56. package/dist/bin/cliOperations.js +61 -9
  57. package/dist/bin/cliOperations.js.map +1 -1
  58. package/dist/bin/copyDb.d.ts +12 -1
  59. package/dist/bin/copyDb.js +248 -60
  60. package/dist/bin/copyDb.js.map +1 -1
  61. package/dist/bin/deploySetup.d.ts +2 -0
  62. package/dist/bin/deploySetup.js +11 -3
  63. package/dist/bin/deploySetup.js.map +1 -1
  64. package/dist/bin/harper.js +1 -1
  65. package/dist/bin/harper.js.map +1 -1
  66. package/dist/bin/help.js +4 -1
  67. package/dist/bin/help.js.map +1 -1
  68. package/dist/bin/lite.js +4 -1
  69. package/dist/bin/lite.js.map +1 -1
  70. package/dist/bin/restart.js +91 -6
  71. package/dist/bin/restart.js.map +1 -1
  72. package/dist/bin/run.js +4 -10
  73. package/dist/bin/run.js.map +1 -1
  74. package/dist/bin/upgrade.js +4 -3
  75. package/dist/bin/upgrade.js.map +1 -1
  76. package/dist/bin/workloadIdentity.d.ts +18 -0
  77. package/dist/bin/workloadIdentity.js +100 -0
  78. package/dist/bin/workloadIdentity.js.map +1 -0
  79. package/dist/components/Application.d.ts +235 -17
  80. package/dist/components/Application.js +3038 -238
  81. package/dist/components/Application.js.map +1 -1
  82. package/dist/components/ApplicationScope.d.ts +8 -0
  83. package/dist/components/ApplicationScope.js +7 -0
  84. package/dist/components/ApplicationScope.js.map +1 -1
  85. package/dist/components/EntryHandler.js +26 -10
  86. package/dist/components/EntryHandler.js.map +1 -1
  87. package/dist/components/OptionsWatcher.d.ts +4 -0
  88. package/dist/components/OptionsWatcher.js +440 -99
  89. package/dist/components/OptionsWatcher.js.map +1 -1
  90. package/dist/components/RuntimeModuleTracker.js +40 -6
  91. package/dist/components/RuntimeModuleTracker.js.map +1 -1
  92. package/dist/components/Scope.js +52 -13
  93. package/dist/components/Scope.js.map +1 -1
  94. package/dist/components/awaitRestart.d.ts +33 -0
  95. package/dist/components/awaitRestart.js +61 -0
  96. package/dist/components/awaitRestart.js.map +1 -0
  97. package/dist/components/componentLoader.d.ts +38 -1
  98. package/dist/components/componentLoader.js +313 -24
  99. package/dist/components/componentLoader.js.map +1 -1
  100. package/dist/components/componentPreparationLock.d.ts +5 -0
  101. package/dist/components/componentPreparationLock.js +14 -6
  102. package/dist/components/componentPreparationLock.js.map +1 -1
  103. package/dist/components/deploymentOperations.js +4 -1
  104. package/dist/components/deploymentOperations.js.map +1 -1
  105. package/dist/components/deploymentRecorder.d.ts +4 -2
  106. package/dist/components/deploymentRecorder.js +1 -0
  107. package/dist/components/deploymentRecorder.js.map +1 -1
  108. package/dist/components/mcp/adapters/harperHttp.js +4 -0
  109. package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
  110. package/dist/components/mcp/listChanged.js +5 -0
  111. package/dist/components/mcp/listChanged.js.map +1 -1
  112. package/dist/components/mcp/toolRegistry.d.ts +1 -0
  113. package/dist/components/mcp/toolRegistry.js.map +1 -1
  114. package/dist/components/mcp/tools/operations.d.ts +5 -0
  115. package/dist/components/mcp/tools/operations.js +9 -0
  116. package/dist/components/mcp/tools/operations.js.map +1 -1
  117. package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
  118. package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
  119. package/dist/components/operations.d.ts +28 -0
  120. package/dist/components/operations.js +476 -113
  121. package/dist/components/operations.js.map +1 -1
  122. package/dist/components/operationsValidation.js +97 -3
  123. package/dist/components/operationsValidation.js.map +1 -1
  124. package/dist/components/packageComponent.js +24 -0
  125. package/dist/components/packageComponent.js.map +1 -1
  126. package/dist/components/requestRestart.d.ts +1 -0
  127. package/dist/components/requestRestart.js +7 -0
  128. package/dist/components/requestRestart.js.map +1 -1
  129. package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
  130. package/dist/components/status/ComponentStatusRegistry.js +63 -0
  131. package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
  132. package/dist/config/RootConfigWatcher.d.ts +9 -1
  133. package/dist/config/RootConfigWatcher.js +228 -37
  134. package/dist/config/RootConfigWatcher.js.map +1 -1
  135. package/dist/config/configReadRetry.d.ts +8 -0
  136. package/dist/config/configReadRetry.js +62 -0
  137. package/dist/config/configReadRetry.js.map +1 -0
  138. package/dist/config/configUtils.d.ts +11 -2
  139. package/dist/config/configUtils.js +304 -47
  140. package/dist/config/configUtils.js.map +1 -1
  141. package/dist/config/harperConfigEnvVars.d.ts +16 -0
  142. package/dist/config/harperConfigEnvVars.js +162 -25
  143. package/dist/config/harperConfigEnvVars.js.map +1 -1
  144. package/dist/config/parseConfigFile.d.ts +4 -0
  145. package/dist/config/parseConfigFile.js +35 -0
  146. package/dist/config/parseConfigFile.js.map +1 -0
  147. package/dist/config/readConfigFileSync.d.ts +1 -0
  148. package/dist/config/readConfigFileSync.js +47 -0
  149. package/dist/config/readConfigFileSync.js.map +1 -0
  150. package/dist/config/watcherArming.d.ts +15 -0
  151. package/dist/config/watcherArming.js +59 -0
  152. package/dist/config/watcherArming.js.map +1 -0
  153. package/dist/dataLayer/blobBackup.d.ts +49 -20
  154. package/dist/dataLayer/blobBackup.js +139 -50
  155. package/dist/dataLayer/blobBackup.js.map +1 -1
  156. package/dist/dataLayer/delete.js +1 -1
  157. package/dist/dataLayer/delete.js.map +1 -1
  158. package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
  159. package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
  160. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  161. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
  162. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  163. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
  164. package/dist/dataLayer/hdbInfoController.d.ts +10 -0
  165. package/dist/dataLayer/hdbInfoController.js +30 -1
  166. package/dist/dataLayer/hdbInfoController.js.map +1 -1
  167. package/dist/dataLayer/insert.d.ts +9 -1
  168. package/dist/dataLayer/insert.js +30 -0
  169. package/dist/dataLayer/insert.js.map +1 -1
  170. package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
  171. package/dist/dataLayer/rocksdbBackup.js +45 -8
  172. package/dist/dataLayer/rocksdbBackup.js.map +1 -1
  173. package/dist/dataLayer/schema.js +8 -0
  174. package/dist/dataLayer/schema.js.map +1 -1
  175. package/dist/dataLayer/schemaDescribe.js +8 -1
  176. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  177. package/dist/index.d.ts +2 -1
  178. package/dist/index.js +4 -1
  179. package/dist/index.js.map +1 -1
  180. package/dist/json/systemSchema.json +55 -0
  181. package/dist/resources/DatabaseTransaction.d.ts +77 -0
  182. package/dist/resources/DatabaseTransaction.js +586 -54
  183. package/dist/resources/DatabaseTransaction.js.map +1 -1
  184. package/dist/resources/LMDBTransaction.d.ts +2 -1
  185. package/dist/resources/LMDBTransaction.js +43 -6
  186. package/dist/resources/LMDBTransaction.js.map +1 -1
  187. package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
  188. package/dist/resources/PrimaryRocksDatabase.js +49 -5
  189. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  190. package/dist/resources/RecordEncoder.d.ts +20 -0
  191. package/dist/resources/RecordEncoder.js +110 -9
  192. package/dist/resources/RecordEncoder.js.map +1 -1
  193. package/dist/resources/RequestTarget.d.ts +2 -0
  194. package/dist/resources/RequestTarget.js.map +1 -1
  195. package/dist/resources/Resource.js +117 -24
  196. package/dist/resources/Resource.js.map +1 -1
  197. package/dist/resources/ResourceInterface.d.ts +28 -1
  198. package/dist/resources/ResourceInterface.js.map +1 -1
  199. package/dist/resources/RocksIndexStore.d.ts +6 -1
  200. package/dist/resources/RocksIndexStore.js +24 -9
  201. package/dist/resources/RocksIndexStore.js.map +1 -1
  202. package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
  203. package/dist/resources/RocksTransactionLogStore.js +160 -49
  204. package/dist/resources/RocksTransactionLogStore.js.map +1 -1
  205. package/dist/resources/Table.d.ts +165 -10
  206. package/dist/resources/Table.js +1805 -303
  207. package/dist/resources/Table.js.map +1 -1
  208. package/dist/resources/analytics/write.js +10 -3
  209. package/dist/resources/analytics/write.js.map +1 -1
  210. package/dist/resources/auditStore.d.ts +181 -2
  211. package/dist/resources/auditStore.js +640 -29
  212. package/dist/resources/auditStore.js.map +1 -1
  213. package/dist/resources/blob.d.ts +129 -9
  214. package/dist/resources/blob.js +992 -114
  215. package/dist/resources/blob.js.map +1 -1
  216. package/dist/resources/branchDatabase.d.ts +48 -0
  217. package/dist/resources/branchDatabase.js +892 -0
  218. package/dist/resources/branchDatabase.js.map +1 -0
  219. package/dist/resources/crdt.js +50 -12
  220. package/dist/resources/crdt.js.map +1 -1
  221. package/dist/resources/dataLoader.js +3 -4
  222. package/dist/resources/dataLoader.js.map +1 -1
  223. package/dist/resources/databases.d.ts +157 -14
  224. package/dist/resources/databases.js +1462 -325
  225. package/dist/resources/databases.js.map +1 -1
  226. package/dist/resources/defineTable.d.ts +10 -2
  227. package/dist/resources/defineTable.js +9 -1
  228. package/dist/resources/defineTable.js.map +1 -1
  229. package/dist/resources/derivedIndexRegistry.d.ts +5 -0
  230. package/dist/resources/derivedIndexRegistry.js +68 -0
  231. package/dist/resources/derivedIndexRegistry.js.map +1 -0
  232. package/dist/resources/derivedIndexRuntime.d.ts +215 -0
  233. package/dist/resources/derivedIndexRuntime.js +2027 -0
  234. package/dist/resources/derivedIndexRuntime.js.map +1 -0
  235. package/dist/resources/graphql.d.ts +1 -1
  236. package/dist/resources/graphql.js +52 -16
  237. package/dist/resources/graphql.js.map +1 -1
  238. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
  239. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
  240. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  241. package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
  242. package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
  243. package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
  244. package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
  245. package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
  246. package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
  247. package/dist/resources/longLivedTransactions.d.ts +71 -0
  248. package/dist/resources/longLivedTransactions.js +358 -0
  249. package/dist/resources/longLivedTransactions.js.map +1 -0
  250. package/dist/resources/models/backendRegistry.d.ts +26 -0
  251. package/dist/resources/models/backendRegistry.js +60 -2
  252. package/dist/resources/models/backendRegistry.js.map +1 -1
  253. package/dist/resources/models/bootstrap.d.ts +33 -1
  254. package/dist/resources/models/bootstrap.js +416 -31
  255. package/dist/resources/models/bootstrap.js.map +1 -1
  256. package/dist/resources/nodeIdMapping.d.ts +5 -0
  257. package/dist/resources/nodeIdMapping.js +49 -0
  258. package/dist/resources/nodeIdMapping.js.map +1 -1
  259. package/dist/resources/recordLock.d.ts +123 -0
  260. package/dist/resources/recordLock.js +315 -0
  261. package/dist/resources/recordLock.js.map +1 -0
  262. package/dist/resources/recordLockCoordinator.d.ts +557 -0
  263. package/dist/resources/recordLockCoordinator.js +2565 -0
  264. package/dist/resources/recordLockCoordinator.js.map +1 -0
  265. package/dist/resources/replayLogs.d.ts +14 -1
  266. package/dist/resources/replayLogs.js +157 -24
  267. package/dist/resources/replayLogs.js.map +1 -1
  268. package/dist/resources/replayLogsGuards.d.ts +94 -7
  269. package/dist/resources/replayLogsGuards.js +111 -7
  270. package/dist/resources/replayLogsGuards.js.map +1 -1
  271. package/dist/resources/replicatedApplyFailure.d.ts +16 -0
  272. package/dist/resources/replicatedApplyFailure.js +63 -0
  273. package/dist/resources/replicatedApplyFailure.js.map +1 -0
  274. package/dist/resources/scheduler/scheduler.js +3 -3
  275. package/dist/resources/scheduler/scheduler.js.map +1 -1
  276. package/dist/resources/search.d.ts +10 -4
  277. package/dist/resources/search.js +283 -37
  278. package/dist/resources/search.js.map +1 -1
  279. package/dist/resources/tracked.d.ts +5 -1
  280. package/dist/resources/tracked.js +74 -23
  281. package/dist/resources/tracked.js.map +1 -1
  282. package/dist/resources/transactionBroadcast.d.ts +1 -1
  283. package/dist/resources/transactionBroadcast.js +2 -2
  284. package/dist/resources/transactionBroadcast.js.map +1 -1
  285. package/dist/security/auth.js +61 -30
  286. package/dist/security/auth.js.map +1 -1
  287. package/dist/security/authn/oidc/claims.d.ts +22 -0
  288. package/dist/security/authn/oidc/claims.js +71 -0
  289. package/dist/security/authn/oidc/claims.js.map +1 -0
  290. package/dist/security/authn/oidc/identityToken.d.ts +27 -0
  291. package/dist/security/authn/oidc/identityToken.js +111 -0
  292. package/dist/security/authn/oidc/identityToken.js.map +1 -0
  293. package/dist/security/authn/oidc/jwks.d.ts +25 -0
  294. package/dist/security/authn/oidc/jwks.js +261 -0
  295. package/dist/security/authn/oidc/jwks.js.map +1 -0
  296. package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
  297. package/dist/security/authn/oidc/providers/generic.js +34 -0
  298. package/dist/security/authn/oidc/providers/generic.js.map +1 -0
  299. package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
  300. package/dist/security/authn/oidc/providers/githubActions.js +129 -0
  301. package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
  302. package/dist/security/authn/oidc/providers/index.d.ts +37 -0
  303. package/dist/security/authn/oidc/providers/index.js +24 -0
  304. package/dist/security/authn/oidc/providers/index.js.map +1 -0
  305. package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
  306. package/dist/security/authn/oidc/tokenExchange.js +306 -0
  307. package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
  308. package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
  309. package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
  310. package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
  311. package/dist/security/authn/oidc/types.d.ts +38 -0
  312. package/dist/security/authn/oidc/types.js +6 -0
  313. package/dist/security/authn/oidc/types.js.map +1 -0
  314. package/dist/security/certificateVerification/index.js +40 -11
  315. package/dist/security/certificateVerification/index.js.map +1 -1
  316. package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
  317. package/dist/security/certificateVerification/trustedIssuers.js +79 -0
  318. package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
  319. package/dist/security/certificateVerification/types.d.ts +1 -0
  320. package/dist/security/credentialProvenance.d.ts +35 -0
  321. package/dist/security/credentialProvenance.js +51 -0
  322. package/dist/security/credentialProvenance.js.map +1 -0
  323. package/dist/security/credentialRejection.d.ts +4 -0
  324. package/dist/security/credentialRejection.js +24 -0
  325. package/dist/security/credentialRejection.js.map +1 -0
  326. package/dist/security/deferredAuthentication.d.ts +36 -0
  327. package/dist/security/deferredAuthentication.js +70 -0
  328. package/dist/security/deferredAuthentication.js.map +1 -0
  329. package/dist/security/impersonation.d.ts +21 -0
  330. package/dist/security/impersonation.js +108 -9
  331. package/dist/security/impersonation.js.map +1 -1
  332. package/dist/security/jsLoader.d.ts +6 -0
  333. package/dist/security/jsLoader.js +77 -15
  334. package/dist/security/jsLoader.js.map +1 -1
  335. package/dist/security/keys.js +301 -71
  336. package/dist/security/keys.js.map +1 -1
  337. package/dist/security/operationScope.d.ts +21 -0
  338. package/dist/security/operationScope.js +36 -0
  339. package/dist/security/operationScope.js.map +1 -0
  340. package/dist/security/permissionsTranslator.js +21 -0
  341. package/dist/security/permissionsTranslator.js.map +1 -1
  342. package/dist/security/tokenAuthentication.d.ts +19 -1
  343. package/dist/security/tokenAuthentication.js +191 -10
  344. package/dist/security/tokenAuthentication.js.map +1 -1
  345. package/dist/security/user.js +4 -3
  346. package/dist/security/user.js.map +1 -1
  347. package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
  348. package/dist/server/DurableSubscriptionsSession.js +67 -10
  349. package/dist/server/DurableSubscriptionsSession.js.map +1 -1
  350. package/dist/server/REST.js +106 -2
  351. package/dist/server/REST.js.map +1 -1
  352. package/dist/server/graphqlQuerying.js +4 -0
  353. package/dist/server/graphqlQuerying.js.map +1 -1
  354. package/dist/server/http.d.ts +16 -1
  355. package/dist/server/http.js +122 -17
  356. package/dist/server/http.js.map +1 -1
  357. package/dist/server/itc/serverHandlers.js +8 -1
  358. package/dist/server/itc/serverHandlers.js.map +1 -1
  359. package/dist/server/jobs/jobProcess.js +6 -2
  360. package/dist/server/jobs/jobProcess.js.map +1 -1
  361. package/dist/server/jobs/jobs.js +4 -1
  362. package/dist/server/jobs/jobs.js.map +1 -1
  363. package/dist/server/liveSubscriptionAuth.d.ts +26 -4
  364. package/dist/server/liveSubscriptionAuth.js +105 -39
  365. package/dist/server/liveSubscriptionAuth.js.map +1 -1
  366. package/dist/server/loadRootComponents.js +49 -10
  367. package/dist/server/loadRootComponents.js.map +1 -1
  368. package/dist/server/mqtt.d.ts +2 -0
  369. package/dist/server/mqtt.js +165 -30
  370. package/dist/server/mqtt.js.map +1 -1
  371. package/dist/server/nodeName.d.ts +2 -0
  372. package/dist/server/nodeName.js +107 -23
  373. package/dist/server/nodeName.js.map +1 -1
  374. package/dist/server/serverHelpers/Headers.d.ts +27 -0
  375. package/dist/server/serverHelpers/Headers.js +145 -1
  376. package/dist/server/serverHelpers/Headers.js.map +1 -1
  377. package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
  378. package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
  379. package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
  380. package/dist/server/serverHelpers/Request.d.ts +5 -10
  381. package/dist/server/serverHelpers/Request.js +38 -136
  382. package/dist/server/serverHelpers/Request.js.map +1 -1
  383. package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
  384. package/dist/server/serverHelpers/contentTypes.js +221 -40
  385. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  386. package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
  387. package/dist/server/serverHelpers/deployValidationState.js +9 -19
  388. package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
  389. package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
  390. package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
  391. package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
  392. package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
  393. package/dist/server/serverHelpers/registeredOperations.js +74 -21
  394. package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
  395. package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
  396. package/dist/server/serverHelpers/requestSanitization.js +20 -0
  397. package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
  398. package/dist/server/serverHelpers/serverHandlers.js +6 -3
  399. package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
  400. package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
  401. package/dist/server/serverHelpers/serverUtilities.js +178 -29
  402. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  403. package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
  404. package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
  405. package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
  406. package/dist/server/serverHelpers/uwsServer.js +19 -1
  407. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  408. package/dist/server/static.js +24 -28
  409. package/dist/server/static.js.map +1 -1
  410. package/dist/server/storageReclamation.d.ts +5 -0
  411. package/dist/server/storageReclamation.js +17 -1
  412. package/dist/server/storageReclamation.js.map +1 -1
  413. package/dist/server/threads/isolatedApplications.d.ts +47 -0
  414. package/dist/server/threads/isolatedApplications.js +171 -0
  415. package/dist/server/threads/isolatedApplications.js.map +1 -0
  416. package/dist/server/threads/itc.d.ts +7 -2
  417. package/dist/server/threads/itc.js +5 -1
  418. package/dist/server/threads/itc.js.map +1 -1
  419. package/dist/server/threads/logRotationTransport.d.ts +1 -0
  420. package/dist/server/threads/logRotationTransport.js +33 -0
  421. package/dist/server/threads/logRotationTransport.js.map +1 -0
  422. package/dist/server/threads/manageThreads.d.ts +83 -3
  423. package/dist/server/threads/manageThreads.js +769 -75
  424. package/dist/server/threads/manageThreads.js.map +1 -1
  425. package/dist/server/threads/socketRouter.d.ts +1 -0
  426. package/dist/server/threads/socketRouter.js +277 -31
  427. package/dist/server/threads/socketRouter.js.map +1 -1
  428. package/dist/server/threads/threadHeapMemory.d.ts +2 -0
  429. package/dist/server/threads/threadHeapMemory.js +31 -0
  430. package/dist/server/threads/threadHeapMemory.js.map +1 -0
  431. package/dist/server/threads/threadServer.js +76 -22
  432. package/dist/server/threads/threadServer.js.map +1 -1
  433. package/dist/sqlEngine/config.d.ts +1 -3
  434. package/dist/sqlEngine/config.js +19 -16
  435. package/dist/sqlEngine/config.js.map +1 -1
  436. package/dist/sqlTranslator/index.d.ts +1 -1
  437. package/dist/sqlTranslator/index.js +30 -7
  438. package/dist/sqlTranslator/index.js.map +1 -1
  439. package/dist/upgrade/directives/5-3-0.d.ts +7 -0
  440. package/dist/upgrade/directives/5-3-0.js +148 -0
  441. package/dist/upgrade/directives/5-3-0.js.map +1 -0
  442. package/dist/upgrade/directives/directivesController.js +2 -1
  443. package/dist/upgrade/directives/directivesController.js.map +1 -1
  444. package/dist/utility/OperationFunctionCaller.js +2 -1
  445. package/dist/utility/OperationFunctionCaller.js.map +1 -1
  446. package/dist/utility/common_utils.d.ts +16 -0
  447. package/dist/utility/common_utils.js +32 -6
  448. package/dist/utility/common_utils.js.map +1 -1
  449. package/dist/utility/componentNames.d.ts +8 -0
  450. package/dist/utility/componentNames.js +12 -1
  451. package/dist/utility/componentNames.js.map +1 -1
  452. package/dist/utility/environment/environmentManager.js +3 -6
  453. package/dist/utility/environment/environmentManager.js.map +1 -1
  454. package/dist/utility/environment/systemInformation.d.ts +1 -0
  455. package/dist/utility/environment/systemInformation.js +1 -0
  456. package/dist/utility/environment/systemInformation.js.map +1 -1
  457. package/dist/utility/errors/commonErrors.d.ts +2 -0
  458. package/dist/utility/errors/commonErrors.js +2 -0
  459. package/dist/utility/errors/commonErrors.js.map +1 -1
  460. package/dist/utility/errors/hdbError.d.ts +33 -0
  461. package/dist/utility/errors/hdbError.js +58 -1
  462. package/dist/utility/errors/hdbError.js.map +1 -1
  463. package/dist/utility/globalSchema.d.ts +18 -0
  464. package/dist/utility/hdbTerms.d.ts +18 -0
  465. package/dist/utility/hdbTerms.js +20 -2
  466. package/dist/utility/hdbTerms.js.map +1 -1
  467. package/dist/utility/logging/harper_logger.d.ts +2 -0
  468. package/dist/utility/logging/harper_logger.js +286 -30
  469. package/dist/utility/logging/harper_logger.js.map +1 -1
  470. package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
  471. package/dist/utility/logging/logGenerationCoordinator.js +184 -0
  472. package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
  473. package/dist/utility/logging/logRotation.d.ts +46 -0
  474. package/dist/utility/logging/logRotation.js +365 -0
  475. package/dist/utility/logging/logRotation.js.map +1 -0
  476. package/dist/utility/logging/logRotator.d.ts +1 -1
  477. package/dist/utility/logging/logRotator.js +192 -85
  478. package/dist/utility/logging/logRotator.js.map +1 -1
  479. package/dist/utility/nodeIdentity.d.ts +9 -0
  480. package/dist/utility/nodeIdentity.js +58 -0
  481. package/dist/utility/nodeIdentity.js.map +1 -0
  482. package/dist/utility/npmUtilities.js +11 -7
  483. package/dist/utility/npmUtilities.js.map +1 -1
  484. package/dist/utility/operationPermissions.d.ts +3 -1
  485. package/dist/utility/operationPermissions.js +16 -1
  486. package/dist/utility/operationPermissions.js.map +1 -1
  487. package/dist/utility/operation_authorization.d.ts +10 -7
  488. package/dist/utility/operation_authorization.js +212 -41
  489. package/dist/utility/operation_authorization.js.map +1 -1
  490. package/dist/utility/watchPath.d.ts +29 -0
  491. package/dist/utility/watchPath.js +68 -0
  492. package/dist/utility/watchPath.js.map +1 -0
  493. package/dist/utility/watcherFallback.d.ts +41 -0
  494. package/dist/utility/watcherFallback.js +153 -0
  495. package/dist/utility/watcherFallback.js.map +1 -1
  496. package/dist/validation/configValidator.d.ts +12 -0
  497. package/dist/validation/configValidator.js +205 -75
  498. package/dist/validation/configValidator.js.map +1 -1
  499. package/dist/validation/installValidator.js +12 -0
  500. package/dist/validation/installValidator.js.map +1 -1
  501. package/dist/validation/validationWrapper.d.ts +11 -0
  502. package/dist/validation/validationWrapper.js +16 -3
  503. package/dist/validation/validationWrapper.js.map +1 -1
  504. package/index.ts +8 -0
  505. package/json/systemSchema.json +55 -0
  506. package/npm-shrinkwrap.json +286 -194
  507. package/package.json +15 -7
  508. package/resources/DESIGN.md +219 -52
  509. package/resources/DatabaseTransaction.ts +657 -52
  510. package/resources/LMDBTransaction.ts +46 -6
  511. package/resources/PrimaryRocksDatabase.ts +46 -7
  512. package/resources/RecordEncoder.ts +124 -9
  513. package/resources/RequestTarget.ts +2 -0
  514. package/resources/Resource.ts +114 -22
  515. package/resources/ResourceInterface.ts +31 -0
  516. package/resources/RocksIndexStore.ts +30 -9
  517. package/resources/RocksTransactionLogStore.ts +188 -51
  518. package/resources/Table.ts +1960 -301
  519. package/resources/analytics/write.ts +10 -3
  520. package/resources/auditStore.ts +647 -32
  521. package/resources/blob.ts +1029 -110
  522. package/resources/branchDatabase.ts +941 -0
  523. package/resources/crdt.ts +76 -12
  524. package/resources/dataLoader.ts +3 -4
  525. package/resources/databases.ts +1584 -320
  526. package/resources/defineTable.ts +18 -2
  527. package/resources/derivedIndexRegistry.ts +56 -0
  528. package/resources/derivedIndexRuntime.ts +2292 -0
  529. package/resources/graphql.ts +72 -17
  530. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
  531. package/resources/indexes/hnswDerivedIndex.ts +531 -0
  532. package/resources/indexes/hnswPlaneBinding.ts +174 -0
  533. package/resources/longLivedTransactions.ts +360 -0
  534. package/resources/models/backendRegistry.ts +84 -2
  535. package/resources/models/bootstrap.ts +473 -28
  536. package/resources/nodeIdMapping.ts +50 -0
  537. package/resources/recordLock.ts +419 -0
  538. package/resources/recordLockCoordinator.ts +3043 -0
  539. package/resources/replayLogs.ts +152 -26
  540. package/resources/replayLogsGuards.ts +171 -8
  541. package/resources/replicatedApplyFailure.ts +77 -0
  542. package/resources/scheduler/scheduler.ts +4 -4
  543. package/resources/search.ts +288 -46
  544. package/resources/tracked.ts +73 -22
  545. package/resources/transactionBroadcast.ts +3 -3
  546. package/security/auth.ts +68 -29
  547. package/security/authn/oidc/claims.ts +72 -0
  548. package/security/authn/oidc/identityToken.ts +129 -0
  549. package/security/authn/oidc/jwks.ts +260 -0
  550. package/security/authn/oidc/providers/generic.ts +40 -0
  551. package/security/authn/oidc/providers/githubActions.ts +137 -0
  552. package/security/authn/oidc/providers/index.ts +52 -0
  553. package/security/authn/oidc/tokenExchange.ts +300 -0
  554. package/security/authn/oidc/trustPolicyOperations.ts +343 -0
  555. package/security/authn/oidc/types.ts +41 -0
  556. package/security/certificateVerification/index.ts +54 -13
  557. package/security/certificateVerification/trustedIssuers.ts +76 -0
  558. package/security/certificateVerification/types.ts +1 -0
  559. package/security/credentialProvenance.ts +47 -0
  560. package/security/credentialRejection.ts +22 -0
  561. package/security/deferredAuthentication.ts +71 -0
  562. package/security/impersonation.ts +117 -12
  563. package/security/jsLoader.ts +83 -18
  564. package/security/keys.ts +298 -72
  565. package/security/operationScope.ts +33 -0
  566. package/security/permissionsTranslator.js +23 -0
  567. package/security/tokenAuthentication.ts +233 -12
  568. package/security/user.ts +4 -3
  569. package/server/DESIGN.md +194 -16
  570. package/server/DurableSubscriptionsSession.ts +71 -11
  571. package/server/REST.ts +115 -4
  572. package/server/graphqlQuerying.ts +4 -0
  573. package/server/http.ts +133 -20
  574. package/server/itc/serverHandlers.js +8 -1
  575. package/server/jobs/jobProcess.ts +8 -2
  576. package/server/jobs/jobs.ts +4 -1
  577. package/server/liveSubscriptionAuth.ts +129 -46
  578. package/server/loadRootComponents.js +50 -8
  579. package/server/mqtt.ts +179 -38
  580. package/server/nodeName.ts +103 -21
  581. package/server/serverHelpers/Headers.ts +135 -0
  582. package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
  583. package/server/serverHelpers/Request.ts +33 -131
  584. package/server/serverHelpers/contentTypes.ts +217 -36
  585. package/server/serverHelpers/deployValidationState.ts +24 -13
  586. package/server/serverHelpers/operationAuthorizationState.ts +34 -3
  587. package/server/serverHelpers/registeredOperations.ts +79 -22
  588. package/server/serverHelpers/requestSanitization.ts +15 -0
  589. package/server/serverHelpers/serverHandlers.js +6 -3
  590. package/server/serverHelpers/serverUtilities.ts +232 -40
  591. package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
  592. package/server/serverHelpers/uwsServer.ts +17 -2
  593. package/server/static.ts +23 -29
  594. package/server/storageReclamation.ts +15 -2
  595. package/server/threads/isolatedApplications.ts +157 -0
  596. package/server/threads/itc.js +11 -1
  597. package/server/threads/logRotationTransport.ts +40 -0
  598. package/server/threads/manageThreads.js +771 -66
  599. package/server/threads/socketRouter.ts +291 -30
  600. package/server/threads/threadHeapMemory.ts +26 -0
  601. package/server/threads/threadServer.js +73 -22
  602. package/sqlTranslator/index.ts +31 -8
  603. package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
  604. package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
  605. package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
  606. package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
  607. package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
  608. package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
  609. package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
  610. package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
  611. package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
  612. package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
  613. package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
  614. package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
  615. package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
  616. package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
  617. package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
  618. package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
  619. package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
  620. package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
  621. package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
  622. package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
  623. package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
  624. package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
  625. package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
  626. package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
  627. package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
  628. package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
  629. package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
  630. package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
  631. package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
  632. package/studio/web/index.html +1 -1
  633. package/upgrade/directives/5-3-0.ts +132 -0
  634. package/upgrade/directives/directivesController.ts +2 -1
  635. package/utility/OperationFunctionCaller.ts +2 -1
  636. package/utility/common_utils.ts +30 -5
  637. package/utility/componentNames.ts +12 -0
  638. package/utility/environment/environmentManager.ts +3 -7
  639. package/utility/environment/systemInformation.ts +7 -0
  640. package/utility/errors/commonErrors.ts +4 -0
  641. package/utility/errors/hdbError.ts +57 -0
  642. package/utility/hdbTerms.ts +19 -0
  643. package/utility/logging/harper_logger.ts +278 -26
  644. package/utility/logging/logGenerationCoordinator.ts +196 -0
  645. package/utility/logging/logRotation.ts +367 -0
  646. package/utility/logging/logRotator.ts +213 -81
  647. package/utility/nodeIdentity.ts +45 -0
  648. package/utility/npmUtilities.ts +12 -8
  649. package/utility/operationPermissions.ts +18 -1
  650. package/utility/operation_authorization.ts +231 -42
  651. package/utility/watchPath.ts +63 -0
  652. package/utility/watcherFallback.ts +148 -0
  653. package/validation/configValidator.ts +215 -75
  654. package/validation/installValidator.ts +15 -0
  655. package/validation/validationWrapper.ts +18 -4
@@ -10,6 +10,10 @@ import * as envMgr from '../../utility/environment/environmentManager.ts';
10
10
  import { CONFIG_PARAMS } from '../../utility/hdbTerms.ts';
11
11
  import * as YAML from 'yaml';
12
12
  import { logger } from '../../utility/logging/logger.ts';
13
+ import {
14
+ errorToString as harperErrorToString,
15
+ errorForLog as harperErrorForLog,
16
+ } from '../../utility/logging/harper_logger.ts';
13
17
  import { Blob } from '../../resources/blob.ts';
14
18
  // TODO: Only load this if fastify is loaded
15
19
  import fp from 'fastify-plugin';
@@ -17,6 +21,36 @@ import { parseMultipartRequest } from './multipartParser.ts';
17
21
  const SERIALIZATION_BIGINT = envMgr.get(CONFIG_PARAMS.SERIALIZATION_BIGINT) !== false;
18
22
  const JSONStringify = SERIALIZATION_BIGINT ? stringify : JSON.stringify;
19
23
  const JSONParse = SERIALIZATION_BIGINT ? parse : JSON.parse;
24
+ const streamStartup = Symbol('streamStartup');
25
+ const serializedStreamError = Symbol('serializedStreamError');
26
+
27
+ type StreamStartup = {
28
+ result: Promise<{ failed?: true; error?: unknown }>;
29
+ abort: () => void;
30
+ start: () => void;
31
+ cancel?: () => void;
32
+ };
33
+
34
+ function streamErrorRecord(error: any) {
35
+ let name = 'Error';
36
+ let message;
37
+ try {
38
+ const code = error?.code;
39
+ if (typeof code === 'string' || typeof code === 'number') name = String(code);
40
+ else if (typeof error?.constructor?.name === 'string') name = error.constructor.name;
41
+ else if (typeof error?.name === 'string') name = error.name;
42
+ } catch {}
43
+ try {
44
+ if (typeof error?.message === 'string') message = error.message;
45
+ } catch {}
46
+ message ??= harperErrorToString(error);
47
+ const record: { error: string; message: string; status?: number } = { error: name, message };
48
+ try {
49
+ const status = error?.statusCode ?? error?.status;
50
+ if (typeof status === 'number') record.status = status;
51
+ } catch {}
52
+ return record;
53
+ }
20
54
 
21
55
  const PUBLIC_ENCODE_OPTIONS = {
22
56
  useRecords: false,
@@ -103,9 +137,14 @@ mediaTypes.set('text/yaml', {
103
137
  });
104
138
 
105
139
  const ndjsonHandler = {
106
- serializeStream(data: any) {
140
+ serializeStream(data: any, _response?: Response, request?: any) {
107
141
  if (data?.[Symbol.iterator] || data?.[Symbol.asyncIterator]) {
108
- return Readable.from(transformIterable(data, (msg: any) => JSONStringify(msg) + '\n'));
142
+ return errorFrameStream(
143
+ data,
144
+ (msg: any) => JSONStringify(msg) + '\n',
145
+ (error) => JSONStringify({ $harperStreamError: streamErrorRecord(error) }) + '\n',
146
+ request?.method === 'GET'
147
+ );
109
148
  }
110
149
  return JSONStringify(data) + '\n';
111
150
  },
@@ -125,11 +164,21 @@ const ndjsonHandler = {
125
164
  mediaTypes.set('application/x-ndjson', ndjsonHandler);
126
165
  mediaTypes.set('application/ndjson', ndjsonHandler);
127
166
 
167
+ function serializeSSEData(data: any) {
168
+ if (typeof data === 'object') return 'data: ' + JSONStringify(data) + '\n';
169
+ return 'data: ' + String(data).replace(/\r\n|\r|\n/g, '\ndata: ') + '\n';
170
+ }
171
+
128
172
  mediaTypes.set('text/event-stream', {
129
173
  // Server-Sent Events (SSE)
130
- serializeStream: function (iterable) {
174
+ serializeStream: function (iterable, _response?: Response, request?: any) {
131
175
  // create a readable stream that we use to stream out events from our subscription
132
- return Readable.from(transformIterable(iterable, this.serialize));
176
+ return errorFrameStream(
177
+ iterable,
178
+ this.serialize,
179
+ (error) => this.serialize({ event: 'harper-error', data: streamErrorRecord(error) }),
180
+ request?.method === 'GET'
181
+ );
133
182
  },
134
183
  serialize: function (message) {
135
184
  if (message.acknowledge) message.acknowledge();
@@ -141,20 +190,20 @@ mediaTypes.set('text/event-stream', {
141
190
  id: message.timestamp,
142
191
  };
143
192
  }
144
- if (message.data || message.event) {
193
+ // A non-null top-level `data` or truthy `event` is an SSE envelope, even with sibling fields.
194
+ // `id`/`retry` alone do not open it: `id` is too common a literal-payload field name (e.g. a
195
+ // database record) to safely treat as an SSE-envelope signal.
196
+ if (message.data != null || message.event) {
145
197
  let serialized = '';
146
198
  if (message.event) serialized += 'event: ' + message.event + '\n';
147
- if (message.data) {
148
- let data = message.data;
149
- if (typeof data === 'object') data = JSONStringify(data);
150
- serialized += 'data: ' + data + '\n';
199
+ if (message.data != null) {
200
+ serialized += serializeSSEData(message.data);
151
201
  }
152
- if (message.id) serialized += 'id: ' + message.id + '\n';
153
- if (message.retry) serialized += 'retry: ' + message.retry + '\n';
202
+ if (message.id != null) serialized += 'id: ' + message.id + '\n';
203
+ if (message.retry != null) serialized += 'retry: ' + message.retry + '\n';
154
204
  return serialized + '\n';
155
205
  } else {
156
- if (typeof message === 'object') return `data: ${JSONStringify(message)}\n\n`;
157
- return `data: ${message}\n\n`;
206
+ return serializeSSEData(message) + '\n';
158
207
  }
159
208
  },
160
209
  compressible: false,
@@ -391,7 +440,12 @@ export function serialize(responseData, request, responseObject) {
391
440
  (responseData[Symbol.iterator] || responseData[Symbol.asyncIterator]) &&
392
441
  serializer.serializer.serializeStream
393
442
  ) {
394
- if (responseData.mapError) {
443
+ if (
444
+ responseData.mapError &&
445
+ serializer.type !== 'application/x-ndjson' &&
446
+ serializer.type !== 'application/ndjson' &&
447
+ serializer.type !== 'text/event-stream'
448
+ ) {
395
449
  // indicate that we want iterator errors to be returned so we can serialize them in a meaningful way, if possible
396
450
  const getColumns = responseData.getColumns;
397
451
  responseData = responseData.mapError((error) => {
@@ -402,9 +456,10 @@ export function serialize(responseData, request, responseObject) {
402
456
  });
403
457
  responseData.getColumns = getColumns;
404
458
  }
405
- let stream = serializer.serializer.serializeStream(responseData, responseObject);
459
+ let stream = serializer.serializer.serializeStream(responseData, responseObject, request);
406
460
  if (canCompress) {
407
461
  responseObject.headers.set('Content-Encoding', 'br');
462
+ const uncompressedStream = stream;
408
463
  stream = stream.pipe(
409
464
  createBrotliCompress({
410
465
  params: {
@@ -416,6 +471,7 @@ export function serialize(responseData, request, responseObject) {
416
471
  },
417
472
  })
418
473
  );
474
+ if (uncompressedStream[streamStartup]) stream[streamStartup] = uncompressedStream[streamStartup];
419
475
  }
420
476
  return stream;
421
477
  }
@@ -436,6 +492,20 @@ export function serialize(responseData, request, responseObject) {
436
492
  }
437
493
 
438
494
  let asyncSerializations: Promise<void>[];
495
+ /**
496
+ * Get the message serializer for a request's negotiated content type, memoized on the request.
497
+ * The returned function is the registered per-content-type serializer, so its identity keys the
498
+ * content type. Caching serialized output across requests under that key is only valid because the
499
+ * built-in serializers are pure functions of their argument — a component registering a serializer
500
+ * into `server.contentTypes` whose output depends on anything else would not be shareable.
501
+ * @param request
502
+ */
503
+ export function getMessageSerializer(request?: Request): (message: any) => Buffer | string {
504
+ if (!request) return JSONStringify;
505
+ let serialize = (request as any).serialize;
506
+ if (!serialize) serialize = (request as any).serialize = findBestSerializer(request).serializer.serialize;
507
+ return serialize;
508
+ }
439
509
  /**
440
510
  * Serialize a message, may be use multiple times (like with WebSockets)
441
511
  * @param message
@@ -450,18 +520,7 @@ export function serializeMessage(
450
520
  if (message?.contentType != null && message.data != null) return message.data;
451
521
  asyncSerializations = inAsyncContinuation ? undefined : [];
452
522
  try {
453
- let serialized: Buffer | string;
454
- if (request) {
455
- let serialize = (request as any).serialize;
456
- if (serialize) serialized = serialize(message);
457
- else {
458
- const serializer = findBestSerializer(request);
459
- serialize = (request as any).serialize = serializer.serializer.serialize;
460
- serialized = serialize(message);
461
- }
462
- } else {
463
- serialized = JSONStringify(message);
464
- }
523
+ const serialized: Buffer | string = getMessageSerializer(request)(message);
465
524
  if (asyncSerializations?.length > 0)
466
525
  // if there were any serialization attempts that must wait for async work to be done, we wait now and then retry the serialization
467
526
  return (asyncSerializations.length === 1 ? asyncSerializations[0] : Promise.all(asyncSerializations)).then(() =>
@@ -615,24 +674,146 @@ function deserializerUnknownType(contentType: ContentType): Deserialize {
615
674
  }
616
675
  }
617
676
 
618
- function transformIterable(iterable, transform) {
677
+ function errorFrameStream(iterable, transform, serializeError, eager: boolean) {
678
+ const transformed = transformIterable(iterable, transform, serializeError, eager);
679
+ const readable = Readable.from(transformed);
680
+ const startup: StreamStartup = transformed[streamStartup];
681
+ startup.cancel = () => readable.destroy();
682
+ readable[streamStartup] = startup;
683
+ return readable;
684
+ }
685
+
686
+ export function discardSerializedStream(stream) {
687
+ stream?.[streamStartup]?.cancel?.();
688
+ stream?.destroy?.();
689
+ }
690
+
691
+ export function waitForStreamStartup(stream) {
692
+ const startup: StreamStartup | undefined = stream?.[streamStartup];
693
+ if (!startup) return;
694
+ startup.start();
695
+ return startup.result.then((result) => {
696
+ if (result.failed) {
697
+ startup.abort();
698
+ discardSerializedStream(stream);
699
+ throw result.error;
700
+ }
701
+ });
702
+ }
703
+
704
+ function transformIterable(iterable, transform, serializeError, eager) {
705
+ let iterator;
706
+ let terminal = false;
707
+ let first = true;
708
+ let started = false;
709
+ let firstStep;
710
+ let startupSettled = false;
711
+ const startupResult = Promise.withResolvers<{ failed?: true; error?: unknown }>();
712
+ const errorDecision = Promise.withResolvers<boolean>();
713
+ let startupTimer;
714
+
715
+ const commit = () => {
716
+ if (startupTimer) clearImmediate(startupTimer);
717
+ if (!startupSettled) {
718
+ startupSettled = true;
719
+ startupResult.resolve({});
720
+ }
721
+ errorDecision.resolve(true);
722
+ };
723
+ const abort = () => {
724
+ if (startupTimer) clearImmediate(startupTimer);
725
+ errorDecision.resolve(false);
726
+ };
727
+ const handleError = async (error) => {
728
+ terminal = true;
729
+ try {
730
+ const returned = iterator.return?.();
731
+ returned?.catch?.(() => {});
732
+ } catch {}
733
+ if (!startupSettled) startupResult.resolve({ failed: true, error });
734
+ if (!startupSettled && !(await errorDecision.promise)) return { done: true };
735
+ logger.warn?.('Error serializing in stream', harperErrorForLog(error));
736
+ return { value: serializeError(error), done: false, [serializedStreamError]: true };
737
+ };
738
+ const transformStep = (step) => {
739
+ if (step?.[serializedStreamError]) return step;
740
+ if (terminal) return { done: true };
741
+ if (step.done) return step;
742
+ try {
743
+ return { value: transform(step.value), done: false };
744
+ } catch (error) {
745
+ return handleError(error);
746
+ }
747
+ };
748
+ const getRawNext = () => {
749
+ if (terminal) return { done: true };
750
+ let step;
751
+ try {
752
+ step = iterator.next();
753
+ } catch (error) {
754
+ return handleError(error);
755
+ }
756
+ if (step.then) return step.then(undefined, handleError);
757
+ return step;
758
+ };
759
+ const getNext = () => {
760
+ if (terminal) return { done: true };
761
+ let step;
762
+ try {
763
+ step = iterator.next();
764
+ } catch (error) {
765
+ return handleError(error);
766
+ }
767
+ if (step.then) return step.then(transformStep, handleError);
768
+ return transformStep(step);
769
+ };
770
+ const start = () => {
771
+ if (started) return;
772
+ started = true;
773
+ iterator = iterable[Symbol.asyncIterator] ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
774
+ firstStep = getRawNext();
775
+ Promise.resolve(firstStep).then(
776
+ () => {
777
+ if (!terminal) commit();
778
+ },
779
+ () => {}
780
+ );
781
+ // After this turn, the HTTP status can no longer wait for a first item without delaying long-lived streams.
782
+ startupTimer = setImmediate(commit);
783
+ };
784
+ if (eager) start();
785
+
619
786
  return {
787
+ [streamStartup]: {
788
+ result: startupResult.promise,
789
+ abort,
790
+ start,
791
+ },
620
792
  [Symbol.asyncIterator]() {
621
- const iterator = iterable[Symbol.asyncIterator] ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
622
793
  return {
623
794
  next() {
624
- const step = iterator.next();
625
- if (step.then) {
626
- // don't transform the terminal sentinel step, whose value is undefined
627
- return step.then((result) => (result.done ? result : { value: transform(result.value), done: false }));
795
+ if (terminal) return { done: true };
796
+ if (first) {
797
+ first = false;
798
+ start();
799
+ const step = firstStep;
800
+ firstStep = undefined;
801
+ if (step.then) return step.then(transformStep);
802
+ return transformStep(step);
628
803
  }
629
- return step.done ? step : { value: transform(step.value), done: false };
804
+ return getNext();
630
805
  },
631
806
  return(value) {
632
- return iterator.return(value);
807
+ terminal = true;
808
+ started = true;
809
+ if (!iterator)
810
+ iterator = iterable[Symbol.asyncIterator]
811
+ ? iterable[Symbol.asyncIterator]()
812
+ : iterable[Symbol.iterator]?.();
813
+ return iterator?.return?.(value) ?? { value, done: true };
633
814
  },
634
815
  throw(error) {
635
- return iterator.throw(error);
816
+ return iterator?.throw?.(error) ?? Promise.reject(error);
636
817
  },
637
818
  };
638
819
  },
@@ -1,25 +1,36 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+
3
+ import type { ComponentStatus } from '../../components/status/ComponentStatus.ts';
4
+
1
5
  // Deploy pre-flight validation loads throwaway candidate component code purely to surface load-time
2
6
  // errors — its top-level `server.registerOperation` / `server.setMcpQuotaHandler` calls mutate
3
7
  // process-wide state (the operation map, its cross-thread announcement, the quota handler) that is
4
8
  // NOT owned by a Scope, so a failed/rolled-back deploy would otherwise leak the candidate's
5
- // registrations onto the live worker. Those registration methods no-op while this guard is active.
9
+ // registrations onto the live worker. Those registration methods no-op while this guard is active,
10
+ // and the candidate's component-status writes are diverted into the throwaway sink below.
6
11
  //
7
- // Depth-counted so overlapping validations both keep the guard raised until the last one finishes.
8
- // Caveat: while a validation is in flight, a legitimate registration from an interleaving real load
9
- // is also skipped (it re-registers on its next load); that window is narrow, and the alternative —
10
- // leaking a candidate's registration live — is worse.
11
- let validationDepth = 0;
12
+ // Context-scoped rather than a process-wide depth counter, because the live component KEEPS SERVING on
13
+ // this worker throughout the window and writes to both of those same places: it registers on its own
14
+ // reload, and `statusForComponent()` is a public API its runtime code may call at any time. A counter
15
+ // cannot tell the two writers apart, so it suppressed the live component's registration and reverted its
16
+ // status report. An async context can: only work descending from the validation load itself is diverted.
17
+ interface DeployValidationContext {
18
+ // Where the candidate's own status writes land instead of the live registry. Discarded with the context.
19
+ statusSink: Map<string, ComponentStatus>;
20
+ }
21
+
22
+ const deployValidation = new AsyncLocalStorage<DeployValidationContext>();
12
23
 
13
24
  export function isDeployValidating(): boolean {
14
- return validationDepth > 0;
25
+ return deployValidation.getStore() !== undefined;
26
+ }
27
+
28
+ /** The throwaway map a candidate's status writes belong in, or `undefined` outside a validation load. */
29
+ export function deployValidationStatusSink(): Map<string, ComponentStatus> | undefined {
30
+ return deployValidation.getStore()?.statusSink;
15
31
  }
16
32
 
17
33
  /** Run `fn` (the throwaway validation load) with the guard raised, lowering it even if `fn` throws. */
18
34
  export async function runWithDeployValidationGuard<T>(fn: () => Promise<T>): Promise<T> {
19
- validationDepth++;
20
- try {
21
- return await fn();
22
- } finally {
23
- validationDepth--;
24
- }
35
+ return deployValidation.run({ statusSink: new Map() }, fn);
25
36
  }
@@ -1,11 +1,42 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
2
 
3
- const operationAuthorizationState = new AsyncLocalStorage<boolean>();
3
+ interface OperationAuthorizationState {
4
+ bypassAuth: boolean;
5
+ apiOperation?: string;
6
+ }
7
+
8
+ const operationAuthorizationState = new AsyncLocalStorage<OperationAuthorizationState>();
9
+
10
+ // Shared, for the common case of no carrier to preserve.
11
+ const BYPASSED: OperationAuthorizationState = Object.freeze({ bypassAuth: true });
12
+ const ENFORCED: OperationAuthorizationState = Object.freeze({ bypassAuth: false });
4
13
 
5
14
  export function runWithOperationAuthorizationBypass<T>(bypassAuth: boolean, callback: () => T): T {
6
- return operationAuthorizationState.run(bypassAuth === true, callback);
15
+ // An existing carrier survives: the enforced branch is not a bypass, and a job handler dispatching
16
+ // a nested authorized operation must not lose its own operation identity.
17
+ const apiOperation = operationAuthorizationState.getStore()?.apiOperation;
18
+ if (apiOperation === undefined) {
19
+ return operationAuthorizationState.run(bypassAuth === true ? BYPASSED : ENFORCED, callback);
20
+ }
21
+ return operationAuthorizationState.run(Object.freeze({ bypassAuth: bypassAuth === true, apiOperation }), callback);
22
+ }
23
+
24
+ /**
25
+ * `apiOperation` MUST come from the same value that selected the code now running, so it cannot name
26
+ * an operation other than the one executing. That is the entire basis for trusting it: a request
27
+ * property would be forgeable, and on the direct-SQL path this check is the only gate.
28
+ */
29
+ export function runWithDispatchedOperation<T>(apiOperation: string, callback: () => T): T {
30
+ return operationAuthorizationState.run(
31
+ Object.freeze({ bypassAuth: operationAuthorizationState.getStore()?.bypassAuth === true, apiOperation }),
32
+ callback
33
+ );
34
+ }
35
+
36
+ export function getOperationAuthorizationState(): OperationAuthorizationState | undefined {
37
+ return operationAuthorizationState.getStore();
7
38
  }
8
39
 
9
40
  export function isOperationAuthorizationBypassed(): boolean {
10
- return operationAuthorizationState.getStore() === true;
41
+ return operationAuthorizationState.getStore()?.bypassAuth === true;
11
42
  }
@@ -11,7 +11,7 @@
11
11
  * so a request is sent to exactly ONE registering worker (never broadcast-first-wins).
12
12
  *
13
13
  * - Worker: `registerOperation()` announces the name (OPERATION_REGISTERED) to all threads;
14
- * only the main thread records it, as name -> Set<threadId>.
14
+ * only the main thread records it, as name -> Set<threadId>, plus `grantable`.
15
15
  * - Main: on an OPERATION_FUNCTION_MAP miss, `getRemoteOperationFunction()` supplies a forwarding
16
16
  * function that sends the request body (OPERATION_EXECUTE_REQUEST) to one live registering
17
17
  * worker and awaits the correlated OPERATION_EXECUTE_RESPONSE.
@@ -26,7 +26,11 @@ import * as env from '../../utility/environment/environmentManager.ts';
26
26
  import harperLogger from '../../utility/logging/harper_logger.ts';
27
27
  import { ServerError } from '../../utility/errors/hdbError.ts';
28
28
  import { sendItcEvent } from '../threads/itc.js';
29
- import { onMessageByType, onThreadExit } from '../threads/manageThreads.js';
29
+ import { hasThreadExited, onMessageByType, onThreadExit } from '../threads/manageThreads.js';
30
+ import {
31
+ registerWorkerGrantableOperation,
32
+ unregisterWorkerGrantableOperation,
33
+ } from '../../utility/operationPermissions.ts';
30
34
  import { runWithOperationAuthorizationBypass } from './operationAuthorizationState.ts';
31
35
 
32
36
  const operationLog = harperLogger.loggerWithTag('operation');
@@ -59,6 +63,9 @@ export function setLocalOperationDispatch(dispatch: typeof localDispatch) {
59
63
 
60
64
  /** name -> threadIds of workers that registered it (main thread only) */
61
65
  const registeredByWorker = new Map<string, Set<number>>();
66
+ // Per originator, not per name: a rolling deploy whose new generation drops `requiresSuperUser`
67
+ // must keep routing the name while retracting grantability, which a name-level flag cannot express.
68
+ const grantableByWorker = new Map<string, Set<number>>();
62
69
  const pendingExecutions = new Map<
63
70
  number,
64
71
  { targetThreadId: number; resolve: (result: any) => void; reject: (error: Error) => void }
@@ -71,27 +78,82 @@ let mainListenersAttached = false;
71
78
  * a lost announcement just means the op stays unreachable (the pre-#1736 status quo), and the
72
79
  * broadcast has its own ack timeout.
73
80
  */
74
- export function announceRegisteredOperation(name: string) {
81
+ export function announceRegisteredOperation(name: string, grantable = false) {
75
82
  if (isMainThread) return;
76
83
  sendItcEvent({
77
84
  type: terms.ITC_EVENT_TYPES.OPERATION_REGISTERED,
78
- message: { name },
85
+ message: { name, grantable },
79
86
  }).catch((error) => operationLog.error(`Failed to announce registered operation '${name}'`, error));
80
87
  }
81
88
 
82
89
  /**
83
90
  * ITC handler (all threads receive the broadcast; only main records it).
84
91
  */
85
- export function operationRegisteredHandler(event: { message: { name: string; originator: number } }) {
92
+ export function operationRegisteredHandler(event: {
93
+ message?: { name?: string; grantable?: boolean; originator?: number };
94
+ }) {
86
95
  if (!isMainThread) return;
87
- const { name, originator } = event.message;
96
+ const { name, grantable, originator } = event?.message ?? {};
88
97
  if (typeof name !== 'string' || typeof originator !== 'number') return;
98
+ // An announcement can lose the race with its own thread's exit, and exit notification fires once
99
+ // per thread, so without this the entry would never be cleaned up. Reads manageThreads' tombstone
100
+ // rather than keeping a second one: job threads are one-shot workers, so a duplicate here would
101
+ // grow per completed job, not per worker restart.
102
+ if (hasThreadExited(originator)) {
103
+ operationLog.debug(`Ignoring operation '${name}' announced by exited worker thread ${originator}`);
104
+ return;
105
+ }
89
106
  let workerIds = registeredByWorker.get(name);
90
107
  if (!workerIds) registeredByWorker.set(name, (workerIds = new Set()));
91
108
  workerIds.add(originator);
109
+ // Mirroring only widens what an allowlist may name; enforcement stays on the worker's
110
+ // chooseOperation. A re-announcement that drops the permission retracts this thread's claim.
111
+ setWorkerGrantable(name, originator, grantable === true);
92
112
  operationLog.debug(`Registered operation '${name}' announced by worker thread ${originator}`);
93
113
  }
94
114
 
115
+ /**
116
+ * A worker that dies mid-execution can never respond, so fail its in-flight forwards rather than
117
+ * waiting out the timeout, and forget its registrations (a replacement re-registers on load).
118
+ */
119
+ function handleThreadExit(deadThreadId: number) {
120
+ for (const [name, workerIds] of registeredByWorker) {
121
+ if (!workerIds.delete(deadThreadId)) continue;
122
+ // A surviving worker that never declared a permission must not keep the name admissible.
123
+ if (workerIds.size === 0) dropRegistration(name);
124
+ else setWorkerGrantable(name, deadThreadId, false);
125
+ }
126
+ for (const [requestId, pending] of pendingExecutions) {
127
+ if (pending.targetThreadId === deadThreadId) {
128
+ pendingExecutions.delete(requestId);
129
+ pending.reject(new ServerError('The worker thread executing this operation exited', 503));
130
+ }
131
+ }
132
+ }
133
+
134
+ function setWorkerGrantable(name: string, threadId: number, grantable: boolean) {
135
+ let grantableIds = grantableByWorker.get(name);
136
+ if (grantable) {
137
+ if (!grantableIds) grantableByWorker.set(name, (grantableIds = new Set()));
138
+ grantableIds.add(threadId);
139
+ registerWorkerGrantableOperation(name);
140
+ } else if (grantableIds?.delete(threadId) && grantableIds.size === 0) {
141
+ grantableByWorker.delete(name);
142
+ unregisterWorkerGrantableOperation(name);
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Forget an operation no live worker offers any more. Both prune paths — thread exit, and a failed
148
+ * send discovering a dead port — route through here so a name can never keep a route without an
149
+ * owner. Grantability is dropped per owner instead, in `setWorkerGrantable`.
150
+ */
151
+ function dropRegistration(name: string) {
152
+ registeredByWorker.delete(name);
153
+ grantableByWorker.delete(name);
154
+ unregisterWorkerGrantableOperation(name);
155
+ }
156
+
95
157
  let rotation = 0;
96
158
  /**
97
159
  * Main-thread dispatch fallback: if a worker registered `name`, return a forwarding operation
@@ -122,23 +184,15 @@ function attachMainListeners() {
122
184
  if (error) pending.reject(new ServerError(error.message, error.statusCode || 500));
123
185
  else pending.resolve(result);
124
186
  });
125
- // A worker that dies mid-execution can never respond; fail its in-flight forwards rather
126
- // than waiting out the timeout, and forget its registrations (a replacement worker
127
- // re-registers on component load).
128
- onThreadExit((deadThreadId: number) => {
129
- for (const [name, workerIds] of registeredByWorker) {
130
- workerIds.delete(deadThreadId);
131
- if (workerIds.size === 0) registeredByWorker.delete(name);
132
- }
133
- for (const [requestId, pending] of pendingExecutions) {
134
- if (pending.targetThreadId === deadThreadId) {
135
- pendingExecutions.delete(requestId);
136
- pending.reject(new ServerError('The worker thread executing this operation exited', 503));
137
- }
138
- }
139
- });
187
+ onThreadExit(handleThreadExit);
140
188
  }
141
189
 
190
+ // Armed at load rather than on first use: serverUtilities imports this module during its own load,
191
+ // before any worker exists. Thread-exit notification fires once per thread and is dropped outright
192
+ // if no listener is attached yet, so a worker dying before its first announcement is processed
193
+ // would otherwise leave a registration nothing could ever clean up.
194
+ if (isMainThread) attachMainListeners();
195
+
142
196
  async function executeRemoteOperation(name: string, body: any, bypassAuth: boolean): Promise<any> {
143
197
  attachMainListeners();
144
198
  const workerIds = registeredByWorker.get(name);
@@ -168,7 +222,10 @@ async function executeRemoteOperation(name: string, body: any, bypassAuth: boole
168
222
  );
169
223
  }
170
224
  if (!sent) {
225
+ // The port is gone, so this thread's claims go with it — grantability included, which
226
+ // handleThreadExit would otherwise not retract while other workers still route the name.
171
227
  workerIds.delete(targetThreadId);
228
+ setWorkerGrantable(name, targetThreadId, false);
172
229
  continue;
173
230
  }
174
231
  return new Promise((promiseResolve, promiseReject) => {
@@ -190,7 +247,7 @@ async function executeRemoteOperation(name: string, body: any, bypassAuth: boole
190
247
  });
191
248
  });
192
249
  }
193
- if (registeredByWorker.get(name)?.size === 0) registeredByWorker.delete(name);
250
+ if (registeredByWorker.get(name)?.size === 0) dropRegistration(name);
194
251
  throw new ServerError(
195
252
  `Operation '${name}' is registered by a component but no worker thread is available to run it`,
196
253
  503
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `evaluateSQL` honors a supplied `parsed_sql_object` verbatim and skips parsing, so one carrying
3
+ * `permissions_checked: true` executes an AST that no authorization check ever saw. Neither position
4
+ * is ever legitimately client-supplied: dispatch parses the statement itself, and the job worker
5
+ * re-parses from the `sql` string dispatch authorized.
6
+ *
7
+ * Both positions, because the two entry points differ: `chooseOperation` overwrites the top-level
8
+ * object with its own parse, but only inside its SQL branch, so a non-SQL job (`export_local` with a
9
+ * `search_by_value` search) can still carry a client-supplied one through to the persisted row.
10
+ */
11
+ export function stripSuppliedParsedSqlObject(request: any): void {
12
+ if (!request) return;
13
+ delete request.parsed_sql_object;
14
+ delete request.search_operation?.parsed_sql_object;
15
+ }
@@ -41,6 +41,9 @@ const NO_AUTH_OPERATIONS = [
41
41
  terms.OPERATIONS_ENUM.CREATE_AUTHENTICATION_TOKENS,
42
42
  terms.OPERATIONS_ENUM.LOGIN,
43
43
  terms.OPERATIONS_ENUM.LOGOUT,
44
+ // The OIDC exchange *is* the authentication (#2171): the caller proves identity with a token
45
+ // from a trusted issuer, not with Harper credentials it does not have.
46
+ terms.OPERATIONS_ENUM.EXCHANGE_OIDC_TOKEN,
44
47
  ];
45
48
 
46
49
  const UNSAFE_REQUEST_BODY_PROPERTIES = ['__proto__', 'constructor', 'prototype'];
@@ -111,10 +114,10 @@ function authHandler(req, resp, done) {
111
114
  const isAuthOperation = !NO_AUTH_OPERATIONS.includes(req.body.operation);
112
115
  if (
113
116
  isAuthOperation ||
114
- // If create token is called without username/password in the body it needs to be authorized
117
+ // Create token needs to be authorized when called without username/password in the body, or
118
+ // with an inline role object (scoped-token minting is gated on the authenticated requester)
115
119
  (req.body.operation === terms.OPERATIONS_ENUM.CREATE_AUTHENTICATION_TOKENS &&
116
- !req.body.username &&
117
- !req.body.password)
120
+ ((!req.body.username && !req.body.password) || (req.body.role && typeof req.body.role === 'object')))
118
121
  ) {
119
122
  pAuthorize(req, resp)
120
123
  .then(async (userData) => {