@pikku/cli 0.12.143 → 0.12.145

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 (231) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/console-app/assets/HelpPanel-BJQaz5Ah.css +1 -0
  3. package/console-app/assets/HelpPanel-nYO2hRY5.js +1 -0
  4. package/console-app/assets/{abnfDiagram-N423BO3Z-CG60mMUd.js → abnfDiagram-N423BO3Z-BIPJyOId.js} +1 -1
  5. package/console-app/assets/architecture-TIHT7OUA-B-c05-x5.js +1 -0
  6. package/console-app/assets/{architectureDiagram-T3A2C74G-Ch6qWsLf.js → architectureDiagram-T3A2C74G-BAH1O4B7.js} +1 -1
  7. package/console-app/assets/{blockDiagram-VBNYF7ZC-yRgqjgqW.js → blockDiagram-VBNYF7ZC-T3kmcPgj.js} +1 -1
  8. package/console-app/assets/{c4Diagram-5PPSVZJV-NvawOgnU.js → c4Diagram-5PPSVZJV-DRva89Br.js} +1 -1
  9. package/console-app/assets/channel-DJ3jfSNX.js +1 -0
  10. package/console-app/assets/{chunk-2GRJ4B5K-BJ9-Roz7.js → chunk-2GRJ4B5K-pBREt5-Y.js} +1 -1
  11. package/console-app/assets/{chunk-4I5QYGJK-DZwmcj48.js → chunk-4I5QYGJK-SmJ1Rqsn.js} +1 -1
  12. package/console-app/assets/{chunk-5RXB4S5H-BTBwIEIt.js → chunk-5RXB4S5H-wo8Xtqiv.js} +1 -1
  13. package/console-app/assets/{chunk-6Q2QTUOP-C55aqlA-.js → chunk-6Q2QTUOP-B6uqaxr0.js} +1 -1
  14. package/console-app/assets/{chunk-7Z6QIM7H-DRmYZ-SZ.js → chunk-7Z6QIM7H-uxzNGOHh.js} +1 -1
  15. package/console-app/assets/{chunk-GF5L2VYU-InZeM4Hr.js → chunk-GF5L2VYU-Cw7tsTe6.js} +1 -1
  16. package/console-app/assets/{chunk-I66GZJ75-BNvijc65.js → chunk-I66GZJ75-DksrbEtn.js} +1 -1
  17. package/console-app/assets/{chunk-JQJVKLGR-CIMXqmif.js → chunk-JQJVKLGR-BnRvPhDK.js} +1 -1
  18. package/console-app/assets/{chunk-KBJHAD2P-C9h3FBoE.js → chunk-KBJHAD2P-PiPaopal.js} +1 -1
  19. package/console-app/assets/{chunk-NSK5VX7P-lz8xBTRo.js → chunk-NSK5VX7P-VK0slsok.js} +1 -1
  20. package/console-app/assets/{chunk-QR6OTTB3-CjOfjLMq.js → chunk-QR6OTTB3-CgQotuzQ.js} +1 -1
  21. package/console-app/assets/{chunk-RYQCIY6F-CV3667Qm.js → chunk-RYQCIY6F-Cei0abOq.js} +1 -1
  22. package/console-app/assets/{chunk-UBXNYLIW-CBN7usxw.js → chunk-UBXNYLIW-B55XJk4O.js} +1 -1
  23. package/console-app/assets/{chunk-W5SLKNZC-5TkpffRm.js → chunk-W5SLKNZC-gFa01tuI.js} +1 -1
  24. package/console-app/assets/{chunk-WRU74C26-GBek0Nby.js → chunk-WRU74C26-C3ESZQ-F.js} +1 -1
  25. package/console-app/assets/chunk-XXDRQBXY-D0tL6SVk.js +1 -0
  26. package/console-app/assets/classDiagram-JCYQIIEL-BqEwCDi8.js +1 -0
  27. package/console-app/assets/classDiagram-v2-OCEON4UE-BqEwCDi8.js +1 -0
  28. package/console-app/assets/{cose-bilkent-JH36ORCC-BkGyb7Kn.js → cose-bilkent-JH36ORCC-CUxqwjs-.js} +1 -1
  29. package/console-app/assets/{cynefin-VYW2F7L2-qMmeyMja.js → cynefin-VYW2F7L2-Dh1yOBBs.js} +1 -1
  30. package/console-app/assets/{cynefinDiagram-MW4NZA55-7MuIYiO4.js → cynefinDiagram-MW4NZA55-BzFWEf8Y.js} +1 -1
  31. package/console-app/assets/{dagre-BbESpUs5.js → dagre-DKjebq_c.js} +1 -1
  32. package/console-app/assets/{dagre-VZM6K2ZE-I6YsMazW.js → dagre-VZM6K2ZE-BllFBMe9.js} +1 -1
  33. package/console-app/assets/{diagram-7IWD3JNH-CJPB2T6d.js → diagram-7IWD3JNH-C58VaHJt.js} +1 -1
  34. package/console-app/assets/{diagram-B4RE2ZJO-CmFGMFPx.js → diagram-B4RE2ZJO-B3w3TcXn.js} +1 -1
  35. package/console-app/assets/{diagram-LBJQPF4R-BMzRMe8g.js → diagram-LBJQPF4R-L1ZkDsab.js} +1 -1
  36. package/console-app/assets/{diagram-Q27KOJAE-CeJb7xQ2.js → diagram-Q27KOJAE-7oaP3D-d.js} +1 -1
  37. package/console-app/assets/{diagram-UB23O5K3-BQkhJgYU.js → diagram-UB23O5K3-CmRNd5vm.js} +1 -1
  38. package/console-app/assets/{ebnfDiagram-BXEA7PRR-C1F_8089.js → ebnfDiagram-BXEA7PRR-D0rxzLaa.js} +1 -1
  39. package/console-app/assets/{erDiagram-JOGREHBK-DRwpdW4v.js → erDiagram-JOGREHBK-Bg0FPLS0.js} +1 -1
  40. package/console-app/assets/eventmodeling-45OFAUF4-CVovwmpS.js +1 -0
  41. package/console-app/assets/flowDiagram-UKHOOZJN-DwRgEyXD.js +1 -0
  42. package/console-app/assets/ganttDiagram-PKOTCBZU-BBxxHrPG.js +292 -0
  43. package/console-app/assets/{gitGraph-TEB2WS4Q-BBt9AGD3.js → gitGraph-TEB2WS4Q-Cn1MjFvM.js} +1 -1
  44. package/console-app/assets/{gitGraphDiagram-DS77QQ5N-y5WPOR-G.js → gitGraphDiagram-DS77QQ5N-JaW7OYCY.js} +1 -1
  45. package/console-app/assets/{index-BmvyL35Z.js → index-Deds7K2I.js} +178 -178
  46. package/console-app/assets/{info-DKCQHKI2-mYDlDDyA.js → info-DKCQHKI2-C2R7hV-y.js} +1 -1
  47. package/console-app/assets/{infoDiagram-6WML65LV-uOP7AjEu.js → infoDiagram-6WML65LV-DIbMcTbW.js} +1 -1
  48. package/console-app/assets/{ishikawaDiagram-WSZJBQD7-BUMKV94t.js → ishikawaDiagram-WSZJBQD7-mozqgfxi.js} +1 -1
  49. package/console-app/assets/{journeyDiagram-NVQOT4AX-C8_km86P.js → journeyDiagram-NVQOT4AX-CKDrjPz5.js} +1 -1
  50. package/console-app/assets/{kanban-definition-27J2QSJJ-Ce5oUBPR.js → kanban-definition-27J2QSJJ-B9shPbST.js} +1 -1
  51. package/console-app/assets/{line-D-6c8Gxs.js → line-DLrnl2PN.js} +1 -1
  52. package/console-app/assets/{linear-CyrGkJOO.js → linear-BQOZezXu.js} +1 -1
  53. package/console-app/assets/{mermaid-parser.core-CYuFKArA.js → mermaid-parser.core-ElI_yw4f.js} +3 -3
  54. package/console-app/assets/{mermaid.core-CXQhu3yO.js → mermaid.core-B02bSmuz.js} +4 -4
  55. package/console-app/assets/{mindmap-definition-FAOFIHXS-CTMHna5d.js → mindmap-definition-FAOFIHXS-BTvmLZE7.js} +1 -1
  56. package/console-app/assets/{packet-7NZHBO7P-Bu7Wxek6.js → packet-7NZHBO7P-CkYMF0Cd.js} +1 -1
  57. package/console-app/assets/{pegDiagram-VL7TDLO6-CQOikBgW.js → pegDiagram-VL7TDLO6-1hBiUSmO.js} +1 -1
  58. package/console-app/assets/{pie-RZYD4A2V-Co7qIvyZ.js → pie-RZYD4A2V-BFMvieVM.js} +1 -1
  59. package/console-app/assets/{pieDiagram-7S7Q4E2Y-Dh6jYgnj.js → pieDiagram-7S7Q4E2Y-vvgYfdFq.js} +1 -1
  60. package/console-app/assets/{quadrantDiagram-CIZ2JOQS-Boongjy-.js → quadrantDiagram-CIZ2JOQS-B_emxK6O.js} +1 -1
  61. package/console-app/assets/{radar-I7S5WNFK-CSJyAKYA.js → radar-I7S5WNFK-C_2tp7_w.js} +1 -1
  62. package/console-app/assets/{railroad-3IZDKUUU-DklknXem.js → railroad-3IZDKUUU-DwlFJLv5.js} +1 -1
  63. package/console-app/assets/railroad-abnf-AHOZXSZD-Cyu_rpdZ.js +1 -0
  64. package/console-app/assets/railroad-ebnf-EBAXGLYW-BLiwK-H7.js +1 -0
  65. package/console-app/assets/railroad-peg-LSFZ7HO6-BUDTDYmP.js +1 -0
  66. package/console-app/assets/{railroadDiagram-AXF67PYL-DEapZRM_.js → railroadDiagram-AXF67PYL-IXXj_KlB.js} +1 -1
  67. package/console-app/assets/{requirementDiagram-LRYGKXZP-CqFLtnyL.js → requirementDiagram-LRYGKXZP-B15ZEbec.js} +1 -1
  68. package/console-app/assets/{sankeyDiagram-W5VNT64P-CNu-G1MH.js → sankeyDiagram-W5VNT64P-w-sj_WN8.js} +1 -1
  69. package/console-app/assets/{sequenceDiagram-SI44F4Z6-CoEKUR3G.js → sequenceDiagram-SI44F4Z6-BP1UgEbX.js} +1 -1
  70. package/console-app/assets/{src-C1UIZ0TF.js → src-BI35UZf8.js} +1 -1
  71. package/console-app/assets/{stateDiagram-OKZ733FA-CJka40EH.js → stateDiagram-OKZ733FA-DE4L-y3n.js} +1 -1
  72. package/console-app/assets/stateDiagram-v2-UEYNNEHI-BsP8TwKV.js +1 -0
  73. package/console-app/assets/{swimlanes-SLNWSIFB-Dv3MGmvW.js → swimlanes-SLNWSIFB-DvAJxCGQ.js} +1 -1
  74. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-BAXO3Id2.js +8 -0
  75. package/console-app/assets/{timeline-definition-Z64GVDOM-CO8etJHi.js → timeline-definition-Z64GVDOM-Cc8M2qee.js} +1 -1
  76. package/console-app/assets/{treeView-QDETBFTQ-BjLcvY-V.js → treeView-QDETBFTQ-DnlS0s0_.js} +1 -1
  77. package/console-app/assets/{treemap-6X3UGDF4-xC9XqGfS.js → treemap-6X3UGDF4-CiUoxlJe.js} +1 -1
  78. package/console-app/assets/{vennDiagram-T6HMQDX7-CJGsYvlQ.js → vennDiagram-T6HMQDX7-dpGyGzMg.js} +1 -1
  79. package/console-app/assets/{wardley-OPB4EBWU-DkMc876g.js → wardley-OPB4EBWU-DrTySJtR.js} +1 -1
  80. package/console-app/assets/{wardleyDiagram-T6FBY63Y-CTe7zAVZ.js → wardleyDiagram-T6FBY63Y-CBvRf8GJ.js} +1 -1
  81. package/console-app/assets/{xychartDiagram-ELKLHX3M-CABg-MLE.js → xychartDiagram-ELKLHX3M-UlPqx-ve.js} +1 -1
  82. package/console-app/index.html +1 -1
  83. package/dist/.pikku/addon/index.d.ts +1 -1
  84. package/dist/.pikku/addon/index.js +1 -1
  85. package/dist/.pikku/addon/pikku-addon-types.gen.d.ts +1 -1
  86. package/dist/.pikku/addon/pikku-addon-types.gen.js +1 -1
  87. package/dist/.pikku/agent/index.d.ts +1 -1
  88. package/dist/.pikku/agent/index.js +1 -1
  89. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  90. package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
  91. package/dist/.pikku/auth/index.d.ts +1 -1
  92. package/dist/.pikku/auth/index.js +1 -1
  93. package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
  94. package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
  95. package/dist/.pikku/channel/index.d.ts +1 -1
  96. package/dist/.pikku/channel/index.js +1 -1
  97. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  98. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  99. package/dist/.pikku/cli/index.d.ts +1 -1
  100. package/dist/.pikku/cli/index.js +1 -1
  101. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  102. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  103. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  104. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  105. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  106. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  107. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  108. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  109. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  110. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  111. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  112. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  113. package/dist/.pikku/error/index.d.ts +1 -1
  114. package/dist/.pikku/error/index.js +1 -1
  115. package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
  116. package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
  117. package/dist/.pikku/function/index.d.ts +1 -1
  118. package/dist/.pikku/function/index.js +1 -1
  119. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  120. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  121. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  122. package/dist/.pikku/function/pikku-functions-meta.gen.json +2 -2
  123. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  124. package/dist/.pikku/gateway/index.d.ts +1 -1
  125. package/dist/.pikku/gateway/index.js +1 -1
  126. package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
  127. package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
  128. package/dist/.pikku/http/index.d.ts +1 -1
  129. package/dist/.pikku/http/index.js +1 -1
  130. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  131. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  132. package/dist/.pikku/mcp/index.d.ts +1 -1
  133. package/dist/.pikku/mcp/index.js +1 -1
  134. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  135. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  136. package/dist/.pikku/middleware/index.d.ts +1 -1
  137. package/dist/.pikku/middleware/index.js +1 -1
  138. package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
  139. package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
  140. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  141. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  142. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  143. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  144. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  145. package/dist/.pikku/queue/index.d.ts +1 -1
  146. package/dist/.pikku/queue/index.js +1 -1
  147. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  148. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  149. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  150. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  151. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  152. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  153. package/dist/.pikku/scenarios/index.d.ts +1 -1
  154. package/dist/.pikku/scenarios/index.js +1 -1
  155. package/dist/.pikku/scenarios/pikku-personas.gen.js +1 -1
  156. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  157. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  158. package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
  159. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  160. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  161. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  162. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  163. package/dist/.pikku/scheduler/index.d.ts +1 -1
  164. package/dist/.pikku/scheduler/index.js +1 -1
  165. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  166. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  167. package/dist/.pikku/schemas/register.gen.js +1 -1
  168. package/dist/.pikku/scopes/index.d.ts +1 -1
  169. package/dist/.pikku/scopes/index.js +1 -1
  170. package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
  171. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
  172. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  173. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  174. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  175. package/dist/.pikku/secrets/index.d.ts +1 -1
  176. package/dist/.pikku/secrets/index.js +1 -1
  177. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  178. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  179. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  180. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  181. package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
  182. package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
  183. package/dist/.pikku/setup/index.d.ts +1 -1
  184. package/dist/.pikku/setup/index.js +1 -1
  185. package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
  186. package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
  187. package/dist/.pikku/trigger/index.d.ts +1 -1
  188. package/dist/.pikku/trigger/index.js +1 -1
  189. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  190. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  191. package/dist/.pikku/variables/index.d.ts +1 -1
  192. package/dist/.pikku/variables/index.js +1 -1
  193. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  194. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  195. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  196. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  197. package/dist/.pikku/workflow/index.d.ts +1 -1
  198. package/dist/.pikku/workflow/index.js +1 -1
  199. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  200. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  201. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  202. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  203. package/dist/bin/pikku-bin.mjs +2 -2
  204. package/dist/src/deploy/analyzer/analyzer.d.ts +8 -1
  205. package/dist/src/deploy/analyzer/analyzer.js +237 -49
  206. package/dist/src/deploy/analyzer/grouping.d.ts +23 -0
  207. package/dist/src/deploy/analyzer/grouping.js +74 -0
  208. package/dist/src/deploy/analyzer/index.d.ts +1 -0
  209. package/dist/src/deploy/analyzer/naming.d.ts +1 -0
  210. package/dist/src/deploy/analyzer/naming.js +9 -0
  211. package/dist/src/deploy/build-pipeline.d.ts +2 -0
  212. package/dist/src/deploy/build-pipeline.js +20 -0
  213. package/dist/src/deploy/codegen/per-unit-codegen.js +8 -2
  214. package/dist/src/functions/commands/deploy-apply.js +1 -0
  215. package/dist/src/functions/commands/deploy-plan.js +1 -0
  216. package/dist/tsconfig.tsbuildinfo +1 -1
  217. package/package.json +6 -6
  218. package/surface.json +1 -1
  219. package/console-app/assets/architecture-TIHT7OUA-DSzfLiV3.js +0 -1
  220. package/console-app/assets/channel-DYUdcfEK.js +0 -1
  221. package/console-app/assets/chunk-XXDRQBXY-B3U_w_pW.js +0 -1
  222. package/console-app/assets/classDiagram-JCYQIIEL-Mg8_8GSE.js +0 -1
  223. package/console-app/assets/classDiagram-v2-OCEON4UE-Mg8_8GSE.js +0 -1
  224. package/console-app/assets/eventmodeling-45OFAUF4-C5L7A6YY.js +0 -1
  225. package/console-app/assets/flowDiagram-UKHOOZJN-D6GmsM3x.js +0 -1
  226. package/console-app/assets/ganttDiagram-PKOTCBZU-CfsGz3Lj.js +0 -292
  227. package/console-app/assets/railroad-abnf-AHOZXSZD-D-2EAJOD.js +0 -1
  228. package/console-app/assets/railroad-ebnf-EBAXGLYW-C5XxxCx7.js +0 -1
  229. package/console-app/assets/railroad-peg-LSFZ7HO6-D8fXoMuX.js +0 -1
  230. package/console-app/assets/stateDiagram-v2-UEYNNEHI-Bfuo66an.js +0 -1
  231. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-CyQmsXKP.js +0 -8
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  /**
5
5
  * Subpath entry — `#pikku/workflow` resolves here.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  /**
5
5
  * Subpath entry — `#pikku/workflow` resolves here.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  import { WorkflowCancelledException } from '@pikku/core/workflow';
5
5
  import type { PikkuWorkflowGraphConfig, PikkuWorkflowGraphResult } from '@pikku/core/workflow';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  import { WorkflowCancelledException } from '@pikku/core/workflow';
5
5
  import { pikkuWorkflowGraph as corePikkuWorkflowGraph } from '@pikku/core/workflow';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  import { pikkuState } from '@pikku/core/state';
5
5
  import allWorkflowMeta from './meta/allWorkflow.gen.json' with { type: 'json' };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.143
2
+ * This file was generated by @pikku/cli@0.12.145
3
3
  */
