harper 5.1.20 → 5.2.0-alpha.5

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 (395) hide show
  1. package/agent/operations.ts +13 -16
  2. package/components/Application.ts +188 -7
  3. package/components/ApplicationScope.ts +3 -0
  4. package/components/Scope.ts +12 -0
  5. package/components/anthropic/index.ts +9 -2
  6. package/components/bedrock/index.ts +25 -2
  7. package/components/componentLoader.ts +56 -7
  8. package/components/componentSecrets.ts +451 -0
  9. package/components/deploymentRecorder.ts +7 -1
  10. package/components/mcp/adapters/fastify.ts +3 -0
  11. package/components/mcp/adapters/harperHttp.ts +3 -0
  12. package/components/mcp/audit.ts +21 -6
  13. package/components/mcp/customResourceRegistry.ts +17 -38
  14. package/components/mcp/listChanged.ts +37 -20
  15. package/components/mcp/quota.ts +145 -0
  16. package/components/mcp/rateLimit.ts +152 -14
  17. package/components/mcp/resources.ts +2 -4
  18. package/components/mcp/toolRegistry.ts +73 -4
  19. package/components/mcp/tools/application.ts +77 -8
  20. package/components/mcp/tools/operations.ts +106 -36
  21. package/components/mcp/tools/schemas/operationDescriptions.ts +4 -4
  22. package/components/mcp/tools/schemas/operations.ts +5 -0
  23. package/components/mcp/transport.ts +55 -4
  24. package/components/ollama/index.ts +6 -2
  25. package/components/openai/index.ts +9 -2
  26. package/components/operations.js +204 -10
  27. package/components/operationsValidation.js +173 -0
  28. package/components/secretOperations.ts +498 -0
  29. package/config/configUtils.ts +25 -1
  30. package/config-app.schema.json +81 -0
  31. package/config-root.schema.json +8 -1
  32. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -3
  33. package/dataLayer/readAuditLog.ts +14 -0
  34. package/dataLayer/schemaDescribe.ts +1 -0
  35. package/dist/agent/operations.d.ts +7 -4
  36. package/dist/agent/operations.js +13 -15
  37. package/dist/agent/operations.js.map +1 -1
  38. package/dist/components/Application.d.ts +25 -2
  39. package/dist/components/Application.js +166 -7
  40. package/dist/components/Application.js.map +1 -1
  41. package/dist/components/ApplicationScope.d.ts +2 -0
  42. package/dist/components/ApplicationScope.js +3 -0
  43. package/dist/components/ApplicationScope.js.map +1 -1
  44. package/dist/components/Scope.d.ts +8 -0
  45. package/dist/components/Scope.js +11 -0
  46. package/dist/components/Scope.js.map +1 -1
  47. package/dist/components/anthropic/index.d.ts +4 -1
  48. package/dist/components/anthropic/index.js +4 -2
  49. package/dist/components/anthropic/index.js.map +1 -1
  50. package/dist/components/bedrock/index.d.ts +4 -1
  51. package/dist/components/bedrock/index.js +22 -2
  52. package/dist/components/bedrock/index.js.map +1 -1
  53. package/dist/components/componentLoader.d.ts +2 -0
  54. package/dist/components/componentLoader.js +52 -10
  55. package/dist/components/componentLoader.js.map +1 -1
  56. package/dist/components/componentSecrets.d.ts +63 -0
  57. package/dist/components/componentSecrets.js +405 -0
  58. package/dist/components/componentSecrets.js.map +1 -0
  59. package/dist/components/deploymentRecorder.d.ts +3 -0
  60. package/dist/components/deploymentRecorder.js +4 -3
  61. package/dist/components/deploymentRecorder.js.map +1 -1
  62. package/dist/components/mcp/adapters/fastify.d.ts +2 -0
  63. package/dist/components/mcp/adapters/fastify.js +1 -0
  64. package/dist/components/mcp/adapters/fastify.js.map +1 -1
  65. package/dist/components/mcp/adapters/harperHttp.d.ts +2 -0
  66. package/dist/components/mcp/adapters/harperHttp.js +1 -0
  67. package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
  68. package/dist/components/mcp/audit.d.ts +2 -2
  69. package/dist/components/mcp/audit.js +20 -5
  70. package/dist/components/mcp/audit.js.map +1 -1
  71. package/dist/components/mcp/customResourceRegistry.d.ts +5 -12
  72. package/dist/components/mcp/customResourceRegistry.js +15 -30
  73. package/dist/components/mcp/customResourceRegistry.js.map +1 -1
  74. package/dist/components/mcp/listChanged.d.ts +7 -2
  75. package/dist/components/mcp/listChanged.js +28 -0
  76. package/dist/components/mcp/listChanged.js.map +1 -1
  77. package/dist/components/mcp/quota.d.ts +31 -0
  78. package/dist/components/mcp/quota.js +155 -0
  79. package/dist/components/mcp/quota.js.map +1 -0
  80. package/dist/components/mcp/rateLimit.d.ts +19 -3
  81. package/dist/components/mcp/rateLimit.js +129 -13
  82. package/dist/components/mcp/rateLimit.js.map +1 -1
  83. package/dist/components/mcp/resources.js.map +1 -1
  84. package/dist/components/mcp/toolRegistry.d.ts +39 -1
  85. package/dist/components/mcp/toolRegistry.js +60 -5
  86. package/dist/components/mcp/toolRegistry.js.map +1 -1
  87. package/dist/components/mcp/tools/application.d.ts +8 -1
  88. package/dist/components/mcp/tools/application.js +65 -5
  89. package/dist/components/mcp/tools/application.js.map +1 -1
  90. package/dist/components/mcp/tools/operations.d.ts +15 -3
  91. package/dist/components/mcp/tools/operations.js +99 -38
  92. package/dist/components/mcp/tools/operations.js.map +1 -1
  93. package/dist/components/mcp/tools/schemas/operationDescriptions.js +4 -4
  94. package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
  95. package/dist/components/mcp/tools/schemas/operations.js +4 -0
  96. package/dist/components/mcp/tools/schemas/operations.js.map +1 -1
  97. package/dist/components/mcp/transport.d.ts +6 -0
  98. package/dist/components/mcp/transport.js +47 -3
  99. package/dist/components/mcp/transport.js.map +1 -1
  100. package/dist/components/ollama/index.d.ts +4 -1
  101. package/dist/components/ollama/index.js +4 -2
  102. package/dist/components/ollama/index.js.map +1 -1
  103. package/dist/components/openai/index.d.ts +4 -1
  104. package/dist/components/openai/index.js +4 -2
  105. package/dist/components/openai/index.js.map +1 -1
  106. package/dist/components/operations.d.ts +39 -0
  107. package/dist/components/operations.js +194 -2
  108. package/dist/components/operations.js.map +1 -1
  109. package/dist/components/operationsValidation.d.ts +38 -0
  110. package/dist/components/operationsValidation.js +155 -0
  111. package/dist/components/operationsValidation.js.map +1 -1
  112. package/dist/components/secretOperations.d.ts +113 -0
  113. package/dist/components/secretOperations.js +475 -0
  114. package/dist/components/secretOperations.js.map +1 -0
  115. package/dist/config/configUtils.d.ts +4 -1
  116. package/dist/config/configUtils.js +18 -1
  117. package/dist/config/configUtils.js.map +1 -1
  118. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -3
  119. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js.map +1 -1
  120. package/dist/dataLayer/readAuditLog.js +11 -0
  121. package/dist/dataLayer/readAuditLog.js.map +1 -1
  122. package/dist/dataLayer/schemaDescribe.js +2 -0
  123. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  124. package/dist/globals.d.ts +1 -1
  125. package/dist/globals.js +1 -0
  126. package/dist/globals.js.map +1 -1
  127. package/dist/index.d.ts +3 -0
  128. package/dist/index.js +1 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/json/systemSchema.json +38 -0
  131. package/dist/resources/DatabaseTransaction.d.ts +31 -3
  132. package/dist/resources/DatabaseTransaction.js +190 -29
  133. package/dist/resources/DatabaseTransaction.js.map +1 -1
  134. package/dist/resources/LMDBTransaction.d.ts +1 -1
  135. package/dist/resources/LMDBTransaction.js +43 -5
  136. package/dist/resources/LMDBTransaction.js.map +1 -1
  137. package/dist/resources/PrimaryRocksDatabase.d.ts +51 -0
  138. package/dist/resources/PrimaryRocksDatabase.js +194 -0
  139. package/dist/resources/PrimaryRocksDatabase.js.map +1 -0
  140. package/dist/resources/RecordEncoder.d.ts +1 -0
  141. package/dist/resources/RecordEncoder.js +81 -75
  142. package/dist/resources/RecordEncoder.js.map +1 -1
  143. package/dist/resources/RequestTarget.d.ts +19 -0
  144. package/dist/resources/RequestTarget.js.map +1 -1
  145. package/dist/resources/Resource.d.ts +0 -1
  146. package/dist/resources/Resource.js +103 -16
  147. package/dist/resources/Resource.js.map +1 -1
  148. package/dist/resources/ResourceInterface.d.ts +6 -2
  149. package/dist/resources/ResourceInterface.js.map +1 -1
  150. package/dist/resources/Resources.js.map +1 -1
  151. package/dist/resources/Table.d.ts +6 -4
  152. package/dist/resources/Table.js +247 -24
  153. package/dist/resources/Table.js.map +1 -1
  154. package/dist/resources/analytics/read.js +25 -28
  155. package/dist/resources/analytics/read.js.map +1 -1
  156. package/dist/resources/blob.js +165 -22
  157. package/dist/resources/blob.js.map +1 -1
  158. package/dist/resources/crdt.d.ts +2 -0
  159. package/dist/resources/crdt.js +45 -36
  160. package/dist/resources/crdt.js.map +1 -1
  161. package/dist/resources/databases.d.ts +1 -0
  162. package/dist/resources/databases.js +134 -7
  163. package/dist/resources/databases.js.map +1 -1
  164. package/dist/resources/graphql.js +8 -0
  165. package/dist/resources/graphql.js.map +1 -1
  166. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +35 -5
  167. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +239 -14
  168. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  169. package/dist/resources/jsResource.js +6 -0
  170. package/dist/resources/jsResource.js.map +1 -1
  171. package/dist/resources/loadEnv.js +30 -3
  172. package/dist/resources/loadEnv.js.map +1 -1
  173. package/dist/resources/login.js +2 -2
  174. package/dist/resources/login.js.map +1 -1
  175. package/dist/resources/models/Models.js +14 -3
  176. package/dist/resources/models/Models.js.map +1 -1
  177. package/dist/resources/models/embedHook.js +10 -2
  178. package/dist/resources/models/embedHook.js.map +1 -1
  179. package/dist/resources/models/openaiStream.d.ts +56 -0
  180. package/dist/resources/models/openaiStream.js +94 -0
  181. package/dist/resources/models/openaiStream.js.map +1 -0
  182. package/dist/resources/replayLogs.js +4 -3
  183. package/dist/resources/replayLogs.js.map +1 -1
  184. package/dist/resources/search.d.ts +1 -1
  185. package/dist/resources/search.js +104 -11
  186. package/dist/resources/search.js.map +1 -1
  187. package/dist/resources/secretDecryptor.d.ts +54 -0
  188. package/dist/resources/secretDecryptor.js +131 -0
  189. package/dist/resources/secretDecryptor.js.map +1 -0
  190. package/dist/resources/tracked.js +15 -5
  191. package/dist/resources/tracked.js.map +1 -1
  192. package/dist/security/auth.js +71 -8
  193. package/dist/security/auth.js.map +1 -1
  194. package/dist/security/jsLoader.js +11 -0
  195. package/dist/security/jsLoader.js.map +1 -1
  196. package/dist/security/tokenAuthentication.d.ts +9 -1
  197. package/dist/security/tokenAuthentication.js +31 -1
  198. package/dist/security/tokenAuthentication.js.map +1 -1
  199. package/dist/server/DurableSubscriptionsSession.d.ts +1 -1
  200. package/dist/server/DurableSubscriptionsSession.js +8 -4
  201. package/dist/server/DurableSubscriptionsSession.js.map +1 -1
  202. package/dist/server/REST.js +28 -9
  203. package/dist/server/REST.js.map +1 -1
  204. package/dist/server/fastifyRoutes.js +11 -1
  205. package/dist/server/fastifyRoutes.js.map +1 -1
  206. package/dist/server/graphqlQuerying.js +4 -3
  207. package/dist/server/graphqlQuerying.js.map +1 -1
  208. package/dist/server/http.d.ts +40 -2
  209. package/dist/server/http.js +560 -77
  210. package/dist/server/http.js.map +1 -1
  211. package/dist/server/itc/serverHandlers.js +64 -0
  212. package/dist/server/itc/serverHandlers.js.map +1 -1
  213. package/dist/server/liveSubscriptionAuth.d.ts +12 -0
  214. package/dist/server/liveSubscriptionAuth.js +140 -0
  215. package/dist/server/liveSubscriptionAuth.js.map +1 -0
  216. package/dist/server/loadRootComponents.js +2 -1
  217. package/dist/server/loadRootComponents.js.map +1 -1
  218. package/dist/server/middlewareChain.d.ts +44 -1
  219. package/dist/server/middlewareChain.js +86 -10
  220. package/dist/server/middlewareChain.js.map +1 -1
  221. package/dist/server/mqtt.js +2 -1
  222. package/dist/server/mqtt.js.map +1 -1
  223. package/dist/server/operationsServer.js +1 -1
  224. package/dist/server/operationsServer.js.map +1 -1
  225. package/dist/server/serverHelpers/Headers.d.ts +9 -0
  226. package/dist/server/serverHelpers/Headers.js +22 -0
  227. package/dist/server/serverHelpers/Headers.js.map +1 -1
  228. package/dist/server/serverHelpers/JSONStream.js +3 -3
  229. package/dist/server/serverHelpers/JSONStream.js.map +1 -1
  230. package/dist/server/serverHelpers/Request.d.ts +52 -1
  231. package/dist/server/serverHelpers/Request.js +122 -1
  232. package/dist/server/serverHelpers/Request.js.map +1 -1
  233. package/dist/server/serverHelpers/contentTypes.js +3 -8
  234. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  235. package/dist/server/serverHelpers/progressEmitter.d.ts +19 -0
  236. package/dist/server/serverHelpers/progressEmitter.js +52 -4
  237. package/dist/server/serverHelpers/progressEmitter.js.map +1 -1
  238. package/dist/server/serverHelpers/registeredOperations.d.ts +40 -0
  239. package/dist/server/serverHelpers/registeredOperations.js +286 -0
  240. package/dist/server/serverHelpers/registeredOperations.js.map +1 -0
  241. package/dist/server/serverHelpers/serverHandlers.js +11 -5
  242. package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
  243. package/dist/server/serverHelpers/serverUtilities.d.ts +1 -0
  244. package/dist/server/serverHelpers/serverUtilities.js +67 -5
  245. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  246. package/dist/server/serverHelpers/uwsServer.d.ts +80 -0
  247. package/dist/server/serverHelpers/uwsServer.js +433 -0
  248. package/dist/server/serverHelpers/uwsServer.js.map +1 -0
  249. package/dist/server/static.d.ts +0 -15
  250. package/dist/server/static.js +161 -2
  251. package/dist/server/static.js.map +1 -1
  252. package/dist/server/status/index.d.ts +4 -1
  253. package/dist/server/status/index.js +64 -4
  254. package/dist/server/status/index.js.map +1 -1
  255. package/dist/server/threads/manageThreads.d.ts +10 -0
  256. package/dist/server/threads/manageThreads.js +107 -4
  257. package/dist/server/threads/manageThreads.js.map +1 -1
  258. package/dist/server/threads/socketRouter.js +5 -1
  259. package/dist/server/threads/socketRouter.js.map +1 -1
  260. package/dist/server/threads/threadServer.js +92 -14
  261. package/dist/server/threads/threadServer.js.map +1 -1
  262. package/dist/upgrade/directives/5-2-0.d.ts +7 -0
  263. package/dist/upgrade/directives/5-2-0.js +108 -0
  264. package/dist/upgrade/directives/5-2-0.js.map +1 -0
  265. package/dist/upgrade/directives/directivesController.js +2 -1
  266. package/dist/upgrade/directives/directivesController.js.map +1 -1
  267. package/dist/utility/common_utils.js +5 -0
  268. package/dist/utility/common_utils.js.map +1 -1
  269. package/dist/utility/envFile.d.ts +41 -0
  270. package/dist/utility/envFile.js +221 -0
  271. package/dist/utility/envFile.js.map +1 -0
  272. package/dist/utility/globalSchema.d.ts +9 -0
  273. package/dist/utility/hdbTerms.d.ts +25 -0
  274. package/dist/utility/hdbTerms.js +31 -0
  275. package/dist/utility/hdbTerms.js.map +1 -1
  276. package/dist/utility/logging/harper_logger.d.ts +21 -0
  277. package/dist/utility/logging/harper_logger.js +160 -8
  278. package/dist/utility/logging/harper_logger.js.map +1 -1
  279. package/dist/utility/logging/logRotator.js +29 -17
  280. package/dist/utility/logging/logRotator.js.map +1 -1
  281. package/dist/utility/logging/readLog.d.ts +1 -1
  282. package/dist/utility/logging/readLog.js +305 -2
  283. package/dist/utility/logging/readLog.js.map +1 -1
  284. package/dist/utility/operationPermissions.d.ts +18 -0
  285. package/dist/utility/operationPermissions.js +35 -1
  286. package/dist/utility/operationPermissions.js.map +1 -1
  287. package/dist/utility/operation_authorization.d.ts +17 -0
  288. package/dist/utility/operation_authorization.js +38 -0
  289. package/dist/utility/operation_authorization.js.map +1 -1
  290. package/dist/utility/secretEnvelope.d.ts +30 -0
  291. package/dist/utility/secretEnvelope.js +94 -0
  292. package/dist/utility/secretEnvelope.js.map +1 -0
  293. package/dist/utility/signalling.d.ts +7 -0
  294. package/dist/utility/signalling.js +16 -0
  295. package/dist/utility/signalling.js.map +1 -1
  296. package/dist/validation/configValidator.js +70 -24
  297. package/dist/validation/configValidator.js.map +1 -1
  298. package/index.ts +4 -0
  299. package/json/systemSchema.json +38 -0
  300. package/npm-shrinkwrap.json +15066 -9347
  301. package/package.json +13 -8
  302. package/resources/DESIGN.md +15 -12
  303. package/resources/DatabaseTransaction.ts +206 -37
  304. package/resources/LMDBTransaction.ts +43 -9
  305. package/resources/PrimaryRocksDatabase.ts +201 -0
  306. package/resources/RecordEncoder.ts +81 -69
  307. package/resources/RequestTarget.ts +21 -0
  308. package/resources/Resource.ts +109 -25
  309. package/resources/ResourceInterface.ts +6 -2
  310. package/resources/Resources.ts +1 -3
  311. package/resources/Table.ts +238 -29
  312. package/resources/analytics/read.ts +25 -30
  313. package/resources/blob.ts +159 -23
  314. package/resources/crdt.ts +37 -31
  315. package/resources/databases.ts +143 -6
  316. package/resources/graphql.ts +8 -0
  317. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +251 -17
  318. package/resources/jsResource.ts +6 -0
  319. package/resources/loadEnv.ts +34 -3
  320. package/resources/login.ts +2 -2
  321. package/resources/models/Models.ts +19 -3
  322. package/resources/models/embedHook.ts +13 -2
  323. package/resources/models/openaiStream.ts +133 -0
  324. package/resources/replayLogs.ts +4 -3
  325. package/resources/search.ts +113 -11
  326. package/resources/secretDecryptor.ts +159 -0
  327. package/resources/tracked.ts +24 -17
  328. package/security/auth.ts +70 -10
  329. package/security/jsLoader.ts +12 -0
  330. package/security/tokenAuthentication.ts +42 -1
  331. package/server/DESIGN.md +10 -0
  332. package/server/DurableSubscriptionsSession.ts +8 -4
  333. package/server/REST.ts +26 -9
  334. package/server/fastifyRoutes.ts +10 -1
  335. package/server/graphqlQuerying.ts +4 -3
  336. package/server/http.ts +563 -77
  337. package/server/itc/serverHandlers.js +70 -0
  338. package/server/liveSubscriptionAuth.ts +152 -0
  339. package/server/loadRootComponents.js +2 -1
  340. package/server/middlewareChain.ts +107 -17
  341. package/server/mqtt.ts +2 -1
  342. package/server/operationsServer.ts +2 -2
  343. package/server/serverHelpers/Headers.ts +24 -0
  344. package/server/serverHelpers/JSONStream.ts +3 -3
  345. package/server/serverHelpers/Request.ts +127 -0
  346. package/server/serverHelpers/contentTypes.ts +3 -8
  347. package/server/serverHelpers/progressEmitter.ts +55 -5
  348. package/server/serverHelpers/registeredOperations.ts +259 -0
  349. package/server/serverHelpers/serverHandlers.js +11 -5
  350. package/server/serverHelpers/serverUtilities.ts +88 -5
  351. package/server/serverHelpers/uwsServer.ts +488 -0
  352. package/server/static.ts +180 -2
  353. package/server/status/index.ts +72 -4
  354. package/server/threads/manageThreads.js +102 -4
  355. package/server/threads/socketRouter.ts +5 -1
  356. package/server/threads/threadServer.js +93 -10
  357. package/studio/web/assets/{Chat-SdD1EZca.js → Chat-Cv_2paZE.js} +2 -2
  358. package/studio/web/assets/{Chat-SdD1EZca.js.map → Chat-Cv_2paZE.js.map} +1 -1
  359. package/studio/web/assets/{FloatingChat-GMq6tHK9.js → FloatingChat-CPyPIcVR.js} +4 -4
  360. package/studio/web/assets/{FloatingChat-GMq6tHK9.js.map → FloatingChat-CPyPIcVR.js.map} +1 -1
  361. package/studio/web/assets/{applications-B5hhv7uA.js → applications-C0jT2vdZ.js} +2 -2
  362. package/studio/web/assets/{applications-B5hhv7uA.js.map → applications-C0jT2vdZ.js.map} +1 -1
  363. package/studio/web/assets/{index-VFcpNWgq.js → index-D_GKOkhn.js} +6 -6
  364. package/studio/web/assets/index-D_GKOkhn.js.map +1 -0
  365. package/studio/web/assets/{index.lazy-DgcJojIA.js → index.lazy-CAmCIA65.js} +4 -4
  366. package/studio/web/assets/{index.lazy-DgcJojIA.js.map → index.lazy-CAmCIA65.js.map} +1 -1
  367. package/studio/web/assets/{profile-BqN-8vzm.js → profile-CaF-4aZe.js} +2 -2
  368. package/studio/web/assets/{profile-BqN-8vzm.js.map → profile-CaF-4aZe.js.map} +1 -1
  369. package/studio/web/assets/{setComponentFile-CHFvFq9u.js → setComponentFile-DLW1DHCt.js} +2 -2
  370. package/studio/web/assets/{setComponentFile-CHFvFq9u.js.map → setComponentFile-DLW1DHCt.js.map} +1 -1
  371. package/studio/web/assets/{setup-CQ3vWJSr.js → setup-TGCErIhq.js} +2 -2
  372. package/studio/web/assets/{setup-CQ3vWJSr.js.map → setup-TGCErIhq.js.map} +1 -1
  373. package/studio/web/assets/{status-BsW5fjuh.js → status-DG0Maoao.js} +2 -2
  374. package/studio/web/assets/{status-BsW5fjuh.js.map → status-DG0Maoao.js.map} +1 -1
  375. package/studio/web/assets/{swagger-ui-react-DITdeB9-.js → swagger-ui-react-8T4SgQ1m.js} +2 -2
  376. package/studio/web/assets/{swagger-ui-react-DITdeB9-.js.map → swagger-ui-react-8T4SgQ1m.js.map} +1 -1
  377. package/studio/web/assets/{tsMode-Dyph-OUs.js → tsMode-DJ6Sl24Q.js} +2 -2
  378. package/studio/web/assets/{tsMode-Dyph-OUs.js.map → tsMode-DJ6Sl24Q.js.map} +1 -1
  379. package/studio/web/assets/{useEntityRestURL-D0QTUqex.js → useEntityRestURL-JO2mfWTQ.js} +2 -2
  380. package/studio/web/assets/{useEntityRestURL-D0QTUqex.js.map → useEntityRestURL-JO2mfWTQ.js.map} +1 -1
  381. package/studio/web/index.html +1 -1
  382. package/upgrade/directives/5-2-0.ts +82 -0
  383. package/upgrade/directives/directivesController.ts +2 -1
  384. package/utility/common_utils.ts +5 -0
  385. package/utility/envFile.ts +218 -0
  386. package/utility/hdbTerms.ts +31 -0
  387. package/utility/logging/harper_logger.ts +156 -8
  388. package/utility/logging/logRotator.ts +24 -14
  389. package/utility/logging/readLog.ts +323 -2
  390. package/utility/operationPermissions.ts +35 -1
  391. package/utility/operation_authorization.ts +74 -1
  392. package/utility/secretEnvelope.ts +113 -0
  393. package/utility/signalling.ts +15 -0
  394. package/validation/configValidator.ts +78 -25
  395. package/studio/web/assets/index-VFcpNWgq.js.map +0 -1
