@pikku/cli 0.12.124 → 0.12.126

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 (296) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/console-app/assets/{abnfDiagram-N423BO3Z-BP7zxMq6.js → abnfDiagram-N423BO3Z-B2suyn6i.js} +1 -1
  3. package/console-app/assets/architecture-TIHT7OUA-DmG0bXDT.js +1 -0
  4. package/console-app/assets/{architectureDiagram-T3A2C74G-mvqdkIfF.js → architectureDiagram-T3A2C74G-BQ5Dfvpo.js} +1 -1
  5. package/console-app/assets/{blockDiagram-VBNYF7ZC-daD8h3VT.js → blockDiagram-VBNYF7ZC-D4pVRDiF.js} +1 -1
  6. package/console-app/assets/{c4Diagram-5PPSVZJV-Bd0_wKJj.js → c4Diagram-5PPSVZJV-Da04jGpq.js} +1 -1
  7. package/console-app/assets/channel-BgCT5gon.js +1 -0
  8. package/console-app/assets/{chunk-2GRJ4B5K-BFRr_H2V.js → chunk-2GRJ4B5K-CwODIPP4.js} +1 -1
  9. package/console-app/assets/{chunk-4I5QYGJK-BXWo5Xyx.js → chunk-4I5QYGJK-Bep4akjR.js} +1 -1
  10. package/console-app/assets/{chunk-5RXB4S5H-BFnXfzzz.js → chunk-5RXB4S5H-CGyCRU9L.js} +1 -1
  11. package/console-app/assets/{chunk-6Q2QTUOP-Bswg4T3s.js → chunk-6Q2QTUOP-D0IK0SMT.js} +1 -1
  12. package/console-app/assets/{chunk-7Z6QIM7H-StNGH40U.js → chunk-7Z6QIM7H-D12vS1jX.js} +1 -1
  13. package/console-app/assets/{chunk-GF5L2VYU-QwXKtQxa.js → chunk-GF5L2VYU-kOLwTzIA.js} +1 -1
  14. package/console-app/assets/{chunk-I66GZJ75-DDQhhfA0.js → chunk-I66GZJ75-Cb2nDoa3.js} +1 -1
  15. package/console-app/assets/{chunk-JQJVKLGR-wFyF2bUv.js → chunk-JQJVKLGR-B3a_ctfQ.js} +1 -1
  16. package/console-app/assets/{chunk-KBJHAD2P-CQPQVDkD.js → chunk-KBJHAD2P-DeP2Lqwp.js} +1 -1
  17. package/console-app/assets/{chunk-NSK5VX7P-DZhjvnHm.js → chunk-NSK5VX7P-BO8vlGrO.js} +1 -1
  18. package/console-app/assets/{chunk-QR6OTTB3-D1-TbcCP.js → chunk-QR6OTTB3-sX5V0Lok.js} +1 -1
  19. package/console-app/assets/{chunk-RYQCIY6F-82OYF6U8.js → chunk-RYQCIY6F-DoCObEhk.js} +1 -1
  20. package/console-app/assets/{chunk-UBXNYLIW-D85x6Zh2.js → chunk-UBXNYLIW-BndMXU5r.js} +1 -1
  21. package/console-app/assets/{chunk-W5SLKNZC-B1Ps46_n.js → chunk-W5SLKNZC--VrZN8EC.js} +1 -1
  22. package/console-app/assets/{chunk-WRU74C26-Ct8XrToU.js → chunk-WRU74C26-DdS0mzXO.js} +1 -1
  23. package/console-app/assets/chunk-XXDRQBXY-EP2C9tTO.js +1 -0
  24. package/console-app/assets/classDiagram-JCYQIIEL-D9wGqB4J.js +1 -0
  25. package/console-app/assets/classDiagram-v2-OCEON4UE-D9wGqB4J.js +1 -0
  26. package/console-app/assets/{cose-bilkent-JH36ORCC-DdevwV5Y.js → cose-bilkent-JH36ORCC-C5EnHkFn.js} +1 -1
  27. package/console-app/assets/{cynefin-VYW2F7L2-Dj55csoo.js → cynefin-VYW2F7L2-9irdkTt4.js} +1 -1
  28. package/console-app/assets/{cynefinDiagram-MW4NZA55-XWSzdajo.js → cynefinDiagram-MW4NZA55-DY19660c.js} +1 -1
  29. package/console-app/assets/{dagre-VZM6K2ZE-BV2l3zSF.js → dagre-VZM6K2ZE-BYFZSaSb.js} +1 -1
  30. package/console-app/assets/{dagre-CLoXIMX5.js → dagre-nXgDYqvf.js} +1 -1
  31. package/console-app/assets/{diagram-7IWD3JNH-DC9NK-nv.js → diagram-7IWD3JNH-oDftiTp1.js} +1 -1
  32. package/console-app/assets/{diagram-B4RE2ZJO-Cirfb0aN.js → diagram-B4RE2ZJO-Cbj-pPbH.js} +1 -1
  33. package/console-app/assets/{diagram-LBJQPF4R-BuRRy5X5.js → diagram-LBJQPF4R-Ch53oSKw.js} +1 -1
  34. package/console-app/assets/{diagram-Q27KOJAE-CAOKQ2xs.js → diagram-Q27KOJAE-DA7K814v.js} +1 -1
  35. package/console-app/assets/{diagram-UB23O5K3-Bto5kBJo.js → diagram-UB23O5K3-B-_C-ctS.js} +1 -1
  36. package/console-app/assets/{ebnfDiagram-BXEA7PRR-C5OndYGC.js → ebnfDiagram-BXEA7PRR-DsOdsKXy.js} +1 -1
  37. package/console-app/assets/{erDiagram-JOGREHBK-DqU4xV4C.js → erDiagram-JOGREHBK-XB1mP5_A.js} +1 -1
  38. package/console-app/assets/eventmodeling-45OFAUF4-NKFCZ8Fj.js +1 -0
  39. package/console-app/assets/flowDiagram-UKHOOZJN-BpdPkmum.js +1 -0
  40. package/console-app/assets/{ganttDiagram-PKOTCBZU-D5_DE9R0.js → ganttDiagram-PKOTCBZU-knk0XSHi.js} +1 -1
  41. package/console-app/assets/{gitGraph-TEB2WS4Q-nuqfz7Fd.js → gitGraph-TEB2WS4Q-COJnK2tM.js} +1 -1
  42. package/console-app/assets/{gitGraphDiagram-DS77QQ5N-BtJwp2Y3.js → gitGraphDiagram-DS77QQ5N-sF0v605q.js} +1 -1
  43. package/console-app/assets/{index-DXcH2K9z.css → index-C8MC-uMB.css} +1 -1
  44. package/console-app/assets/{index-DRfts2XF.js → index-DMnbsgzs.js} +3 -3
  45. package/console-app/assets/{info-DKCQHKI2-CIfPVqHr.js → info-DKCQHKI2-Cbatr0w6.js} +1 -1
  46. package/console-app/assets/{infoDiagram-6WML65LV-B-gTHQad.js → infoDiagram-6WML65LV-93TFPCu2.js} +1 -1
  47. package/console-app/assets/{ishikawaDiagram-WSZJBQD7-CCwAWb1g.js → ishikawaDiagram-WSZJBQD7-BBR8_Qms.js} +1 -1
  48. package/console-app/assets/{journeyDiagram-NVQOT4AX-DhqNj_ci.js → journeyDiagram-NVQOT4AX-zG55yDoc.js} +1 -1
  49. package/console-app/assets/{kanban-definition-27J2QSJJ-DspZ1b3Y.js → kanban-definition-27J2QSJJ-DonGcEAY.js} +1 -1
  50. package/console-app/assets/{line-D7ZCpNkR.js → line-D1WdVm1S.js} +1 -1
  51. package/console-app/assets/{linear-B5jMy_q9.js → linear-D2GQL4Cm.js} +1 -1
  52. package/console-app/assets/{mermaid-parser.core-CMBFGJ0U.js → mermaid-parser.core-b4yKyO56.js} +3 -3
  53. package/console-app/assets/{mermaid.core-DYoDrSEJ.js → mermaid.core-Cwfec1gr.js} +4 -4
  54. package/console-app/assets/{mindmap-definition-FAOFIHXS-DsHwd2K9.js → mindmap-definition-FAOFIHXS-D0G4yKgw.js} +1 -1
  55. package/console-app/assets/{packet-7NZHBO7P-BSRRjf4H.js → packet-7NZHBO7P-DDa4HL2T.js} +1 -1
  56. package/console-app/assets/{pegDiagram-VL7TDLO6-Bi0OlzgS.js → pegDiagram-VL7TDLO6-fPdN5VZs.js} +1 -1
  57. package/console-app/assets/{pie-RZYD4A2V-D-8tgqYW.js → pie-RZYD4A2V-DRHURUqo.js} +1 -1
  58. package/console-app/assets/{pieDiagram-7S7Q4E2Y-CsYbVqaR.js → pieDiagram-7S7Q4E2Y-DMYn8ga_.js} +1 -1
  59. package/console-app/assets/{quadrantDiagram-CIZ2JOQS-LkLWrWKK.js → quadrantDiagram-CIZ2JOQS-C190OamC.js} +1 -1
  60. package/console-app/assets/{radar-I7S5WNFK-Bst62XZP.js → radar-I7S5WNFK-Djvqzz9A.js} +1 -1
  61. package/console-app/assets/{railroad-3IZDKUUU-zJswMQYF.js → railroad-3IZDKUUU-C9YvFeFq.js} +1 -1
  62. package/console-app/assets/railroad-abnf-AHOZXSZD-B3CYVW4p.js +1 -0
  63. package/console-app/assets/railroad-ebnf-EBAXGLYW-DrZ2yF62.js +1 -0
  64. package/console-app/assets/railroad-peg-LSFZ7HO6-CWAmMyxd.js +1 -0
  65. package/console-app/assets/{railroadDiagram-AXF67PYL-C0QZkg7m.js → railroadDiagram-AXF67PYL-IRFg1VrU.js} +1 -1
  66. package/console-app/assets/{requirementDiagram-LRYGKXZP-BQg0AbLI.js → requirementDiagram-LRYGKXZP-L-7ubbcT.js} +1 -1
  67. package/console-app/assets/{sankeyDiagram-W5VNT64P-CQb0BMMi.js → sankeyDiagram-W5VNT64P-DBttV6Gt.js} +1 -1
  68. package/console-app/assets/{sequenceDiagram-SI44F4Z6-BzgBi0a5.js → sequenceDiagram-SI44F4Z6-Bg15oKAB.js} +1 -1
  69. package/console-app/assets/{src-Dg-KiSsV.js → src-DUC7tLWb.js} +1 -1
  70. package/console-app/assets/{stateDiagram-OKZ733FA-BiqXn68g.js → stateDiagram-OKZ733FA-PWl0XGs5.js} +1 -1
  71. package/console-app/assets/stateDiagram-v2-UEYNNEHI-Celbgz4u.js +1 -0
  72. package/console-app/assets/{swimlanes-SLNWSIFB-Dy7wDP1q.js → swimlanes-SLNWSIFB-CyXEtGBV.js} +1 -1
  73. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-zxpNaB4U.js +8 -0
  74. package/console-app/assets/{timeline-definition-Z64GVDOM-DSWXli8X.js → timeline-definition-Z64GVDOM-BLA-DhBt.js} +1 -1
  75. package/console-app/assets/{treeView-QDETBFTQ-CeWwcs9r.js → treeView-QDETBFTQ-Bfnmn2UY.js} +1 -1
  76. package/console-app/assets/{treemap-6X3UGDF4-BfrumiJh.js → treemap-6X3UGDF4-DTA0wveO.js} +1 -1
  77. package/console-app/assets/{vennDiagram-T6HMQDX7-BsuldZ1n.js → vennDiagram-T6HMQDX7-CLXYZln0.js} +1 -1
  78. package/console-app/assets/{wardley-OPB4EBWU-oZldxS8z.js → wardley-OPB4EBWU-zwxqisG0.js} +1 -1
  79. package/console-app/assets/{wardleyDiagram-T6FBY63Y-C5LXyHMj.js → wardleyDiagram-T6FBY63Y-hKtKvNlv.js} +1 -1
  80. package/console-app/assets/{xychartDiagram-ELKLHX3M-CwhqhNkO.js → xychartDiagram-ELKLHX3M-BGf8p4bo.js} +1 -1
  81. package/console-app/index.html +2 -2
  82. package/dist/.pikku/addon/index.d.ts +1 -1
  83. package/dist/.pikku/addon/index.js +1 -1
  84. package/dist/.pikku/addon/pikku-addon-types.gen.d.ts +1 -1
  85. package/dist/.pikku/addon/pikku-addon-types.gen.js +1 -1
  86. package/dist/.pikku/agent/index.d.ts +1 -1
  87. package/dist/.pikku/agent/index.js +1 -1
  88. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  89. package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
  90. package/dist/.pikku/auth/index.d.ts +1 -1
  91. package/dist/.pikku/auth/index.js +1 -1
  92. package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
  93. package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
  94. package/dist/.pikku/channel/index.d.ts +1 -1
  95. package/dist/.pikku/channel/index.js +1 -1
  96. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  97. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  98. package/dist/.pikku/cli/index.d.ts +1 -1
  99. package/dist/.pikku/cli/index.js +1 -1
  100. package/dist/.pikku/cli/pikku-cli-channel.js +11 -1
  101. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  102. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  103. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  104. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  105. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +7 -0
  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-meta.gen.json +27 -0
  110. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  111. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  112. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  113. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  114. package/dist/.pikku/error/index.d.ts +1 -1
  115. package/dist/.pikku/error/index.js +1 -1
  116. package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
  117. package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
  118. package/dist/.pikku/function/index.d.ts +1 -1
  119. package/dist/.pikku/function/index.js +1 -1
  120. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  121. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  122. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  123. package/dist/.pikku/function/pikku-functions-meta.gen.json +59 -23
  124. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  125. package/dist/.pikku/gateway/index.d.ts +1 -1
  126. package/dist/.pikku/gateway/index.js +1 -1
  127. package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
  128. package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
  129. package/dist/.pikku/http/index.d.ts +1 -1
  130. package/dist/.pikku/http/index.js +1 -1
  131. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  132. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  133. package/dist/.pikku/mcp/index.d.ts +1 -1
  134. package/dist/.pikku/mcp/index.js +1 -1
  135. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  136. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  137. package/dist/.pikku/middleware/index.d.ts +1 -1
  138. package/dist/.pikku/middleware/index.js +1 -1
  139. package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
  140. package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
  141. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  142. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  143. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  144. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  145. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  146. package/dist/.pikku/queue/index.d.ts +1 -1
  147. package/dist/.pikku/queue/index.js +1 -1
  148. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  149. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  150. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  151. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  152. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  153. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  154. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +2 -0
  155. package/dist/.pikku/scenarios/index.d.ts +1 -1
  156. package/dist/.pikku/scenarios/index.js +1 -1
  157. package/dist/.pikku/scenarios/pikku-personas.gen.js +1 -1
  158. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  159. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  160. package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
  161. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  162. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  163. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  164. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  165. package/dist/.pikku/scheduler/index.d.ts +1 -1
  166. package/dist/.pikku/scheduler/index.js +1 -1
  167. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  168. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  169. package/dist/.pikku/schemas/register.gen.js +7 -1
  170. package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -1
  171. package/dist/.pikku/schemas/schemas/FabricProjectsListInput.schema.json +1 -0
  172. package/dist/.pikku/schemas/schemas/FabricProjectsListOutput.schema.json +1 -0
  173. package/dist/.pikku/schemas/schemas/FabricSecretsListInput.schema.json +1 -1
  174. package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -1
  175. package/dist/.pikku/schemas/schemas/FabricSecretsSetInput.schema.json +1 -1
  176. package/dist/.pikku/schemas/schemas/FabricVariablesGetInput.schema.json +1 -1
  177. package/dist/.pikku/schemas/schemas/FabricVariablesSetInput.schema.json +1 -1
  178. package/dist/.pikku/schemas/schemas/PersonaSecretInput.schema.json +1 -0
  179. package/dist/.pikku/scopes/index.d.ts +1 -1
  180. package/dist/.pikku/scopes/index.js +1 -1
  181. package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
  182. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
  183. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  184. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  185. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  186. package/dist/.pikku/secrets/index.d.ts +1 -1
  187. package/dist/.pikku/secrets/index.js +1 -1
  188. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  189. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  190. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  191. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  192. package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
  193. package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
  194. package/dist/.pikku/setup/index.d.ts +1 -1
  195. package/dist/.pikku/setup/index.js +1 -1
  196. package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
  197. package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
  198. package/dist/.pikku/trigger/index.d.ts +1 -1
  199. package/dist/.pikku/trigger/index.js +1 -1
  200. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  201. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  202. package/dist/.pikku/variables/index.d.ts +1 -1
  203. package/dist/.pikku/variables/index.js +1 -1
  204. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  205. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  206. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  207. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  208. package/dist/.pikku/workflow/index.d.ts +1 -1
  209. package/dist/.pikku/workflow/index.js +1 -1
  210. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  211. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  212. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  213. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  214. package/dist/bin/pikku-bin.mjs +2 -2
  215. package/dist/src/cli.wiring.js +13 -1
  216. package/dist/src/deploy/build-pipeline.d.ts +10 -0
  217. package/dist/src/deploy/build-pipeline.js +16 -1
  218. package/dist/src/deploy/bundler/bun-bundler.js +12 -5
  219. package/dist/src/deploy/frontend-assets.d.ts +50 -0
  220. package/dist/src/deploy/frontend-assets.js +82 -0
  221. package/dist/src/fabric/fabric-commands.d.ts +55 -15
  222. package/dist/src/fabric/fabric-commands.js +6 -0
  223. package/dist/src/fabric/functions/deploy.function.js +12 -2
  224. package/dist/src/fabric/functions/projects-list.function.d.ts +72 -0
  225. package/dist/src/fabric/functions/projects-list.function.js +63 -0
  226. package/dist/src/fabric/functions/secrets-list.function.d.ts +4 -4
  227. package/dist/src/fabric/functions/secrets-list.function.js +4 -4
  228. package/dist/src/fabric/functions/secrets-rotate.function.d.ts +4 -4
  229. package/dist/src/fabric/functions/secrets-rotate.function.js +8 -5
  230. package/dist/src/fabric/functions/secrets-set.function.d.ts +4 -4
  231. package/dist/src/fabric/functions/secrets-set.function.js +4 -4
  232. package/dist/src/fabric/functions/validate.function.js +49 -24
  233. package/dist/src/fabric/functions/variables-get.function.d.ts +4 -4
  234. package/dist/src/fabric/functions/variables-get.function.js +4 -4
  235. package/dist/src/fabric/functions/variables-set.function.d.ts +4 -4
  236. package/dist/src/fabric/functions/variables-set.function.js +4 -4
  237. package/dist/src/fabric/lib/blank-comments.d.ts +21 -0
  238. package/dist/src/fabric/lib/blank-comments.js +71 -0
  239. package/dist/src/fabric/lib/blank-scenario-meta.d.ts +1 -0
  240. package/dist/src/fabric/lib/blank-scenario-meta.js +110 -0
  241. package/dist/src/fabric/lib/deployment.d.ts +26 -0
  242. package/dist/src/fabric/lib/deployment.js +35 -0
  243. package/dist/src/fabric/lib/stage.d.ts +19 -3
  244. package/dist/src/fabric/lib/stage.js +29 -6
  245. package/dist/src/functions/commands/db-reset.js +6 -2
  246. package/dist/src/functions/commands/deploy-apply.d.ts +10 -0
  247. package/dist/src/functions/commands/deploy-apply.js +8 -0
  248. package/dist/src/functions/commands/deploy-plan.js +1 -0
  249. package/dist/src/functions/commands/dev.js +18 -3
  250. package/dist/src/functions/commands/environment.d.ts +10 -0
  251. package/dist/src/functions/commands/environment.js +24 -0
  252. package/dist/src/functions/commands/persona.d.ts +18 -0
  253. package/dist/src/functions/commands/persona.js +41 -2
  254. package/dist/src/functions/commands/scenario-browser.d.ts +13 -5
  255. package/dist/src/functions/commands/serve-frontend.d.ts +11 -0
  256. package/dist/src/functions/commands/serve-frontend.js +17 -0
  257. package/dist/src/functions/commands/serve.js +16 -3
  258. package/dist/src/functions/db/annotation-parser.d.ts +8 -0
  259. package/dist/src/functions/db/annotation-parser.js +2 -0
  260. package/dist/src/functions/db/check-enums.d.ts +38 -0
  261. package/dist/src/functions/db/check-enums.js +103 -0
  262. package/dist/src/functions/db/db-codegen.js +35 -1
  263. package/dist/src/functions/db/postgres/postgres-introspector.d.ts +14 -0
  264. package/dist/src/functions/db/postgres/postgres-introspector.js +48 -0
  265. package/dist/src/functions/db/sqlite/sqlite-introspector.d.ts +3 -4
  266. package/dist/src/functions/db/sqlite/sqlite-introspector.js +5 -17
  267. package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.d.ts +9 -6
  268. package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.js +57 -30
  269. package/dist/src/server/actor-sign-in.d.ts +24 -1
  270. package/dist/src/server/actor-sign-in.js +45 -2
  271. package/dist/src/server/dev-server-runner.interface.d.ts +9 -0
  272. package/dist/src/server/node-server-runner.js +3 -0
  273. package/dist/src/server/server-ready.d.ts +6 -9
  274. package/dist/src/server/server-ready.js +6 -9
  275. package/dist/src/utils/frontend.d.ts +9 -0
  276. package/dist/src/utils/frontend.js +18 -0
  277. package/dist/src/utils/persona-credentials.d.ts +23 -2
  278. package/dist/src/utils/persona-credentials.js +55 -2
  279. package/dist/src/utils/pikku-cli-config.d.ts +14 -5
  280. package/dist/src/utils/pikku-cli-config.js +57 -10
  281. package/dist/tsconfig.tsbuildinfo +1 -1
  282. package/package.json +12 -12
  283. package/snippets.json +2 -2
  284. package/surface.json +101 -51
  285. package/console-app/assets/architecture-TIHT7OUA-D4Hj6824.js +0 -1
  286. package/console-app/assets/channel-09aKDzM0.js +0 -1
  287. package/console-app/assets/chunk-XXDRQBXY-C1KaR4pt.js +0 -1
  288. package/console-app/assets/classDiagram-JCYQIIEL-23nagJMi.js +0 -1
  289. package/console-app/assets/classDiagram-v2-OCEON4UE-23nagJMi.js +0 -1
  290. package/console-app/assets/eventmodeling-45OFAUF4-RyG54ZHy.js +0 -1
  291. package/console-app/assets/flowDiagram-UKHOOZJN-DNdfrnRg.js +0 -1
  292. package/console-app/assets/railroad-abnf-AHOZXSZD-DX4FqVY6.js +0 -1
  293. package/console-app/assets/railroad-ebnf-EBAXGLYW-DdyOtX1l.js +0 -1
  294. package/console-app/assets/railroad-peg-LSFZ7HO6-CclC1sXF.js +0 -1
  295. package/console-app/assets/stateDiagram-v2-UEYNNEHI-I34jrzP0.js +0 -1
  296. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-C1PrPB0G.js +0 -8