4
4
  import { addWorkflow } from '@pikku/core/workflow';
5
5
  import './pikku-workflow-wirings-meta.gen.js';
@@ -11,8 +11,8 @@ async function checkForUpdate() {
11
11
  })
12
12
  if (!res.ok) return
13
13
  const { version: latest } = await res.json()
14
- if (latest !== '0.12.143') {
15
- process.stderr.write(`\n Update available 0.12.143 → ${latest}\n brew upgrade pikku or npm install -g @pikku/cli\n\n`)
14
+ if (latest !== '0.12.145') {
15
+ process.stderr.write(`\n Update available 0.12.145 → ${latest}\n brew upgrade pikku or npm install -g @pikku/cli\n\n`)
16
16
  }
17
17
  } catch {}
18
18
  }
@@ -7,6 +7,7 @@
7
7
  * Workflow orchestrators dispatch to step units via queue or RPC (inline).
8
8
  */
9
9
  import { type InspectorState } from '@pikku/inspector';
10
+ import { type GroupingConfig } from './grouping.js';
10
11
  import type { DeploymentManifest } from '@pikku/deploy';
11
12
  export interface AnalyzerOptions {
12
13
  projectId: string;
@@ -34,6 +35,12 @@ export interface AnalyzerOptions {
34
35
  */
35
36
  workflowQueues?: boolean;
36
37
  globalHTTPPrefix?: string;
38
+ /**
39
+ * Sourced from `pikku.config.json` → `deploy.grouping`. Decides how many
40
+ * deployment units the `role: 'function'` units collapse into. Omitted
41
+ * means one unit per function.
42
+ */
43
+ grouping?: GroupingConfig;
37
44
  }
38
45
  export declare function analyzeDeployment(state: InspectorState, options: AnalyzerOptions): DeploymentManifest;
39
- export declare function toSafeKebab(str: string): string;
46
+ export { toSafeKebab } from './naming.js';
@@ -9,6 +9,8 @@
9
9
  import { resolveDeployTarget, } from '@pikku/inspector';
10
10
  import { relative } from 'node:path';
11
11
  import { isScenarioFunction, withoutScenarios, withoutScenarioWorkflows, } from '../../functions/wirings/scenarios/scenario-partition.js';
12
+ import { toSafeKebab } from './naming.js';
13
+ import { createUnitResolver } from './grouping.js';
12
14
  export function analyzeDeployment(state, options) {
13
15
  const serverlessIncompatible = new Set(options.serverlessIncompatible ?? []);
14
16
  const defaultTarget = options.defaultTarget ?? 'serverless';
@@ -30,6 +32,86 @@ export function analyzeDeployment(state, options) {
30
32
  const functionsMeta = withoutScenarios(state.functions.meta);
31
33
  const graphMeta = withoutScenarioWorkflows(state.workflows.graphMeta);
32
34
  const httpMeta = state.http.meta;
35
+ const tagIndex = buildFunctionTagIndex(state, functionsMeta);
36
+ const tagsFor = (funcId) => tagIndex.get(funcId) ?? [];
37
+ const resolver = createUnitResolver(options.grouping, {
38
+ routesForFunction: (funcId) => collectHttpRoutes(httpMeta, funcId).flatMap((r) => [
39
+ r.route,
40
+ prefixed(r.route),
41
+ ]),
42
+ tagsForFunction: tagsFor,
43
+ });
44
+ const addFunctionUnit = (unit) => {
45
+ const existing = units.find((u) => u.name === unit.name);
46
+ if (!existing) {
47
+ units.push(unit);
48
+ return;
49
+ }
50
+ if (existing.target !== unit.target) {
51
+ const rule = resolver.ruleForUnit(unit.name);
52
+ throw new Error(`deploy.grouping: unit "${unit.name}" would hold both serverless and server functions ` +
53
+ `(${existing.functionIds.join(', ')} vs ${unit.functionIds.join(', ')}). ` +
54
+ (rule
55
+ ? `Give the server-target functions their own rule, or drop them from "${unit.name}".`
56
+ : `A grouping rule cannot change a function's target.`));
57
+ }
58
+ for (const id of unit.functionIds) {
59
+ if (!existing.functionIds.includes(id)) {
60
+ existing.functionIds.push(id);
61
+ }
62
+ }
63
+ for (const service of unit.services) {
64
+ if (!existing.services.some((s) => s.capability === service.capability &&
65
+ s.sourceServiceName === service.sourceServiceName)) {
66
+ existing.services.push(service);
67
+ }
68
+ }
69
+ for (const dep of unit.dependsOn) {
70
+ if (dep !== existing.name && !existing.dependsOn.includes(dep)) {
71
+ existing.dependsOn.push(dep);
72
+ }
73
+ }
74
+ for (const tag of unit.tags) {
75
+ if (!existing.tags.includes(tag)) {
76
+ existing.tags.push(tag);
77
+ }
78
+ }
79
+ for (const handler of unit.handlers) {
80
+ if (handler.type === 'fetch') {
81
+ const fetchHandler = existing.handlers.find((h) => h.type === 'fetch');
82
+ if (fetchHandler) {
83
+ fetchHandler.routes.push(...handler.routes);
84
+ }
85
+ else {
86
+ existing.handlers.push(handler);
87
+ }
88
+ }
89
+ else {
90
+ existing.handlers.push(handler);
91
+ }
92
+ }
93
+ if (unit.invokedAgents?.length) {
94
+ const merged = new Set([
95
+ ...(existing.invokedAgents ?? []),
96
+ ...unit.invokedAgents,
97
+ ]);
98
+ existing.invokedAgents = [...merged];
99
+ }
100
+ };
101
+ const unitFunctionIds = new Map();
102
+ const unitFor = (funcId) => {
103
+ const name = resolver.forFunction(funcId);
104
+ const existing = unitFunctionIds.get(name);
105
+ if (existing) {
106
+ if (!existing.includes(funcId)) {
107
+ existing.push(funcId);
108
+ }
109
+ }
110
+ else {
111
+ unitFunctionIds.set(name, [funcId]);
112
+ }
113
+ return name;
114
+ };
33
115
  // ── Step 1: Create function units ──────────────────────────────────
34
116
  // Each function gets one unit. Collect all its triggers.
35
117
  for (const [funcId, funcMeta] of entries(functionsMeta)) {
@@ -70,7 +152,7 @@ export function analyzeDeployment(state, options) {
70
152
  handlers.push({ type: 'queue', queueName: queueMeta.name ?? queueName });
71
153
  queues.push({
72
154
  name: queueMeta.name ?? queueName,
73
- consumerUnit: toSafeKebab(funcId),
155
+ consumerUnit: unitFor(funcId),
74
156
  consumerFunctionId: funcId,
75
157
  });
76
158
  }
@@ -86,7 +168,7 @@ export function analyzeDeployment(state, options) {
86
168
  scheduledTasks.push({
87
169
  name: schedMeta.name,
88
170
  schedule: schedMeta.schedule,
89
- unitName: toSafeKebab(funcId),
171
+ unitName: unitFor(funcId),
90
172
  functionId: funcId,
91
173
  });
92
174
  }
@@ -128,25 +210,72 @@ export function analyzeDeployment(state, options) {
128
210
  continue;
129
211
  }
130
212
  const invokedAgents = collectInvokedAgents(state, funcId);
131
- units.push({
132
- name: toSafeKebab(funcId),
213
+ addFunctionUnit({
214
+ name: unitFor(funcId),
133
215
  role: 'function',
134
216
  target: resolveDeployTarget(funcMeta, serverlessIncompatible, funcId, defaultTarget),
135
217
  functionIds: [funcId],
136
218
  services: withAgentServices(collectServicesForFunction(funcMeta), invokedAgents),
137
219
  dependsOn: [],
138
220
  handlers,
139
- tags: funcMeta.tags ?? [],
221
+ tags: tagsFor(funcId),
140
222
  ...(invokedAgents.length > 0 && { invokedAgents }),
141
223
  });
142
224
  }
225
+ // ── Step 1b: Addon units ───────────────────────────────────────────
226
+ const addonUnitByRpcName = new Map();
227
+ for (const [namespace, addonMeta] of entries(state.addonFunctions ?? {})) {
228
+ const exposed = entries(addonMeta).filter(([, meta]) => meta.expose);
229
+ if (exposed.length === 0) {
230
+ continue;
231
+ }
232
+ const unitName = resolver.forAddon(namespace);
233
+ const addonIncompatible = new Set(state.addonServerlessIncompatible?.get(namespace) ?? []);
234
+ const routes = [];
235
+ const functionIds = [];
236
+ const services = [];
237
+ let target = defaultTarget;
238
+ for (const [funcName, funcMeta] of exposed) {
239
+ const rpcName = `${namespace}:${funcName}`;
240
+ functionIds.push(rpcName);
241
+ addonUnitByRpcName.set(rpcName, unitName);
242
+ routes.push({
243
+ method: 'post',
244
+ route: prefixed(`/rpc/${rpcName}`),
245
+ pikkuFuncId: rpcName,
246
+ });
247
+ routes.push({
248
+ method: 'post',
249
+ route: prefixed(`/remote/rpc/${rpcName}`),
250
+ pikkuFuncId: rpcName,
251
+ });
252
+ for (const service of collectServicesForFunction(funcMeta)) {
253
+ if (!services.some((s) => s.sourceServiceName === service.sourceServiceName)) {
254
+ services.push(service);
255
+ }
256
+ }
257
+ if (resolveDeployTarget(funcMeta, addonIncompatible, rpcName, defaultTarget) === 'server') {
258
+ target = 'server';
259
+ }
260
+ }
261
+ addFunctionUnit({
262
+ name: unitName,
263
+ role: 'function',
264
+ target,
265
+ functionIds,
266
+ services,
267
+ dependsOn: [],
268
+ handlers: [{ type: 'fetch', routes }],
269
+ tags: [],
270
+ });
271
+ }
143
272
  // ── Step 2: Agent gateways ─────────────────────────────────────────
144
273
  for (const [agentName, agentMeta] of entries(state.agents.agentsMeta)) {
145
274
  const toolIds = agentMeta.tools ?? [];
146
275
  const subAgentNames = agentMeta.agents ?? [];
147
276
  const unitName = `agent-${toSafeKebab(agentName)}`;
148
277
  // Agent gateway depends on its tool function units
149
- const toolUnitNames = toolIds.map((id) => toSafeKebab(id));
278
+ const toolUnitNames = toolIds.map((id) => unitFor(id));
150
279
  const subAgentUnitNames = subAgentNames.map((sa) => `agent-${toSafeKebab(sa)}`);
151
280
  // Agent needs AI services
152
281
  const agentServices = agentServiceRequirements();
@@ -224,7 +353,7 @@ export function analyzeDeployment(state, options) {
224
353
  const allMcpIds = [...mcpToolIds, ...mcpResourceIds, ...mcpPromptIds];
225
354
  if (allMcpIds.length > 0) {
226
355
  const unitName = 'mcp-server';
227
- const mcpFuncUnitNames = allMcpIds.map((id) => toSafeKebab(id));
356
+ const mcpFuncUnitNames = allMcpIds.map((id) => unitFor(id));
228
357
  units.push({
229
358
  name: unitName,
230
359
  role: 'mcp',
@@ -233,7 +362,7 @@ export function analyzeDeployment(state, options) {
233
362
  services: [],
234
363
  dependsOn: mcpFuncUnitNames,
235
364
  handlers: [{ type: 'fetch', routes: [] }],
236
- tags: collectTags(allMcpIds, functionsMeta),
365
+ tags: collectTags(allMcpIds, tagsFor),
237
366
  });
238
367
  mcpEndpoints.push({
239
368
  unitName,
@@ -248,7 +377,7 @@ export function analyzeDeployment(state, options) {
248
377
  if (funcIds.length === 0)
249
378
  continue;
250
379
  const unitName = `channel-${toSafeKebab(channelName)}`;
251
- const funcUnitNames = funcIds.map((id) => toSafeKebab(id));
380
+ const funcUnitNames = funcIds.map((id) => unitFor(id));
252
381
  units.push({
253
382
  name: unitName,
254
383
  role: 'channel',
@@ -267,34 +396,35 @@ export function analyzeDeployment(state, options) {
267
396
  });
268
397
  }
269
398
  // ── Step 5: Workflows ──────────────────────────────────────────────
270
- buildWorkflows(graphMeta, functionsMeta, { ...state.rpc?.exposedMeta, ...state.rpc?.internalMeta }, httpMeta, units, workflows, queues, workflowQueues);
399
+ buildWorkflows(graphMeta, functionsMeta, { ...state.rpc?.exposedMeta, ...state.rpc?.internalMeta }, httpMeta, units, workflows, queues, workflowQueues, unitFor);
271
400
  // ── Step 6: Ensure function units exist for gateway dependencies ───
272
401
  // Gateways depend on function units. If a function is only used via
273
402
  // a gateway (not directly wired to HTTP/queue/cron), it still needs
274
403
  // a unit with a fetch handler for RPC access.
275
- const existingUnitNames = new Set(units.map((u) => u.name));
276
404
  const unitsSnapshot = Array.from(units);
277
405
  for (const unit of unitsSnapshot) {
278
406
  for (const dep of unit.dependsOn) {
279
- if (!existingUnitNames.has(dep)) {
280
- // Find the function ID for this dependency
281
- const funcId = fromKebab(dep);
407
+ for (const funcId of unitFunctionIds.get(dep) ?? []) {
408
+ const existing = units.find((u) => u.name === dep);
409
+ if (existing?.functionIds.includes(funcId)) {
410
+ continue;
411
+ }
282
412
  const funcMeta = functionsMeta[funcId];
283
- if (funcMeta) {
284
- const invokedAgents = collectInvokedAgents(state, funcId);
285
- units.push({
286
- name: dep,
287
- role: 'function',
288
- target: resolveDeployTarget(funcMeta, serverlessIncompatible, funcId, defaultTarget),
289
- functionIds: [funcId],
290
- services: withAgentServices(collectServicesForFunction(funcMeta), invokedAgents),
291
- dependsOn: [],
292
- handlers: [{ type: 'fetch', routes: [] }],
293
- tags: funcMeta.tags ?? [],
294
- ...(invokedAgents.length > 0 && { invokedAgents }),
295
- });
296
- existingUnitNames.add(dep);
413
+ if (!funcMeta) {
414
+ continue;
297
415
  }
416
+ const invokedAgents = collectInvokedAgents(state, funcId);
417
+ addFunctionUnit({
418
+ name: dep,
419
+ role: 'function',
420
+ target: resolveDeployTarget(funcMeta, serverlessIncompatible, funcId, defaultTarget),
421
+ functionIds: [funcId],
422
+ services: withAgentServices(collectServicesForFunction(funcMeta), invokedAgents),
423
+ dependsOn: [],
424
+ handlers: [{ type: 'fetch', routes: [] }],
425
+ tags: tagsFor(funcId),
426
+ ...(invokedAgents.length > 0 && { invokedAgents }),
427
+ });
298
428
  }
299
429
  }
300
430
  }
@@ -457,6 +587,25 @@ export function analyzeDeployment(state, options) {
457
587
  }
458
588
  }
459
589
  }
590
+ if (addonUnitByRpcName.size > 0) {
591
+ const catchAll = prefixed('/rpc/:rpcName');
592
+ for (const unit of units) {
593
+ if (addonUnitByRpcName.has(unit.functionIds[0] ?? ''))
594
+ continue;
595
+ const servesCatchAll = unit.handlers.some((handler) => handler.type === 'fetch' &&
596
+ handler.routes.some((route) => route.route === catchAll));
597
+ if (!servesCatchAll)
598
+ continue;
599
+ const dispatch = { ...(unit.dispatch ?? {}) };
600
+ for (const [rpcName, unitName] of addonUnitByRpcName) {
601
+ dispatch[rpcName] = unitName;
602
+ if (!unit.dependsOn.includes(unitName)) {
603
+ unit.dependsOn.push(unitName);
604
+ }
605
+ }
606
+ unit.dispatch = dispatch;
607
+ }
608
+ }
460
609
  const byNamespace = (a, b) => a.namespace.localeCompare(b.namespace);
461
610
  const variablesById = new Map();
462
611
  for (const v of state.variables.definitions) {
@@ -491,7 +640,7 @@ export function analyzeDeployment(state, options) {
491
640
  // ---------------------------------------------------------------------------
492
641
  // Workflow builder
493
642
  // ---------------------------------------------------------------------------
494
- function buildWorkflows(graphMeta, functionsMeta, rpcMeta, _httpMeta, units, workflows, queues, workflowQueues) {
643
+ function buildWorkflows(graphMeta, functionsMeta, rpcMeta, _httpMeta, units, workflows, queues, workflowQueues, unitFor) {
495
644
  for (const [_wfName, graph] of entries(graphMeta)) {
496
645
  const steps = [];
497
646
  const stepUnitNames = [];
@@ -500,7 +649,7 @@ function buildWorkflows(graphMeta, functionsMeta, rpcMeta, _httpMeta, units, wor
500
649
  continue;
501
650
  if (!('rpcName' in node))
502
651
  continue;
503
- const stepUnitName = toSafeKebab(node.rpcName);
652
+ const stepUnitName = unitFor(node.rpcName);
504
653
  // Step dispatch is decided per-function: a step runs inline unless its
505
654
  // function is marked `workflowQueued: true` (then it dispatches via queue).
506
655
  const stepFuncId = rpcMeta[node.rpcName] ?? node.rpcName;
@@ -588,7 +737,7 @@ function buildWorkflows(graphMeta, functionsMeta, rpcMeta, _httpMeta, units, wor
588
737
  const stepQueueName = `wf-step-${toSafeKebab(step.functionId)}`;
589
738
  queues.push({
590
739
  name: stepQueueName,
591
- consumerUnit: toSafeKebab(step.functionId),
740
+ consumerUnit: unitFor(step.functionId),
592
741
  consumerFunctionId: `pikkuWorkflowWorker:${step.functionId}`,
593
742
  });
594
743
  }
@@ -731,32 +880,71 @@ function collectChannelFunctionIds(channelMeta) {
731
880
  // ---------------------------------------------------------------------------
732
881
  // Naming helpers
733
882
  // ---------------------------------------------------------------------------
734
- export function toSafeKebab(str) {
735
- return str
736
- .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
737
- .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
738
- .replace(/[:/\\]/g, '-')
739
- .replace(/--+/g, '-')
740
- .replace(/^-|-$/g, '')
741
- .toLowerCase();
742
- }
743
- function fromKebab(str) {
744
- return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
745
- }
883
+ export { toSafeKebab } from './naming.js';
746
884
  // ---------------------------------------------------------------------------
747
885
  // Tag helpers
748
886
  // ---------------------------------------------------------------------------
749
- function collectTags(funcIds, functionsMeta) {
887
+ function collectTags(funcIds, tagsFor) {
750
888
  const tags = new Set();
751
889
  for (const id of funcIds) {
752
- const meta = functionsMeta[id];
753
- if (meta?.tags) {
754
- for (const tag of meta.tags)
755
- tags.add(tag);
756
- }
890
+ for (const tag of tagsFor(id))
891
+ tags.add(tag);
757
892
  }
758
893
  return [...tags];
759
894
  }
895
+ /**
896
+ * Every tag that applies to a function, from the function itself and from every
897
+ * wiring that reaches it.
898
+ *
899
+ * Tags are almost always written on the wiring — `wireHTTP({ tags: ['todos'] })`
900
+ * — not on the `pikkuFunc`, so reading `FunctionMeta.tags` alone sees nothing in
901
+ * a typical project. `deploy.grouping` matches on the tags a user actually
902
+ * wrote, which means the union.
903
+ */
904
+ function buildFunctionTagIndex(state, functionsMeta) {
905
+ const index = new Map();
906
+ const add = (funcId, tags) => {
907
+ if (!funcId || !tags?.length)
908
+ return;
909
+ let set = index.get(funcId);
910
+ if (!set) {
911
+ set = new Set();
912
+ index.set(funcId, set);
913
+ }
914
+ for (const tag of tags)
915
+ set.add(tag);
916
+ };
917
+ for (const [funcId, meta] of entries(functionsMeta)) {
918
+ add(funcId, meta.tags);
919
+ }
920
+ for (const method of HTTP_METHODS) {
921
+ const methodRoutes = state.http?.meta?.[method];
922
+ if (!methodRoutes)
923
+ continue;
924
+ for (const routeMeta of values(methodRoutes)) {
925
+ add(routeMeta.pikkuFuncId, routeMeta.tags);
926
+ }
927
+ }
928
+ for (const meta of values(state.queueWorkers?.meta ?? {})) {
929
+ add(meta.pikkuFuncId, meta.tags);
930
+ }
931
+ for (const meta of values(state.scheduledTasks?.meta ?? {})) {
932
+ add(meta.pikkuFuncId, meta.tags);
933
+ }
934
+ for (const meta of [
935
+ ...values(state.mcpEndpoints?.toolsMeta ?? {}),
936
+ ...values(state.mcpEndpoints?.resourcesMeta ?? {}),
937
+ ...values(state.mcpEndpoints?.promptsMeta ?? {}),
938
+ ]) {
939
+ add(meta.pikkuFuncId, meta.tags);
940
+ }
941
+ for (const channelMeta of values(state.channels?.meta ?? {})) {
942
+ for (const funcId of collectChannelFunctionIds(channelMeta)) {
943
+ add(funcId, channelMeta.tags);
944
+ }
945
+ }
946
+ return new Map([...index].map(([funcId, tags]) => [funcId, [...tags]]));
947
+ }
760
948
  // ---------------------------------------------------------------------------
761
949
  // Typed iteration helpers
762
950
  // ---------------------------------------------------------------------------
@@ -0,0 +1,23 @@
1
+ export type GroupingStrategy = 'function' | 'single';
2
+ export interface GroupingRule {
3
+ unit: string;
4
+ tags?: string[];
5
+ addon?: string;
6
+ routes?: string[];
7
+ }
8
+ export interface GroupingConfig {
9
+ strategy?: GroupingStrategy;
10
+ rules?: GroupingRule[];
11
+ }
12
+ export interface UnitResolverInput {
13
+ routesForFunction: (funcId: string) => string[];
14
+ tagsForFunction: (funcId: string) => string[];
15
+ }
16
+ export interface UnitResolver {
17
+ forFunction: (funcId: string) => string;
18
+ forAddon: (namespace: string) => string;
19
+ isGrouped: boolean;
20
+ ruleForUnit: (unitName: string) => GroupingRule | undefined;
21
+ }
22
+ export declare const validateGrouping: (config: GroupingConfig) => void;
23
+ export declare const createUnitResolver: (config: GroupingConfig | undefined, input: UnitResolverInput) => UnitResolver;
@@ -0,0 +1,74 @@
1
+ import { toSafeKebab } from './naming.js';
2
+ const SINGLE_UNIT_NAME = 'app';
3
+ const routeMatcher = (pattern) => {
4
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
5
+ return new RegExp(`^${escaped.replace(/\*/g, '.*')}$`);
6
+ };
7
+ export const validateGrouping = (config) => {
8
+ const rules = config.rules ?? [];
9
+ const seen = new Set();
10
+ for (const rule of rules) {
11
+ if (!rule.unit) {
12
+ throw new Error(`deploy.grouping: every rule needs a "unit" name (offending rule: ${JSON.stringify(rule)})`);
13
+ }
14
+ if (seen.has(rule.unit)) {
15
+ throw new Error(`deploy.grouping: two rules both name the unit "${rule.unit}". Merge them into one rule.`);
16
+ }
17
+ seen.add(rule.unit);
18
+ if (!rule.tags?.length && !rule.addon && !rule.routes?.length) {
19
+ throw new Error(`deploy.grouping: rule "${rule.unit}" matches nothing. Give it at least one of "tags", "addon" or "routes".`);
20
+ }
21
+ }
22
+ };
23
+ export const createUnitResolver = (config, input) => {
24
+ const strategy = config?.strategy ?? 'function';
25
+ const rules = config?.rules ?? [];
26
+ if (config) {
27
+ validateGrouping(config);
28
+ }
29
+ const compiled = rules.map((rule) => ({
30
+ rule,
31
+ unit: toSafeKebab(rule.unit),
32
+ tags: rule.tags,
33
+ addon: rule.addon,
34
+ routes: rule.routes?.map(routeMatcher),
35
+ }));
36
+ const byUnitName = new Map(compiled.map((c) => [c.unit, c.rule]));
37
+ const matches = (c, tags, routes, addon) => {
38
+ if (c.tags && !c.tags.some((tag) => tags.includes(tag))) {
39
+ return false;
40
+ }
41
+ if (c.addon && c.addon !== addon) {
42
+ return false;
43
+ }
44
+ if (c.routes && !c.routes.some((re) => routes.some((r) => re.test(r)))) {
45
+ return false;
46
+ }
47
+ return true;
48
+ };
49
+ const fallback = (funcId) => strategy === 'single' ? SINGLE_UNIT_NAME : toSafeKebab(funcId);
50
+ return {
51
+ isGrouped: strategy !== 'function' || compiled.length > 0,
52
+ ruleForUnit: (unitName) => byUnitName.get(unitName),
53
+ forFunction: (funcId) => {
54
+ if (compiled.length > 0) {
55
+ const tags = input.tagsForFunction(funcId);
56
+ const routes = input.routesForFunction(funcId);
57
+ for (const c of compiled) {
58
+ if (matches(c, tags, routes, undefined)) {
59
+ return c.unit;
60
+ }
61
+ }
62
+ }
63
+ return fallback(funcId);
64
+ },
65
+ forAddon: (namespace) => {
66
+ for (const c of compiled) {
67
+ if (c.addon === namespace && !c.tags && !c.routes) {
68
+ return c.unit;
69
+ }
70
+ }
71
+ return `addon-${toSafeKebab(namespace)}`;
72
+ },
73
+ };
74
+ };
@@ -1,2 +1,3 @@
1
1
  export { analyzeDeployment } from './analyzer.js';
2
2
  export type { AnalyzerOptions } from './analyzer.js';
3
+ export type { GroupingConfig, GroupingRule, GroupingStrategy, } from './grouping.js';
@@ -0,0 +1 @@
1
+ export declare function toSafeKebab(str: string): string;
@@ -0,0 +1,9 @@
1
+ export function toSafeKebab(str) {
2
+ return str
3
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
4
+ .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
5
+ .replace(/[:/\\]/g, '-')
6
+ .replace(/--+/g, '-')
7
+ .replace(/^-|-$/g, '')
8
+ .toLowerCase();
9
+ }
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { InspectorState } from '@pikku/inspector';
8
8
  import { PikkuError } from '@pikku/core/errors';
9
+ import type { GroupingConfig } from './analyzer/index.js';
9
10
  import type { DeploymentManifest } from '@pikku/deploy';
10
11
  import type { Bundler } from './bundler/bundler.interface.js';
11
12
  import type { BundleResult } from './bundler/types.js';
@@ -50,6 +51,7 @@ export declare function runBuildPipeline(options: {
50
51
  inspectorState: InspectorState;
51
52
  serverlessIncompatible?: string[];
52
53
  defaultTarget?: 'serverless' | 'server';
54
+ grouping?: GroupingConfig;
53
55
  globalHTTPPrefix?: string;
54
56
  getEntryContext: (unitDir: string, pikkuDir: string, unit: DeploymentManifest['units'][0], state: InspectorState) => unknown;
55
57
  /**
@@ -153,6 +153,7 @@ export async function runBuildPipeline(options) {
153
153
  projectId,
154
154
  serverlessIncompatible: options.serverlessIncompatible,
155
155
  defaultTarget: options.defaultTarget,
156
+ grouping: options.grouping,
156
157
  globalHTTPPrefix: options.globalHTTPPrefix,
157
158
  workflowQueues,
158
159
  });
@@ -299,7 +300,26 @@ export async function runBuildPipeline(options) {
299
300
  unitPikkuDirs.set(k, v);
300
301
  codegenErrors.push(...serverCodegenErrors);
301
302
  // Replace individual server units with the merged one in the manifest
303
+ const mergedNames = new Set(serverUnits.map((u) => u.name));
302
304
  manifest.units = [...serverlessUnits, mergedServerUnit];
305
+ // Anything that named one of the units just folded away has to follow it,
306
+ // or the manifest ships a queue consumer and a cron pointing at a unit
307
+ // that no longer exists.
308
+ for (const queue of manifest.queues) {
309
+ if (mergedNames.has(queue.consumerUnit)) {
310
+ queue.consumerUnit = serverUnitName;
311
+ }
312
+ }
313
+ for (const task of manifest.scheduledTasks) {
314
+ if (mergedNames.has(task.unitName)) {
315
+ task.unitName = serverUnitName;
316
+ }
317
+ }
318
+ for (const unit of manifest.units) {
319
+ unit.dependsOn = [
320
+ ...new Set(unit.dependsOn.map((dep) => mergedNames.has(dep) ? serverUnitName : dep)),
321
+ ].filter((dep) => dep !== unit.name);
322
+ }
303
323
  logger.info(` Server container: ${serverUnits.length} functions merged into one unit`);
304
324
  }
305
325
  logger.info(`Codegen complete: ${unitPikkuDirs.size} units`);