@@ -11,6 +11,14 @@ const hdbTerms = require('../utility/hdbTerms.ts');
11
11
  const env = require('../utility/environment/environmentManager.ts');
12
12
  const configUtils = require('../config/configUtils.ts');
13
13
  const hdbUtils = require('../utility/common_utils.ts');
14
+ const {
15
+ isEnvFile,
16
+ isProtectedEnvFile,
17
+ parseEnvKeys,
18
+ renderMaskedEnv,
19
+ upsertEnvValues,
20
+ removeEnvKeys,
21
+ } = require('../utility/envFile.ts');
14
22
  const { handleHDBError, ServerError, hdbErrors } = require('../utility/errors/hdbError.ts');
15
23
  const { HDB_ERROR_MSGS, HTTP_STATUS_CODES } = hdbErrors;
16
24
  const manageThreads = require('../server/threads/manageThreads.js');
@@ -18,7 +26,7 @@ const { packageDirectory } = require('../components/packageComponent.ts');
18
26
  const { Resources } = require('../resources/Resources.ts');
19
27
  const { Application, prepareApplication, ASIDE_STAGING_DIR } = require('./Application.ts');
20
28
  const { server } = require('../server/Server.ts');
21
- const { DeploymentRecorder, awaitDeploymentRow } = require('./deploymentRecorder.ts');
29
+ const { DeploymentRecorder, awaitDeploymentRow, DEFAULT_AWAIT_ROW_TIMEOUT_MS } = require('./deploymentRecorder.ts');
22
30
  const { ProgressEmitter } = require('../server/serverHelpers/progressEmitter.ts');