@@ -1,5 +1,6 @@
1
1
  import { Pool } from 'pg';
2
2
  import { MIGRATION_TRACKING_TABLE } from '../db-migrator.js';
3
+ import { parseCheckEnumValues } from '../check-enums.js';
3
4
  /** Table display name matching `listTables` (schema-qualified unless `public`). */
4
5
  function tableKey(schema, table) {
5
6
  return schema === 'public' ? table : `${schema}.${table}`;
@@ -85,6 +86,8 @@ export class PostgresIntrospector {
85
86
  FROM information_schema.columns c
86
87
  WHERE c.table_schema = $2 AND c.table_name = $1
87
88
  ORDER BY c.ordinal_position`, [tableName, schema]);
89
+ const checkEnums = (await this.getCheckEnums({ schema, name: tableName })).get(table) ??
90
+ new Map();
88
91
  return result.rows.map((r) => ({
89
92
  name: r.column_name,
90
93
  type: resolveColumnType(r.data_type, r.udt_name),
@@ -93,8 +96,51 @@ export class PostgresIntrospector {
93
96
  pk: Boolean(r.is_pk),
94
97
  defaultValue: r.column_default,
95
98
  generated: r.is_generated === 'ALWAYS',
99
+ enumValues: checkEnums.get(r.column_name),
96
100
  }));
97
101
  }
102
+ /**
103
+ * Columns constrained to a value list by a `CHECK (col IN (…))`, keyed like
104
+ * {@link getAllColumns} then by column name. Postgres has native enums, but
105
+ * a CHECK is the other half of how a schema says "one of these" — and the
106
+ * one an app written against SQLite as well ends up using, since SQLite has
107
+ * no enums at all. Left as plain `string`, every caller narrows it by hand.
108
+ *
109
+ * Only single-column constraints are read: `conkey` naming two columns means
110
+ * neither is restricted to the list on its own.
111
+ *
112
+ * `table` limits the sweep to one table; omitted, it covers the schema. Both
113
+ * are one round-trip — see {@link getAllColumns}.
114
+ */
115
+ async getCheckEnums(table) {
116
+ const result = await this.client.query(`SELECT n.nspname AS table_schema,
117
+ cl.relname AS table_name,
118
+ a.attname AS column_name,
119
+ pg_get_constraintdef(co.oid) AS def
120
+ FROM pg_constraint co
121
+ JOIN pg_class cl ON cl.oid = co.conrelid
122
+ JOIN pg_namespace n ON n.oid = cl.relnamespace
123
+ JOIN pg_attribute a ON a.attrelid = co.conrelid AND a.attnum = co.conkey[1]
124
+ WHERE co.contype = 'c'
125
+ AND array_length(co.conkey, 1) = 1
126
+ AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
127
+ AND n.nspname NOT LIKE 'pg_temp_%'
128
+ AND ($1::text IS NULL OR (n.nspname = $1 AND cl.relname = $2))`, [table?.schema ?? null, table?.name ?? null]);
129
+ const byTable = new Map();
130
+ for (const r of result.rows) {
131
+ const values = parseCheckEnumValues(r.def);
132
+ if (!values)
133
+ continue;
134
+ const key = tableKey(r.table_schema, r.table_name);
135
+ let cols = byTable.get(key);
136
+ if (!cols) {
137
+ cols = new Map();
138
+ byTable.set(key, cols);
139
+ }
140
+ cols.set(r.column_name, values);
141
+ }
142
+ return byTable;
143
+ }
98
144
  async getForeignKeys(table) {
99
145
  const dotIdx = table.indexOf('.');
100
146
  const schema = dotIdx >= 0 ? table.slice(0, dotIdx) : 'public';
@@ -153,6 +199,7 @@ export class PostgresIntrospector {
153
199
  WHERE c.table_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
154
200
  AND c.table_schema NOT LIKE 'pg_temp_%'
155
201
  ORDER BY c.table_schema, c.table_name, c.ordinal_position`);
202
+ const checkEnums = await this.getCheckEnums();
156
203
  const byTable = new Map();
157
204
  for (const r of result.rows) {
158
205
  if (isMigrationTracking(r.table_name))
@@ -171,6 +218,7 @@ export class PostgresIntrospector {
171
218
  pk: Boolean(r.is_pk),
172
219
  defaultValue: r.column_default,
173
220
  generated: r.is_generated === 'ALWAYS',
221
+ enumValues: checkEnums.get(key)?.get(r.column_name),
174
222
  });
175
223
  }