23
31
 
24
32
  /**
@@ -362,6 +370,16 @@ async function deployComponent(req) {
362
370
  throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
363
371
  }
364
372
 
373
+ // Ingest any provided registry token into the secrets store so the credential lives as
374
+ // replicated ciphertext (reference, not embed); already-reference entries pass through, and with
375
+ // no custody a literal token stays as a transient, this-node-only fallback (#1158). Peers
376
+ // re-running a replicated deploy already carry references and never re-ingest.
377
+ const { ingestRegistryAuth, resolveRegistryAuth } = require('./secretOperations.ts');
378
+ req.registryAuth = await ingestRegistryAuth(req, req.registryAuth, req.project);
379
+ // References are safe to persist (config + deployment row) and replicate; a no-custody literal
380
+ // token is not — it is used only for this node's install below, then stripped before replication.
381
+ const registryAuthReferences = (req.registryAuth ?? []).filter((entry) => entry && entry.secret !== undefined);
382
+
365
383
  // Write to root config if the request contains a package identifier
366
384
  if (req.package) {
367
385
  // Check if trying to overwrite a core component (requires force)
@@ -385,6 +403,9 @@ async function deployComponent(req) {
385
403
  };
386
404
  }
387
405
  if (req.urlPath !== undefined) applicationConfig.urlPath = req.urlPath;
406
+ // Persist registry-auth references (never tokens) so every cold install of this component —
407
+ // reboot, new peer, rollback — re-resolves the credential from the store.
408
+ if (registryAuthReferences.length) applicationConfig.registryAuth = registryAuthReferences;
388
409
  await configUtils.addConfig(req.project, applicationConfig);
389
410
  }
390
411
 
@@ -409,6 +430,8 @@ async function deployComponent(req) {
409
430
  package_identifier: req.package ?? null,
410
431
  user: req.hdb_user?.username,
411
432
  restart_mode: req.restart === 'rolling' ? 'rolling' : req.restart ? 'immediate' : null,
433
+ // Reference form only — the rollback source for re-resolving registry auth.
434
+ registry_auth: registryAuthReferences.length ? registryAuthReferences : null,
412
435
  emitter,
413
436
  });
414
437
  if (recorder) req._deploymentId = recorder.deploymentId;
@@ -446,6 +469,19 @@ async function deployComponent(req) {
446
469
  extractionPayload = row.payload_blob.stream();
447
470
  }
448
471
 
472
+ // Resolve registryAuth references into concrete tokens for this node's npm pack/install
473
+ // (a no-custody literal-token fallback passes through unchanged). On a peer running a
474
+ // replicated deploy, the referenced hdb_secret row may arrive just behind the deploy op, so
475
+ // allow a bounded grace period (same budget as the payload-row wait) for it to replicate in.
476
+ let registryAuthWaitMs = 0;
477
+ if (isReplicatedExecution) {
478
+ const requested = Number(req.deployment_timeout);
479
+ registryAuthWaitMs = Number.isFinite(requested) && requested >= 0 ? requested : DEFAULT_AWAIT_ROW_TIMEOUT_MS;
480
+ }
481
+ const resolvedRegistryAuth = await resolveRegistryAuth(req.registryAuth, req.project, {
482
+ waitMs: registryAuthWaitMs,
483
+ });
484
+
449
485
  const application = new Application({
450
486
  name: req.project,
451
487
  payload: extractionPayload,
@@ -462,7 +498,16 @@ async function deployComponent(req) {
462
498
  installCapture.push(manager, stream, line);
463
499
  if (emitter) emit('install', { manager, stream, line });
464
500
  },
501
+ // Private-registry auth (already resolved above), used here for this node's npm pack/install.
502
+ registryAuth: resolvedRegistryAuth,
465
503
  });
504
+ // Reduce req.registryAuth to references only (never a token) before it can reach an error/log
505
+ // path or replication: references are what peers resolve from their own replicated hdb_secret
506
+ // copy; a no-custody literal token is dropped entirely (peers fall back to their fabric-injected
507
+ // NPM_CONFIG_USERCONFIG, as before). This also fixes the prior success-only strip that leaked a
508
+ // literal token on a prepare/load failure.
509
+ if (registryAuthReferences.length) req.registryAuth = registryAuthReferences;
510
+ else delete req.registryAuth;
466
511
 
467
512
  emit('phase', { phase: 'prepare', status: 'start' });
468
513
  await prepareApplication(application);
@@ -475,18 +520,32 @@ async function deployComponent(req) {
475
520
  pseudoResources.isWorker = true;
476
521
 
477
522
  const componentLoader = require('./componentLoader.ts').default || require('./componentLoader.ts');
523
+ const { trackScopeClose } = require('./scopeShutdown.ts');
478
524
  let lastError;
479
525
  componentLoader.setErrorReporter((error) => (lastError = error));
480
526
  emit('phase', { phase: 'load', status: 'start' });
481
- await componentLoader.loadComponent(
482
- application.dirPath,
483
- pseudoResources,
484
- undefined,
485
- false,
486
- undefined,
487
- false,
488
- req.project
489
- );
527
+ // This load exists only to surface load-time errors early; the Scopes it creates are
528
+ // throwaway. They are collected (instead of registered for worker-shutdown auto-close) so we
529
+ // can close them here once validation completes — otherwise each deploy leaks the Scope's
530
+ // deploy-lifecycle listeners on this worker, eventually tripping MaxListenersExceededWarning
531
+ // (#1462).
532
+ const validationScopes = new Set();
533
+ const validation = (async () => {
534
+ try {
535
+ await componentLoader.loadComponent(application.dirPath, pseudoResources, undefined, {
536
+ collectScopes: validationScopes,
537
+ });
538
+ } finally {
539
+ const closeResults = await Promise.allSettled(Array.from(validationScopes, (scope) => scope.close()));
540
+ for (const result of closeResults) {
541
+ if (result.status === 'rejected') log.warn('Failed to close a deploy-validation Scope', result.reason);
542
+ }
543
+ }
544
+ })();
545
+ // Track the load+close so a concurrent worker shutdown waits for these scopes to finish
546
+ // disposing — a plugin may start a native runtime in handleApplication — before realExit.
547
+ trackScopeClose(validation);
548
+ await validation;
490
549
  emit('phase', { phase: 'load', status: 'done' });
491
550
 
492
551
  if (lastError) throw lastError;
@@ -497,6 +556,9 @@ async function deployComponent(req) {
497
556
  // ProgressEmitter holds function listeners that can't survive the replication
498
557
  // channel's serialization; strip it unconditionally.
499
558
  delete req.progress;
559
+ // req.registryAuth was already deleted immediately after the Application ctor (above) so the
560
+ // token never reaches the replication channel or a peer's operation log; peers authenticate
561
+ // against the private registry via their own fabric-injected NPM_CONFIG_USERCONFIG on reinstall.
500
562
  if (systemReplicated && recorder) {
501
563
  // The hdb_deployment row + payload_blob will reach peers via table replication,
502
564
  // so peers can look up the payload by deployment_id. Drop req.payload to keep
@@ -748,6 +810,10 @@ async function getComponents() {
748
810
  mtime: stats.mtime,
749
811
  size: stats.size,
750
812
  };
813
+ // Flag protected .env files so editors know their contents are masked by
814
+ // get_component_file and only editable via set_env_value. Template files
815
+ // (.env.example / .sample / .template) are not secret, so they are left alone.
816
+ if (isProtectedEnvFile(itemName)) res.protected = true;
751
817
  result.entries.push(res);
752
818
  }
753
819
  }
@@ -762,7 +828,12 @@ async function getComponents() {
762
828
  name: configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT).split(path.sep).slice(-1).pop(),
763
829
  entries: [],
764
830
  });
831
+ const { getUnsatisfiedEnv } = require('./componentSecrets.ts');
765
832
  for (let entry of results.entries) {
833
+ // Declared-but-unsatisfied `env:` expectations (#1550) — metadata only (name, description,
834
+ // required, reason, tier), never values — so Studio/deploy output can render configure-me.
835
+ const unsatisfiedEnv = getUnsatisfiedEnv(entry.name);
836
+ if (unsatisfiedEnv.length > 0) entry.unsatisfiedEnv = unsatisfiedEnv;
766
837
  const componentConfig = rootConfig?.[entry.name];
767
838
  if (!componentConfig || typeof componentConfig !== 'object') continue;
768
839
  if (componentConfig.package) entry.package = componentConfig.package;
@@ -846,6 +917,19 @@ async function getComponentFile(req) {
846
917
  HTTP_STATUS_CODES.CONTENT_TOO_LARGE
847
918
  );
848
919
  }
920
+ // Protected .env files expose the key names (and a value-free masked rendering) but never
921
+ // the secret values. Template files (.env.example etc.) fall through and are read verbatim.
922
+ if (isProtectedEnvFile(req.file)) {
923
+ const keys = parseEnvKeys(await fs.readFile(filePath, 'utf8'));
924
+ return {
925
+ protected: true,
926
+ keys,
927
+ message: renderMaskedEnv(keys),
928
+ size: stats.size,
929
+ birthtime: stats.birthtime,
930
+ mtime: stats.mtime,
931
+ };
932
+ }
849
933
  return {
850
934
  message: await fs.readFile(filePath, options),
851
935
  size: stats.size,
@@ -884,6 +968,113 @@ async function setComponentFile(req) {
884
968
  return response;
885
969
  }
886
970
 
971
+ /**
972
+ * Resolve the absolute path of a project's env file (defaulting to `.env`) and confirm it is one.
973
+ * @param req
974
+ * @returns {{file:string, filePath:string}}
975
+ */
976
+ function resolveEnvFilePath(req) {
977
+ const file = req.file || '.env';
978
+ if (!isEnvFile(file)) {
979
+ const msg = `'${file}' is not a .env file`;
980
+ throw handleHDBError(new Error(msg), msg, HTTP_STATUS_CODES.BAD_REQUEST);
981
+ }
982
+ const compRoot = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
983
+ return { file, filePath: path.join(compRoot, req.project, file) };
984
+ }
985
+
986
+ /**
987
+ * List the key names of a project's .env file. Never returns the secret values.
988
+ * @param req
989
+ * @returns {Promise<{file:string, keys:string[], size:number, mtime:Date}>}
990
+ */
991
+ async function getEnvKeys(req) {
992
+ const validation = validator.getEnvKeysValidator(req);
993
+ if (validation) {
994
+ throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
995
+ }
996
+
997
+ const { file, filePath } = resolveEnvFilePath(req);
998
+ try {
999
+ const [contents, stats] = await Promise.all([fs.readFile(filePath, 'utf8'), fs.stat(filePath)]);
1000
+ return { file, keys: parseEnvKeys(contents), size: stats.size, mtime: stats.mtime };
1001
+ } catch (err) {
1002
+ if (err.code === hdbTerms.NODE_ERROR_CODES.ENOENT) {
1003
+ throw new Error(`Component file not found '${path.join(req.project, file)}'`);
1004
+ }
1005
+ throw err;
1006
+ }
1007
+ }
1008
+
1009
+ /**
1010
+ * Set one (`key` + `value`) or many (`values`) entries in a project's .env file, preserving all
1011
+ * other keys, comments and formatting. Creates the file if it does not exist. Never echoes values.
1012
+ * @param req
1013
+ * @returns {Promise<{message:string, keys:string[]}>}
1014
+ */
1015
+ async function setEnvValue(req) {
1016
+ const validation = validator.setEnvValueValidator(req);
1017
+ if (validation) {
1018
+ throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
1019
+ }
1020
+
1021
+ const { file, filePath } = resolveEnvFilePath(req);
1022
+ const updates = req.values ?? { [req.key]: req.value };
1023
+
1024
+ let existing = '';
1025
+ try {
1026
+ existing = await fs.readFile(filePath, 'utf8');
1027
+ } catch (err) {
1028
+ if (err.code !== hdbTerms.NODE_ERROR_CODES.ENOENT) throw err;
1029
+ }
1030
+
1031
+ let updated;
1032
+ try {
1033
+ updated = upsertEnvValues(existing, updates);
1034
+ } catch (err) {
1035
+ throw handleHDBError(err, err.message, HTTP_STATUS_CODES.BAD_REQUEST);
1036
+ }
1037
+ await fs.outputFile(filePath, updated, 'utf8');
1038
+
1039
+ const response = await server.replication.replicateOperation(req);
1040
+ response.message = `Successfully set env value(s) in ${file}`;
1041
+ response.keys = parseEnvKeys(updated);
1042
+ return response;
1043
+ }
1044
+
1045
+ /**
1046
+ * Remove one (`key`) or many (`keys`) entries from a project's .env file, leaving the rest intact.
1047
+ * @param req
1048
+ * @returns {Promise<{message:string, keys:string[]}>}
1049
+ */
1050
+ async function deleteEnvValue(req) {
1051
+ const validation = validator.deleteEnvValueValidator(req);
1052
+ if (validation) {
1053
+ throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
1054
+ }
1055
+
1056
+ const { file, filePath } = resolveEnvFilePath(req);
1057
+ const keysToRemove = req.keys ?? [req.key];
1058
+
1059
+ let existing;
1060
+ try {
1061
+ existing = await fs.readFile(filePath, 'utf8');
1062
+ } catch (err) {
1063
+ if (err.code === hdbTerms.NODE_ERROR_CODES.ENOENT) {
1064
+ throw new Error(`Component file not found '${path.join(req.project, file)}'`);
1065
+ }
1066
+ throw err;
1067
+ }
1068
+
1069
+ const updated = removeEnvKeys(existing, keysToRemove);
1070
+ await fs.outputFile(filePath, updated, 'utf8');
1071
+
1072
+ const response = await server.replication.replicateOperation(req);
1073
+ response.message = `Successfully deleted env value(s) from ${file}`;
1074
+ response.keys = parseEnvKeys(updated);
1075
+ return response;
1076
+ }
1077
+
887
1078
  /**
888
1079
  * Deletes a component dir/file
889
1080
  * @param req
@@ -939,4 +1130,7 @@ exports.deployComponent = deployComponent;
939
1130
  exports.getComponents = getComponents;
940
1131
  exports.getComponentFile = getComponentFile;
941
1132
  exports.setComponentFile = setComponentFile;
1133
+ exports.getEnvKeys = getEnvKeys;
1134
+ exports.setEnvValue = setEnvValue;
1135
+ exports.deleteEnvValue = deleteEnvValue;
942
1136
  exports.dropComponent = dropComponent;
@@ -9,10 +9,15 @@ const hdbLogger = require('../utility/logging/harper_logger.ts');
9
9
  const configUtils = require('../config/configUtils.ts');
10
10
  const { hdbErrors } = require('../utility/errors/hdbError.ts');
11
11
  const { HDB_ERROR_MSGS } = hdbErrors;
12
+ const { ENV_ENCRYPTED_PREFIX } = require('../utility/envFile.ts');
12
13
 
13
14
  // File name can only be alphanumeric, dash and underscores
14
15
  const PROJECT_FILE_NAME_REGEX = /^[a-zA-Z0-9-_]+$/;
15
16
 
17
+ // dotenv's accepted key character set. Restricting keys to this prevents a crafted key (e.g. one
18
+ // containing `=` or a newline) from injecting extra assignments into a .env file.
19
+ const ENV_KEY_REGEX = /^[\w.-]+$/;
20
+
16
21
  module.exports = {
17
22
  getDropCustomFunctionValidator,
18
23
  setCustomFunctionValidator,
@@ -23,6 +28,12 @@ module.exports = {
23
28
  setComponentFileValidator,
24
29
  getComponentFileValidator,
25
30
  dropComponentFileValidator,
31
+ getEnvKeysValidator,
32
+ setEnvValueValidator,
33
+ deleteEnvValueValidator,
34
+ setSecretValidator,
35
+ grantSecretValidator,
36
+ deleteSecretValidator,
26
37
  };
27
38
 
28
39
  /**
@@ -169,6 +180,141 @@ function getComponentFileValidator(req) {
169
180
  return validator.validateBySchema(req, getCompSchema);
170
181
  }
171
182
 
183
+ /**
184
+ * Validate get_env_keys requests. `file` is optional and defaults to `.env` in the handler.
185
+ * @param req
186
+ * @returns {*}
187
+ */
188
+ function getEnvKeysValidator(req) {
189
+ const schema = Joi.object({
190
+ // Patterned like the env writers (not the looser getComponentFile) so a `project` containing
191
+ // `..` can't traverse out of the components root when joined in resolveEnvFilePath.
192
+ project: Joi.string()
193
+ .pattern(PROJECT_FILE_NAME_REGEX)
194
+ .required()
195
+ .messages({ 'string.pattern.base': HDB_ERROR_MSGS.BAD_PROJECT_NAME }),
196
+ file: Joi.string().custom(checkFilePath).optional(),
197
+ });
198
+
199
+ return validator.validateBySchema(req, schema);
200
+ }
201
+
202
+ /**
203
+ * Validate set_env_value requests: exactly one of (`key` + `value`) or `values` (a key→value map).
204
+ * @param req
205
+ * @returns {*}
206
+ */
207
+ function setEnvValueValidator(req) {
208
+ const schema = Joi.object({
209
+ project: Joi.string()
210
+ .pattern(PROJECT_FILE_NAME_REGEX)
211
+ .required()
212
+ .messages({ 'string.pattern.base': HDB_ERROR_MSGS.BAD_PROJECT_NAME }),
213
+ file: Joi.string().custom(checkFilePath).optional(),
214
+ key: Joi.string().pattern(ENV_KEY_REGEX),
215
+ value: Joi.string().allow(''),
216
+ // `.unknown(false)` rejects keys that don't match ENV_KEY_REGEX. Without it the schema-wide
217
+ // `allowUnknown: true` (see validateBySchema) would let an invalid key (e.g. with a space or
218
+ // newline) pass through unvalidated and corrupt the file.
219
+ values: Joi.object().pattern(ENV_KEY_REGEX, Joi.string().allow('')).unknown(false),
220
+ })
221
+ .with('key', 'value')
222
+ .with('value', 'key')
223
+ .xor('key', 'values');
224
+
225
+ return validator.validateBySchema(req, schema);
226
+ }
227
+
228
+ /**
229
+ * Validate delete_env_value requests: exactly one of `key` or `keys` (an array of key names).
230
+ * @param req
231
+ * @returns {*}
232
+ */
233
+ function deleteEnvValueValidator(req) {
234
+ const schema = Joi.object({
235
+ project: Joi.string()
236
+ .pattern(PROJECT_FILE_NAME_REGEX)
237
+ .required()
238
+ .messages({ 'string.pattern.base': HDB_ERROR_MSGS.BAD_PROJECT_NAME }),
239
+ file: Joi.string().custom(checkFilePath).optional(),
240
+ key: Joi.string().pattern(ENV_KEY_REGEX),
241
+ keys: Joi.array().items(Joi.string().pattern(ENV_KEY_REGEX)).min(1),
242
+ }).xor('key', 'keys');
243
+
244
+ return validator.validateBySchema(req, schema);
245
+ }
246
+
247
+ // A secret name doubles as an env key when materialized, so it is held to the same character set.
248
+ const SECRET_NAME = Joi.string()
249
+ .pattern(ENV_KEY_REGEX)
250
+ .required()
251
+ .messages({ 'string.pattern.base': `'name' must only contain word characters, dots and dashes` });
252
+
253
+ // The encrypted-value marker followed by a base64url envelope body (structural validation of the
254
+ // decoded JSON happens in the handler via parseEnvelopeFields). Derived from the shared prefix
255
+ // constant so validator and handler can't drift; the prefix contains no regex metacharacters.
256
+ // Trailing `=` padding is tolerated — some browser encoders emit padded base64url, and Node's
257
+ // base64url decoder accepts either form.
258
+ const SECRET_ENVELOPE_REGEX = new RegExp(`^${ENV_ENCRYPTED_PREFIX}[A-Za-z0-9_-]+={0,2}$`);
259
+
260
+ // Size cap for secret values and envelopes: rows live forever in a replicated, audited system
261
+ // table, so unbounded payloads are a storage/replication hazard, not a feature.
262
+ const SECRET_MAX_LENGTH = 256 * 1024;
263
+
264
+ /**
265
+ * Validate set_secret requests: `name` plus exactly one of `value` (plaintext) or `envelope`
266
+ * (`enc:v1:` ciphertext), with optional `metadata`, and a tier of either `processEnv` or `grants`
267
+ * (the handler rejects the two together — a processEnv secret is global, so scoping it is meaningless).
268
+ * @param req
269
+ * @returns {*}
270
+ */
271
+ function setSecretValidator(req) {
272
+ const schema = Joi.object({
273
+ name: SECRET_NAME,
274
+ value: Joi.string().allow('').max(SECRET_MAX_LENGTH),
275
+ envelope: Joi.string()
276
+ .max(SECRET_MAX_LENGTH)
277
+ .pattern(SECRET_ENVELOPE_REGEX)
278
+ .messages({ 'string.pattern.base': `'envelope' must be an '${ENV_ENCRYPTED_PREFIX}' base64url envelope` }),
279
+ // Modest structural caps: metadata is a small free-form label object, not a payload store,
280
+ // and grants is a set (explicit duplicates rejected here; write paths also dedupe dirty state).
281
+ metadata: Joi.object().max(100),
282
+ grants: Joi.array().items(Joi.string().min(1)).max(100).unique(),
283
+ // process.env delivery tier; mutually exclusive with grants (enforced in the handler so the
284
+ // check also covers a grants add against an already-processEnv stored row).
285
+ processEnv: Joi.boolean(),
286
+ }).xor('value', 'envelope');
287
+
288
+ return validator.validateBySchema(req, schema);
289
+ }
290
+
291
+ /**
292
+ * Validate grant_secret / revoke_secret requests (same shape: `name` + `component`).
293
+ * @param req
294
+ * @returns {*}
295
+ */
296
+ function grantSecretValidator(req) {
297
+ const schema = Joi.object({
298
+ name: SECRET_NAME,
299
+ component: Joi.string().min(1).required(),
300
+ });
301
+
302
+ return validator.validateBySchema(req, schema);
303
+ }
304
+
305
+ /**
306
+ * Validate delete_secret requests.
307
+ * @param req
308
+ * @returns {*}
309
+ */
310
+ function deleteSecretValidator(req) {
311
+ const schema = Joi.object({
312
+ name: SECRET_NAME,
313
+ });
314
+
315
+ return validator.validateBySchema(req, schema);
316
+ }
317
+
172
318
  /**
173
319
  * Validate addCustomFunctionProject requests.
174
320
  * @param req
@@ -252,6 +398,33 @@ function deployComponentValidator(req) {
252
398
  })
253
399
  .optional()
254
400
  .messages({ 'any.invalid': 'urlPath must not contain ".."' }),
401
+ // Private-registry auth. Each entry supplies its credential exactly one of two ways:
402
+ // - `token`: a literal token, used only for this node's npm pack/install and never
403
+ // persisted or replicated (stripped from req before replicateOperation).
404
+ // - `secret`: the name of an hdb_secret row (#1550); the token is resolved by decrypting
405
+ // that row on this node at deploy time, so the credential lives in the secrets store
406
+ // (reference, not embed) instead of travelling in the operation body.
407
+ registryAuth: Joi.array()
408
+ .items(
409
+ Joi.object({
410
+ // registry and token are written verbatim into the transient .npmrc, which is
411
+ // line-based; forbid CR/LF so a super_user can't inject extra npm config lines.
412
+ // (registry also accepts bare hosts and //host/ forms, so a strict URI validator
413
+ // would reject supported inputs — the newline guard is the right scope here.)
414
+ registry: Joi.string()
415
+ .pattern(/^[^\r\n]+$/)
416
+ .required(),
417
+ token: Joi.string().pattern(/^[^\r\n]+$/),
418
+ // A reference into the hdb_secret store; same name grammar as set_secret's `name`.
419
+ secret: Joi.string()
420
+ .pattern(ENV_KEY_REGEX)
421
+ .messages({ 'string.pattern.base': `'secret' must only contain word characters, dots and dashes` }),
422
+ scope: Joi.string()
423
+ .pattern(/^@[a-z0-9-_.]+$/)
424
+ .optional(),
425
+ }).xor('token', 'secret')
426
+ )
427
+ .optional(),
255
428
  }).with('urlPath', 'package');
256
429
 
257
430
  return validator.validateBySchema(req, deployProjSchema);