176
224
  return byTable;
@@ -7,10 +7,9 @@ export declare class SqliteIntrospector implements DbIntrospector {
7
7
  getColumns(table: string): Promise<ColumnInfo[]>;
8
8
  /**
9
9
  * SQLite has no native enums, but a `CHECK (col IN ('a','b',…))` constraint is
10
- * an enum by another name. Parse the table's stored `CREATE TABLE` DDL and map
11
- * each constrained column to its allowed values so codegen can type it as a
12
- * union. Only the positive `col IN (…)` form is recognised (the convention);
13
- * `NOT IN`, ranges, and boolean expressions are left as plain `string`.
10
+ * an enum by another name. Read back the table's stored `CREATE TABLE` DDL —
11
+ * which SQLite keeps verbatim, comments included — and map each constrained
12
+ * column to its allowed values so codegen can type it as a union.
14
13
  */
15
14
  private parseCheckEnums;
16
15
  getForeignKeys(table: string): Promise<ForeignKeyInfo[]>;
@@ -1,4 +1,5 @@
1
1
  import { MIGRATION_TRACKING_TABLE } from '../db-migrator.js';
2
+ import { parseCheckEnumsFromDdl } from '../check-enums.js';
2
3
  const SKIP_TABLES = new Set(['sqlite_sequence', MIGRATION_TRACKING_TABLE]);
3
4
  export class SqliteIntrospector {
4
5
  db;
@@ -34,28 +35,15 @@ export class SqliteIntrospector {
34
35
  }
35
36
  /**
36
37
  * SQLite has no native enums, but a `CHECK (col IN ('a','b',…))` constraint is
37
- * an enum by another name. Parse the table's stored `CREATE TABLE` DDL and map
38
- * each constrained column to its allowed values so codegen can type it as a
39
- * union. Only the positive `col IN (…)` form is recognised (the convention);
40
- * `NOT IN`, ranges, and boolean expressions are left as plain `string`.
38
+ * an enum by another name. Read back the table's stored `CREATE TABLE` DDL —
39
+ * which SQLite keeps verbatim, comments included — and map each constrained
40
+ * column to its allowed values so codegen can type it as a union.
41
41
  */
42
42
  parseCheckEnums(table) {
43
- const out = new Map();
44
43
  const row = this.db
45
44
  .prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`)
46
45
  .get(table);
47
- const ddl = row?.sql;
48
- if (!ddl)
49
- return out;
50
- const checkIn = /CHECK\s*\(\s*"?(\w+)"?\s+IN\s*\(([^)]*)\)/gi;
51
- let m;
52
- while ((m = checkIn.exec(ddl))) {
53
- const column = m[1];
54
- const values = [...m[2].matchAll(/'((?:[^']|'')*)'/g)].map((q) => q[1].replace(/''/g, "'"));
55
- if (values.length > 0)
56
- out.set(column, values);
57
- }
58
- return out;
46
+ return row?.sql ? parseCheckEnumsFromDdl(row.sql) : new Map();
59
47
  }
60
48
  async getForeignKeys(table) {
61
49
  const escaped = `"${table.replace(/"/g, '""')}"`;
@@ -12,12 +12,15 @@ export interface VirtualUserGenOutput {
12
12
  * `pikku persona run` does the same thing from a terminal; this is the same run
13
13
  * started over RPC, from CI or from a console, with the result kept.
14
14
  *
15
- * A virtual user is NOT a workflow and NOT a queued job. It explores, so no two
16
- * attempts take the same steps and there is nothing to replay; and the run
17
- * record already carries the progress a queue would only be holding on the way
18
- * here. So `runVirtualUser` writes the record, kicks the run off without
19
- * awaiting it, and returns the id. The one cost is stated on the record: a
20
- * restart mid-run strands it at `running`.
15
+ * A virtual user is still NOT a workflow: it explores, so no two attempts take
16
+ * the same steps and there is nothing to replay. What it does need is a
17
+ * trigger. `runVirtualUser` writes the record and returns the id; the run
18
+ * itself is dispatched onto `pikku-virtual-user-runs`, at one attempt, because
19
+ * a queue is the only dispatch that survives a deployment which puts each
20
+ * function in its own unit — there is no in-process promise to leave running
21
+ * there, and an RPC to a function nothing triggers has nowhere to land. A
22
+ * project with no queue service keeps the in-process dispatch, which is
23
+ * correct for the single process it runs in.
21
24
  *
22
25
  * Emitted as two files. The schemas are zod, and the inspector reads a zod
23
26
  * schema by importing the module that declares it — which it cannot do for the
@@ -8,12 +8,15 @@
8
8
  * `pikku persona run` does the same thing from a terminal; this is the same run
9
9
  * started over RPC, from CI or from a console, with the result kept.
10
10
  *
11
- * A virtual user is NOT a workflow and NOT a queued job. It explores, so no two
12
- * attempts take the same steps and there is nothing to replay; and the run
13
- * record already carries the progress a queue would only be holding on the way
14
- * here. So `runVirtualUser` writes the record, kicks the run off without
15
- * awaiting it, and returns the id. The one cost is stated on the record: a
16
- * restart mid-run strands it at `running`.
11
+ * A virtual user is still NOT a workflow: it explores, so no two attempts take
12
+ * the same steps and there is nothing to replay. What it does need is a
13
+ * trigger. `runVirtualUser` writes the record and returns the id; the run
14
+ * itself is dispatched onto `pikku-virtual-user-runs`, at one attempt, because
15
+ * a queue is the only dispatch that survives a deployment which puts each
16
+ * function in its own unit — there is no in-process promise to leave running
17
+ * there, and an RPC to a function nothing triggers has nowhere to land. A
18
+ * project with no queue service keeps the in-process dispatch, which is
19
+ * correct for the single process it runs in.
17
20
  *
18
21
  * Emitted as two files. The schemas are zod, and the inspector reads a zod
19
22
  * schema by importing the module that declares it — which it cannot do for the
@@ -265,6 +268,7 @@ export const ExecuteVirtualUserRunOutput = z.object({
265
268
  */
266
269
  import { pikkuFunc, pikkuSessionlessFunc, type Session } from '${leaf('function')}'
267
270
  import { pikkuMiddleware } from '${leaf('middleware')}'
271
+ import { wireQueueWorker } from '${leaf('queue')}'
268
272
  import { defineScope } from '${leaf('scopes')}'
269
273
  import {
270
274
  executeVirtualUserRun as executeRun,
@@ -278,7 +282,7 @@ import {
278
282
  virtualUserScheduleRunInput,
279
283
  writeVirtualUserSchedule,
280
284
  } from '@pikku/core/virtual-user'
281
- import { createPersonas, personaConfigs } from '${pathToPersonas}'
285
+ import { createPersonas, personaConfigs, personaEnvironments } from '${pathToPersonas}'
282
286
  import {
283
287
  ExecuteVirtualUserRunInput,
284
288
  ExecuteVirtualUserRunOutput,
@@ -326,13 +330,20 @@ export const runVirtualUser = pikkuFunc({
326
330
  scopes: ['virtualUser:run'],
327
331
  input: RunVirtualUserInput,
328
332
  output: RunVirtualUserOutput,
329
- func: async ({ virtualUserRunStore, config }, input, { session, rpc }) => {
333
+ func: async (
334
+ { virtualUserRunStore, config, queueService },
335
+ input,
336
+ { session, rpc }
337
+ ) => {
330
338
  const { runId, persona, disposition, goals, memory, seed } =
331
339
  await startVirtualUserRun({
332
340
  store: virtualUserRunStore,
333
341
  personas: personaConfigs,
334
- // Cast because an application's Config is its own interface and need
335
- // not declare nodeEnv at all.
342
+ // Which of the configured environments this process is decides whether
343
+ // a run is against production. \`config\` is only the fallback for a
344
+ // project that configures none, and is cast because an application's
345
+ // Config is its own interface and need not declare nodeEnv at all.
346
+ environments: personaEnvironments,
336
347
  config: config as { nodeEnv?: string } | undefined,
337
348
  persona: input.persona,
338
349
  disposition: input.disposition,
@@ -342,26 +353,35 @@ export const runVirtualUser = pikkuFunc({
342
353
  startedBy: session?.userId ?? null,
343
354
  })
344
355
 
345
- // Deliberately not awaited: a run takes minutes, and a held-open request
346
- // survives neither a rollout nor a proxy timeout. executeVirtualUserRun
347
- // writes both outcomes to the record itself, so the only thing left to
348
- // handle here is a rejection escaping the promise — without the catch it
349
- // becomes an unhandled rejection and takes the process with it.
350
- void rpc!
351
- .invoke('executeVirtualUserRun', {
352
- runId,
353
- persona,
354
- disposition,
355
- goals,
356
- memory,
357
- seed,
358
- budget: input.budget,
359
- // Rides the dispatch and nothing else. The run record is deliberately
360
- // not given it: a record outlives the run, and a credential in a row
361
- // somebody can read back is a credential leak.
362
- operatorToken: input.operatorToken,
356
+ const job = {
357
+ runId,
358
+ persona,
359
+ disposition,
360
+ goals,
361
+ memory,
362
+ seed,
363
+ budget: input.budget,
364
+ // Rides the dispatch and nothing else. The run record is deliberately
365
+ // not given it: a record outlives the run, and a credential in a row
366
+ // somebody can read back is a credential leak.
367
+ operatorToken: input.operatorToken,
368
+ }
369
+
370
+ if (queueService) {
371
+ // One attempt. A run is an exploration, so a redelivery is a second
372
+ // different outing writing into a record that already has an outcome.
373
+ await queueService.add('pikku-virtual-user-runs', job, {
374
+ attempts: 1,
375
+ pikkuUserId: session?.userId,
363
376
  })
364
- .catch(() => {})
377
+ } else {
378
+ // Deliberately not awaited: a run takes minutes, and a held-open request
379
+ // survives neither a rollout nor a proxy timeout. executeVirtualUserRun
380
+ // writes both outcomes to the record itself, so the only thing left to
381
+ // handle here is a rejection escaping the promise — without the catch it
382
+ // becomes an unhandled rejection and takes the process with it.
383
+ void rpc!.invoke('executeVirtualUserRun', job).catch(() => {})
384
+ }
365
385
 
366
386
  return { runId }
367
387
  },
@@ -557,7 +577,8 @@ export const tickVirtualUserSchedules = pikkuSessionlessFunc<void, void>({
557
577
 
558
578
  /**
559
579
  * The run itself. Not exposed: it is dispatched by \`runVirtualUser\` and has no
560
- * caller of its own.
580
+ * caller of its own — but it is wired to a queue below, which is what gives it
581
+ * a unit of its own under a per-function deploy.
561
582
  */
562
583
  export const executeVirtualUserRun = pikkuSessionlessFunc({
563
584
  tags: ['pikku'],
@@ -578,6 +599,12 @@ export const executeVirtualUserRun = pikkuSessionlessFunc({
578
599
  ...input,
579
600
  }),
580
601
  })
602
+
603
+ wireQueueWorker({
604
+ name: 'pikku-virtual-user-runs',
605
+ tags: ['pikku'],
606
+ func: executeVirtualUserRun,
607
+ })
581
608
  `;
582
609
  return { schemas, functions };
583
610
  };
@@ -1,5 +1,28 @@
1
1
  import type { Logger } from '@pikku/core/services';
2
2
  export declare const ACTOR_SECRET_ENV = "SCENARIO_ACTOR_SECRET";
3
+ /**
4
+ * Read as an alias for the root when a project set only this one, and then
5
+ * cleared: the root derives every persona's credential, so a bundle holding it
6
+ * holds all of them. What the browser switcher gets instead is
7
+ * {@link DEV_ACTOR_SECRETS_ENV}.
8
+ */
3
9
  export declare const VITE_ACTOR_SECRET_ENV = "VITE_SCENARIO_ACTOR_SECRET";
4
- export declare const enableDevActorSignIn: (logger: Logger) => void;
10
+ /**
11
+ * The dev switcher's credentials, `{ email: secret }` as JSON — one capability
12
+ * per declared persona, each refused for any other address.
13
+ */
14
+ export declare const DEV_ACTOR_SECRETS_ENV = "VITE_DEV_ACTOR_SECRETS";
15
+ /** Just enough of a persona to mint their credential. */
16
+ export interface DevActorIdentity {
17
+ id: string;
18
+ email: string;
19
+ }
20
+ /**
21
+ * Turn on passwordless actor sign-in for this `pikku dev` run and hand the
22
+ * frontend switcher one credential per declared persona.
23
+ *
24
+ * `personas` is a thunk because resolving them means reading inspector state,
25
+ * which is not worth doing for a project that declares none.
26
+ */
27
+ export declare const enableDevActorSignIn: (logger: Logger, personas?: () => Promise<DevActorIdentity[]>) => Promise<void>;
5
28
  export declare const disableDevActorSignIn: (logger: Logger) => void;
@@ -1,9 +1,28 @@
1
1
  import { randomBytes } from 'node:crypto';
2
2
  import { ACTOR_SIGN_IN_OPT_IN_ENV, DEV_ACTOR_SIGN_IN_ENV, } from '@pikku/better-auth';
3
+ import { ACTOR_ROOT_SECRET_MIN_LENGTH, deriveActorSecret, } from '@pikku/core/services';
3
4
  export const ACTOR_SECRET_ENV = 'SCENARIO_ACTOR_SECRET';
5
+ /**
6
+ * Read as an alias for the root when a project set only this one, and then
7
+ * cleared: the root derives every persona's credential, so a bundle holding it
8
+ * holds all of them. What the browser switcher gets instead is
9
+ * {@link DEV_ACTOR_SECRETS_ENV}.
10
+ */
4
11
  export const VITE_ACTOR_SECRET_ENV = 'VITE_SCENARIO_ACTOR_SECRET';
12
+ /**
13
+ * The dev switcher's credentials, `{ email: secret }` as JSON — one capability
14
+ * per declared persona, each refused for any other address.
15
+ */
16
+ export const DEV_ACTOR_SECRETS_ENV = 'VITE_DEV_ACTOR_SECRETS';
5
17
  const mintEphemeralSecret = () => randomBytes(32).toString('base64url');
6
- export const enableDevActorSignIn = (logger) => {
18
+ /**
19
+ * Turn on passwordless actor sign-in for this `pikku dev` run and hand the
20
+ * frontend switcher one credential per declared persona.
21
+ *
22
+ * `personas` is a thunk because resolving them means reading inspector state,
23
+ * which is not worth doing for a project that declares none.
24
+ */
25
+ export const enableDevActorSignIn = async (logger, personas) => {
7
26
  process.env[DEV_ACTOR_SIGN_IN_ENV] = 'true';
8
27
  const configured = process.env[ACTOR_SECRET_ENV] || undefined;
9
28
  const configuredForFrontend = process.env[VITE_ACTOR_SECRET_ENV] || undefined;
@@ -14,10 +33,34 @@ export const enableDevActorSignIn = (logger) => {
14
33
  }
15
34
  const secret = configured ?? configuredForFrontend ?? mintEphemeralSecret();
16
35
  process.env[ACTOR_SECRET_ENV] = secret;
17
- process.env[VITE_ACTOR_SECRET_ENV] = secret;
36
+ delete process.env[VITE_ACTOR_SECRET_ENV];
18
37
  logger.info((configured ?? configuredForFrontend)
19
38
  ? `Actor quick login enabled, using the ${configured ? ACTOR_SECRET_ENV : VITE_ACTOR_SECRET_ENV} already in this environment`
20
39
  : 'Actor quick login enabled with a secret minted for this run — nothing to configure, and it is gone when the server stops');
40
+ if (secret.length < ACTOR_ROOT_SECRET_MIN_LENGTH) {
41
+ logger.warn(`${ACTOR_SECRET_ENV} is shorter than ${ACTOR_ROOT_SECRET_MIN_LENGTH} characters, so no persona credential can be derived from it and every actor sign-in will be refused. ` +
42
+ `Generate one with \`openssl rand -base64 32\`, or unset it and let this run mint its own.`);
43
+ return;
44
+ }
45
+ if (!personas) {
46
+ return;
47
+ }
48
+ try {
49
+ const declared = await personas();
50
+ if (declared.length === 0) {
51
+ return;
52
+ }
53
+ const credentials = {};
54
+ for (const persona of declared) {
55
+ credentials[persona.email] = await deriveActorSecret(secret, persona.email);
56
+ }
57
+ process.env[DEV_ACTOR_SECRETS_ENV] = JSON.stringify(credentials);
58
+ logger.info(`Minted ${declared.length} persona credential${declared.length === 1 ? '' : 's'} for the dev switcher — the root stays on the server`);
59
+ }
60
+ catch (cause) {
61
+ logger.warn(`Could not mint persona credentials for the dev switcher: ${cause instanceof Error ? cause.message : String(cause)}. ` +
62
+ `The switcher will render nothing; scenario runs are unaffected.`);
63
+ }
21
64
  };
22
65
  export const disableDevActorSignIn = (logger) => {
23
66
  if (process.env[DEV_ACTOR_SIGN_IN_ENV] !== undefined) {
@@ -16,6 +16,15 @@ export interface DevServerInstance {
16
16
  start(): Promise<void>;
17
17
  /** Full teardown — closes the server and any owned WebSocket server. */
18
18
  stop(): Promise<void>;
19
+ /**
20
+ * The port the server actually bound, readable once `start()` has resolved.
21
+ *
22
+ * Diverges from the requested port whenever that was `0`, which is the only
23
+ * race-free way for a parent process to hand the server a port: anything the
24
+ * parent picks can be taken between its check and the server's bind. The
25
+ * ready line is built from this, so a parent learns the port by reading it.
26
+ */
27
+ readonly port: number;
19
28
  }
20
29
  /** Config shape both runtimes accept (Core config + host/port/content). */
21
30
  export type DevServerConfig = NodeHTTPServerConfig;
@@ -51,6 +51,9 @@ export class NodeServerRunner {
51
51
  return {
52
52
  init: () => server.init(),
53
53
  start: () => server.start(),
54
+ get port() {
55
+ return server.port;
56
+ },
54
57
  stop: async () => {
55
58
  if (wss) {
56
59
  await new Promise((resolve, reject) => wss.close((err) => (err ? reject(err) : resolve())));
@@ -1,12 +1,9 @@
1
1
  /**
2
- * Printed once the server is listening AND the project's `afterStart`
3
- * lifecycle has resolved.
2
+ * The readiness handshake, owned by `@pikku/deploy` so the CLI and the
3
+ * standalone provider's generated server entry print and wait on the same
4
+ * string. Re-exported here because `--spawn` and the dev/serve commands have
5
+ * always imported it from this path.
4
6
  *
5
- * The runtime's own `listening on …` line is emitted inside `server.start()`,
6
- * which runs *before* `afterStart` — so anything a project seeds there (users,
7
- * scopes, fixtures) is still pending when it appears, and a parent process
8
- * that treats it as readiness races the seed. This marker is the point at
9
- * which the server is actually usable, and it is what `--spawn` waits for.
7
+ * @see {@link SERVER_READY_MARKER} for why `listening on …` is not readiness.
10
8
  */
11
- export declare const SERVER_READY_MARKER = "pikku: ready";
12
- export declare const serverReadyLine: (hostname: string, port: number) => string;
9
+ export { SERVER_READY_MARKER, serverReadyLine } from '@pikku/deploy';
@@ -1,12 +1,9 @@
1
1
  /**
2
- * Printed once the server is listening AND the project's `afterStart`
3
- * lifecycle has resolved.
2
+ * The readiness handshake, owned by `@pikku/deploy` so the CLI and the
3
+ * standalone provider's generated server entry print and wait on the same
4
+ * string. Re-exported here because `--spawn` and the dev/serve commands have
5
+ * always imported it from this path.
4
6
  *
5
- * The runtime's own `listening on …` line is emitted inside `server.start()`,
6
- * which runs *before* `afterStart` — so anything a project seeds there (users,
7
- * scopes, fixtures) is still pending when it appears, and a parent process
8
- * that treats it as readiness races the seed. This marker is the point at
9
- * which the server is actually usable, and it is what `--spawn` waits for.
7
+ * @see {@link SERVER_READY_MARKER} for why `listening on …` is not readiness.
10
8
  */
11
- export const SERVER_READY_MARKER = 'pikku: ready';
12
- export const serverReadyLine = (hostname, port) => `${SERVER_READY_MARKER} on http://${hostname}:${port}`;
9
+ export { SERVER_READY_MARKER, serverReadyLine } from '@pikku/deploy';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Throw unless `dir` holds a built frontend.
3
+ *
4
+ * Both serving and deploying read a frontend's output rather than producing it,
5
+ * so an unbuilt directory is the one failure mode the config invites, and it is
6
+ * silent everywhere it is not caught: a server boots fine and answers every
7
+ * page with a 404, and a deploy ships a binary with nothing inside it.
8
+ */
9
+ export declare function assertFrontendBuilt(dir: string): Promise<void>;
@@ -0,0 +1,18 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Throw unless `dir` holds a built frontend.
5
+ *
6
+ * Both serving and deploying read a frontend's output rather than producing it,
7
+ * so an unbuilt directory is the one failure mode the config invites, and it is
8
+ * silent everywhere it is not caught: a server boots fine and answers every
9
+ * page with a 404, and a deploy ships a binary with nothing inside it.
10
+ */
11
+ export async function assertFrontendBuilt(dir) {
12
+ try {
13
+ await stat(join(dir, 'index.html'));
14
+ }
15
+ catch {
16
+ throw new Error(`No frontend build found at ${dir} — pikku serves your frontend's output and never builds it, so run the frontend's build first (or drop "frontend" from pikku.config.json).`);
17
+ }
18
+ }
@@ -1,12 +1,33 @@
1
1
  import type { VariablesService } from '@pikku/core/services';
2
- import type { HttpPersonasConfig } from '@pikku/core/persona';
2
+ import type { ActorSecretResolver, HttpPersonasConfig } from '@pikku/core/persona';
3
3
  /** A Fabric operator token, which is what a deployed stage accepts. */
4
4
  export declare const OPERATOR_TOKEN_VARIABLE = "FABRIC_OPERATOR_TOKEN";
5
- /** The actor plugin's passwordless secret, which only `pikku dev` serves. */
5
+ /**
6
+ * The ROOT actor secret, which derives every persona's credential and so is
7
+ * entitled to all of them. Only `pikku dev` serves the endpoint it opens.
8
+ */
6
9
  export declare const ACTOR_SECRET_VARIABLE = "SCENARIO_ACTOR_SECRET";
10
+ /**
11
+ * Already-derived per-persona credentials, `id=secret` comma-separated — what a
12
+ * run is given when it should be able to sign in as some personas and not the
13
+ * rest. Each value is bound to that persona's address by the target, so the
14
+ * list is the whole of what this run can be.
15
+ */
16
+ export declare const PERSONA_SECRETS_VARIABLE = "PIKKU_PERSONA_SECRETS";
7
17
  /** Opt in to creating persona accounts the target does not already have. */
8
18
  export declare const CREATE_MISSING_VARIABLE = "PIKKU_PERSONA_CREATE_MISSING";
9
19
  export type PersonaCredentials = Pick<HttpPersonasConfig, 'secret' | 'operator'>;
20
+ /**
21
+ * `id=secret,id=secret` into a lookup. A value containing `=` is kept whole —
22
+ * base64url never produces one, but a hand-written credential might.
23
+ */
24
+ export declare const parsePersonaSecrets: (raw: string) => Record<string, string>;
25
+ /**
26
+ * Refuses rather than falling through to the root: a run handed a narrow set of
27
+ * credentials asking for a persona outside it is a run doing something nobody
28
+ * authorised, and the useful answer names the persona.
29
+ */
30
+ export declare const personaSecretResolver: (secrets: Record<string, string>) => ActorSecretResolver;
10
31
  /**
11
32
  * How the personas in this run will sign in, decided by which credential the
12
33
  * environment actually holds.
@@ -1,9 +1,55 @@
1
1
  /** A Fabric operator token, which is what a deployed stage accepts. */
2
2
  export const OPERATOR_TOKEN_VARIABLE = 'FABRIC_OPERATOR_TOKEN';
3
- /** The actor plugin's passwordless secret, which only `pikku dev` serves. */
3
+ /**
4
+ * The ROOT actor secret, which derives every persona's credential and so is
5
+ * entitled to all of them. Only `pikku dev` serves the endpoint it opens.
6
+ */
4
7
  export const ACTOR_SECRET_VARIABLE = 'SCENARIO_ACTOR_SECRET';
8
+ /**
9
+ * Already-derived per-persona credentials, `id=secret` comma-separated — what a
10
+ * run is given when it should be able to sign in as some personas and not the
11
+ * rest. Each value is bound to that persona's address by the target, so the
12
+ * list is the whole of what this run can be.
13
+ */
14
+ export const PERSONA_SECRETS_VARIABLE = 'PIKKU_PERSONA_SECRETS';
5
15
  /** Opt in to creating persona accounts the target does not already have. */
6
16
  export const CREATE_MISSING_VARIABLE = 'PIKKU_PERSONA_CREATE_MISSING';
17
+ /**
18
+ * `id=secret,id=secret` into a lookup. A value containing `=` is kept whole —
19
+ * base64url never produces one, but a hand-written credential might.
20
+ */
21
+ export const parsePersonaSecrets = (raw) => {
22
+ const secrets = {};
23
+ for (const entry of raw.split(',')) {
24
+ const trimmed = entry.trim();
25
+ if (!trimmed)
26
+ continue;
27
+ const eq = trimmed.indexOf('=');
28
+ if (eq <= 0) {
29
+ throw new Error(`${PERSONA_SECRETS_VARIABLE} entry '${trimmed}' is not 'personaId=secret'`);
30
+ }
31
+ secrets[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
32
+ }
33
+ if (Object.keys(secrets).length === 0) {
34
+ throw new Error(`${PERSONA_SECRETS_VARIABLE} is set but lists no personas`);
35
+ }
36
+ return secrets;
37
+ };
38
+ /**
39
+ * Refuses rather than falling through to the root: a run handed a narrow set of
40
+ * credentials asking for a persona outside it is a run doing something nobody
41
+ * authorised, and the useful answer names the persona.
42
+ */
43
+ export const personaSecretResolver = (secrets) => {
44
+ return (persona) => {
45
+ const secret = secrets[persona.id];
46
+ if (!secret) {
47
+ throw new Error(`No credential for persona '${persona.id}' — ${PERSONA_SECRETS_VARIABLE} carries ` +
48
+ `${Object.keys(secrets).sort().join(', ')}. Mint one with \`pikku persona secret ${persona.id}\`.`);
49
+ }
50
+ return secret;
51
+ };
52
+ };
7
53
  /**
8
54
  * How the personas in this run will sign in, decided by which credential the
9
55
  * environment actually holds.
@@ -26,11 +72,18 @@ export const resolvePersonaCredentials = async (variables, what) => {
26
72
  const createMissing = String(await variables.get(CREATE_MISSING_VARIABLE)) === 'true';
27
73
  return { operator: { token, createMissing } };
28
74
  }
75
+ const personaSecrets = await variables.get(PERSONA_SECRETS_VARIABLE);
76
+ if (personaSecrets) {
77
+ return {
78
+ secret: personaSecretResolver(parsePersonaSecrets(String(personaSecrets))),
79
+ };
80
+ }
29
81
  const secret = await variables.get(ACTOR_SECRET_VARIABLE);
30
82
  if (secret) {
31
83
  return { secret };
32
84
  }
33
85
  throw new Error(`Neither ${OPERATOR_TOKEN_VARIABLE} nor ${ACTOR_SECRET_VARIABLE} is set — ${what} cannot sign in. ` +
34
86
  `Export ${ACTOR_SECRET_VARIABLE} against a local \`pikku dev\` target, or ` +
35
- `${OPERATOR_TOKEN_VARIABLE} against a deployed one (never put either in pikku.config.json).`);
87
+ `${OPERATOR_TOKEN_VARIABLE} against a deployed one (never put either in pikku.config.json). ` +
88
+ `To hand this run only some personas, mint their credentials with \`pikku persona secret\` and set ${PERSONA_SECRETS_VARIABLE}.`);
36
89
  };