@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.
- package/CHANGELOG.md +245 -0
- package/console-app/assets/{abnfDiagram-N423BO3Z-BP7zxMq6.js → abnfDiagram-N423BO3Z-B2suyn6i.js} +1 -1
- package/console-app/assets/architecture-TIHT7OUA-DmG0bXDT.js +1 -0
- package/console-app/assets/{architectureDiagram-T3A2C74G-mvqdkIfF.js → architectureDiagram-T3A2C74G-BQ5Dfvpo.js} +1 -1
- package/console-app/assets/{blockDiagram-VBNYF7ZC-daD8h3VT.js → blockDiagram-VBNYF7ZC-D4pVRDiF.js} +1 -1
- package/console-app/assets/{c4Diagram-5PPSVZJV-Bd0_wKJj.js → c4Diagram-5PPSVZJV-Da04jGpq.js} +1 -1
- package/console-app/assets/channel-BgCT5gon.js +1 -0
- package/console-app/assets/{chunk-2GRJ4B5K-BFRr_H2V.js → chunk-2GRJ4B5K-CwODIPP4.js} +1 -1
- package/console-app/assets/{chunk-4I5QYGJK-BXWo5Xyx.js → chunk-4I5QYGJK-Bep4akjR.js} +1 -1
- package/console-app/assets/{chunk-5RXB4S5H-BFnXfzzz.js → chunk-5RXB4S5H-CGyCRU9L.js} +1 -1
- package/console-app/assets/{chunk-6Q2QTUOP-Bswg4T3s.js → chunk-6Q2QTUOP-D0IK0SMT.js} +1 -1
- package/console-app/assets/{chunk-7Z6QIM7H-StNGH40U.js → chunk-7Z6QIM7H-D12vS1jX.js} +1 -1
- package/console-app/assets/{chunk-GF5L2VYU-QwXKtQxa.js → chunk-GF5L2VYU-kOLwTzIA.js} +1 -1
- package/console-app/assets/{chunk-I66GZJ75-DDQhhfA0.js → chunk-I66GZJ75-Cb2nDoa3.js} +1 -1
- package/console-app/assets/{chunk-JQJVKLGR-wFyF2bUv.js → chunk-JQJVKLGR-B3a_ctfQ.js} +1 -1
- package/console-app/assets/{chunk-KBJHAD2P-CQPQVDkD.js → chunk-KBJHAD2P-DeP2Lqwp.js} +1 -1
- package/console-app/assets/{chunk-NSK5VX7P-DZhjvnHm.js → chunk-NSK5VX7P-BO8vlGrO.js} +1 -1
- package/console-app/assets/{chunk-QR6OTTB3-D1-TbcCP.js → chunk-QR6OTTB3-sX5V0Lok.js} +1 -1
- package/console-app/assets/{chunk-RYQCIY6F-82OYF6U8.js → chunk-RYQCIY6F-DoCObEhk.js} +1 -1
- package/console-app/assets/{chunk-UBXNYLIW-D85x6Zh2.js → chunk-UBXNYLIW-BndMXU5r.js} +1 -1
- package/console-app/assets/{chunk-W5SLKNZC-B1Ps46_n.js → chunk-W5SLKNZC--VrZN8EC.js} +1 -1
- package/console-app/assets/{chunk-WRU74C26-Ct8XrToU.js → chunk-WRU74C26-DdS0mzXO.js} +1 -1
- package/console-app/assets/chunk-XXDRQBXY-EP2C9tTO.js +1 -0
- package/console-app/assets/classDiagram-JCYQIIEL-D9wGqB4J.js +1 -0
- package/console-app/assets/classDiagram-v2-OCEON4UE-D9wGqB4J.js +1 -0
- package/console-app/assets/{cose-bilkent-JH36ORCC-DdevwV5Y.js → cose-bilkent-JH36ORCC-C5EnHkFn.js} +1 -1
- package/console-app/assets/{cynefin-VYW2F7L2-Dj55csoo.js → cynefin-VYW2F7L2-9irdkTt4.js} +1 -1
- package/console-app/assets/{cynefinDiagram-MW4NZA55-XWSzdajo.js → cynefinDiagram-MW4NZA55-DY19660c.js} +1 -1
- package/console-app/assets/{dagre-VZM6K2ZE-BV2l3zSF.js → dagre-VZM6K2ZE-BYFZSaSb.js} +1 -1
- package/console-app/assets/{dagre-CLoXIMX5.js → dagre-nXgDYqvf.js} +1 -1
- package/console-app/assets/{diagram-7IWD3JNH-DC9NK-nv.js → diagram-7IWD3JNH-oDftiTp1.js} +1 -1
- package/console-app/assets/{diagram-B4RE2ZJO-Cirfb0aN.js → diagram-B4RE2ZJO-Cbj-pPbH.js} +1 -1
- package/console-app/assets/{diagram-LBJQPF4R-BuRRy5X5.js → diagram-LBJQPF4R-Ch53oSKw.js} +1 -1
- package/console-app/assets/{diagram-Q27KOJAE-CAOKQ2xs.js → diagram-Q27KOJAE-DA7K814v.js} +1 -1
- package/console-app/assets/{diagram-UB23O5K3-Bto5kBJo.js → diagram-UB23O5K3-B-_C-ctS.js} +1 -1
- package/console-app/assets/{ebnfDiagram-BXEA7PRR-C5OndYGC.js → ebnfDiagram-BXEA7PRR-DsOdsKXy.js} +1 -1
- package/console-app/assets/{erDiagram-JOGREHBK-DqU4xV4C.js → erDiagram-JOGREHBK-XB1mP5_A.js} +1 -1
- package/console-app/assets/eventmodeling-45OFAUF4-NKFCZ8Fj.js +1 -0
- package/console-app/assets/flowDiagram-UKHOOZJN-BpdPkmum.js +1 -0
- package/console-app/assets/{ganttDiagram-PKOTCBZU-D5_DE9R0.js → ganttDiagram-PKOTCBZU-knk0XSHi.js} +1 -1
- package/console-app/assets/{gitGraph-TEB2WS4Q-nuqfz7Fd.js → gitGraph-TEB2WS4Q-COJnK2tM.js} +1 -1
- package/console-app/assets/{gitGraphDiagram-DS77QQ5N-BtJwp2Y3.js → gitGraphDiagram-DS77QQ5N-sF0v605q.js} +1 -1
- package/console-app/assets/{index-DXcH2K9z.css → index-C8MC-uMB.css} +1 -1
- package/console-app/assets/{index-DRfts2XF.js → index-DMnbsgzs.js} +3 -3
- package/console-app/assets/{info-DKCQHKI2-CIfPVqHr.js → info-DKCQHKI2-Cbatr0w6.js} +1 -1
- package/console-app/assets/{infoDiagram-6WML65LV-B-gTHQad.js → infoDiagram-6WML65LV-93TFPCu2.js} +1 -1
- package/console-app/assets/{ishikawaDiagram-WSZJBQD7-CCwAWb1g.js → ishikawaDiagram-WSZJBQD7-BBR8_Qms.js} +1 -1
- package/console-app/assets/{journeyDiagram-NVQOT4AX-DhqNj_ci.js → journeyDiagram-NVQOT4AX-zG55yDoc.js} +1 -1
- package/console-app/assets/{kanban-definition-27J2QSJJ-DspZ1b3Y.js → kanban-definition-27J2QSJJ-DonGcEAY.js} +1 -1
- package/console-app/assets/{line-D7ZCpNkR.js → line-D1WdVm1S.js} +1 -1
- package/console-app/assets/{linear-B5jMy_q9.js → linear-D2GQL4Cm.js} +1 -1
- package/console-app/assets/{mermaid-parser.core-CMBFGJ0U.js → mermaid-parser.core-b4yKyO56.js} +3 -3
- package/console-app/assets/{mermaid.core-DYoDrSEJ.js → mermaid.core-Cwfec1gr.js} +4 -4
- package/console-app/assets/{mindmap-definition-FAOFIHXS-DsHwd2K9.js → mindmap-definition-FAOFIHXS-D0G4yKgw.js} +1 -1
- package/console-app/assets/{packet-7NZHBO7P-BSRRjf4H.js → packet-7NZHBO7P-DDa4HL2T.js} +1 -1
- package/console-app/assets/{pegDiagram-VL7TDLO6-Bi0OlzgS.js → pegDiagram-VL7TDLO6-fPdN5VZs.js} +1 -1
- package/console-app/assets/{pie-RZYD4A2V-D-8tgqYW.js → pie-RZYD4A2V-DRHURUqo.js} +1 -1
- package/console-app/assets/{pieDiagram-7S7Q4E2Y-CsYbVqaR.js → pieDiagram-7S7Q4E2Y-DMYn8ga_.js} +1 -1
- package/console-app/assets/{quadrantDiagram-CIZ2JOQS-LkLWrWKK.js → quadrantDiagram-CIZ2JOQS-C190OamC.js} +1 -1
- package/console-app/assets/{radar-I7S5WNFK-Bst62XZP.js → radar-I7S5WNFK-Djvqzz9A.js} +1 -1
- package/console-app/assets/{railroad-3IZDKUUU-zJswMQYF.js → railroad-3IZDKUUU-C9YvFeFq.js} +1 -1
- package/console-app/assets/railroad-abnf-AHOZXSZD-B3CYVW4p.js +1 -0
- package/console-app/assets/railroad-ebnf-EBAXGLYW-DrZ2yF62.js +1 -0
- package/console-app/assets/railroad-peg-LSFZ7HO6-CWAmMyxd.js +1 -0
- package/console-app/assets/{railroadDiagram-AXF67PYL-C0QZkg7m.js → railroadDiagram-AXF67PYL-IRFg1VrU.js} +1 -1
- package/console-app/assets/{requirementDiagram-LRYGKXZP-BQg0AbLI.js → requirementDiagram-LRYGKXZP-L-7ubbcT.js} +1 -1
- package/console-app/assets/{sankeyDiagram-W5VNT64P-CQb0BMMi.js → sankeyDiagram-W5VNT64P-DBttV6Gt.js} +1 -1
- package/console-app/assets/{sequenceDiagram-SI44F4Z6-BzgBi0a5.js → sequenceDiagram-SI44F4Z6-Bg15oKAB.js} +1 -1
- package/console-app/assets/{src-Dg-KiSsV.js → src-DUC7tLWb.js} +1 -1
- package/console-app/assets/{stateDiagram-OKZ733FA-BiqXn68g.js → stateDiagram-OKZ733FA-PWl0XGs5.js} +1 -1
- package/console-app/assets/stateDiagram-v2-UEYNNEHI-Celbgz4u.js +1 -0
- package/console-app/assets/{swimlanes-SLNWSIFB-Dy7wDP1q.js → swimlanes-SLNWSIFB-CyXEtGBV.js} +1 -1
- package/console-app/assets/swimlanesDiagram-ULZ7WXOC-zxpNaB4U.js +8 -0
- package/console-app/assets/{timeline-definition-Z64GVDOM-DSWXli8X.js → timeline-definition-Z64GVDOM-BLA-DhBt.js} +1 -1
- package/console-app/assets/{treeView-QDETBFTQ-CeWwcs9r.js → treeView-QDETBFTQ-Bfnmn2UY.js} +1 -1
- package/console-app/assets/{treemap-6X3UGDF4-BfrumiJh.js → treemap-6X3UGDF4-DTA0wveO.js} +1 -1
- package/console-app/assets/{vennDiagram-T6HMQDX7-BsuldZ1n.js → vennDiagram-T6HMQDX7-CLXYZln0.js} +1 -1
- package/console-app/assets/{wardley-OPB4EBWU-oZldxS8z.js → wardley-OPB4EBWU-zwxqisG0.js} +1 -1
- package/console-app/assets/{wardleyDiagram-T6FBY63Y-C5LXyHMj.js → wardleyDiagram-T6FBY63Y-hKtKvNlv.js} +1 -1
- package/console-app/assets/{xychartDiagram-ELKLHX3M-CwhqhNkO.js → xychartDiagram-ELKLHX3M-BGf8p4bo.js} +1 -1
- package/console-app/index.html +2 -2
- package/dist/.pikku/addon/index.d.ts +1 -1
- package/dist/.pikku/addon/index.js +1 -1
- package/dist/.pikku/addon/pikku-addon-types.gen.d.ts +1 -1
- package/dist/.pikku/addon/pikku-addon-types.gen.js +1 -1
- package/dist/.pikku/agent/index.d.ts +1 -1
- package/dist/.pikku/agent/index.js +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
- package/dist/.pikku/auth/index.d.ts +1 -1
- package/dist/.pikku/auth/index.js +1 -1
- package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
- package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
- package/dist/.pikku/channel/index.d.ts +1 -1
- package/dist/.pikku/channel/index.js +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/index.d.ts +1 -1
- package/dist/.pikku/cli/index.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +11 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +7 -0
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +27 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/error/index.d.ts +1 -1
- package/dist/.pikku/error/index.js +1 -1
- package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
- package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
- package/dist/.pikku/function/index.d.ts +1 -1
- package/dist/.pikku/function/index.js +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +59 -23
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/gateway/index.d.ts +1 -1
- package/dist/.pikku/gateway/index.js +1 -1
- package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
- package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
- package/dist/.pikku/http/index.d.ts +1 -1
- package/dist/.pikku/http/index.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/mcp/index.d.ts +1 -1
- package/dist/.pikku/mcp/index.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/middleware/index.d.ts +1 -1
- package/dist/.pikku/middleware/index.js +1 -1
- package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
- package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/queue/index.d.ts +1 -1
- package/dist/.pikku/queue/index.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +2 -0
- package/dist/.pikku/scenarios/index.d.ts +1 -1
- package/dist/.pikku/scenarios/index.js +1 -1
- package/dist/.pikku/scenarios/pikku-personas.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
- package/dist/.pikku/scheduler/index.d.ts +1 -1
- package/dist/.pikku/scheduler/index.js +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +7 -1
- package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricProjectsListInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricProjectsListOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsListInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsSetInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricVariablesGetInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricVariablesSetInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PersonaSecretInput.schema.json +1 -0
- package/dist/.pikku/scopes/index.d.ts +1 -1
- package/dist/.pikku/scopes/index.js +1 -1
- package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
- package/dist/.pikku/secrets/index.d.ts +1 -1
- package/dist/.pikku/secrets/index.js +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/setup/index.d.ts +1 -1
- package/dist/.pikku/setup/index.js +1 -1
- package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
- package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
- package/dist/.pikku/trigger/index.d.ts +1 -1
- package/dist/.pikku/trigger/index.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/index.d.ts +1 -1
- package/dist/.pikku/variables/index.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/index.d.ts +1 -1
- package/dist/.pikku/workflow/index.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +13 -1
- package/dist/src/deploy/build-pipeline.d.ts +10 -0
- package/dist/src/deploy/build-pipeline.js +16 -1
- package/dist/src/deploy/bundler/bun-bundler.js +12 -5
- package/dist/src/deploy/frontend-assets.d.ts +50 -0
- package/dist/src/deploy/frontend-assets.js +82 -0
- package/dist/src/fabric/fabric-commands.d.ts +55 -15
- package/dist/src/fabric/fabric-commands.js +6 -0
- package/dist/src/fabric/functions/deploy.function.js +12 -2
- package/dist/src/fabric/functions/projects-list.function.d.ts +72 -0
- package/dist/src/fabric/functions/projects-list.function.js +63 -0
- package/dist/src/fabric/functions/secrets-list.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-list.function.js +4 -4
- package/dist/src/fabric/functions/secrets-rotate.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-rotate.function.js +8 -5
- package/dist/src/fabric/functions/secrets-set.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-set.function.js +4 -4
- package/dist/src/fabric/functions/validate.function.js +49 -24
- package/dist/src/fabric/functions/variables-get.function.d.ts +4 -4
- package/dist/src/fabric/functions/variables-get.function.js +4 -4
- package/dist/src/fabric/functions/variables-set.function.d.ts +4 -4
- package/dist/src/fabric/functions/variables-set.function.js +4 -4
- package/dist/src/fabric/lib/blank-comments.d.ts +21 -0
- package/dist/src/fabric/lib/blank-comments.js +71 -0
- package/dist/src/fabric/lib/blank-scenario-meta.d.ts +1 -0
- package/dist/src/fabric/lib/blank-scenario-meta.js +110 -0
- package/dist/src/fabric/lib/deployment.d.ts +26 -0
- package/dist/src/fabric/lib/deployment.js +35 -0
- package/dist/src/fabric/lib/stage.d.ts +19 -3
- package/dist/src/fabric/lib/stage.js +29 -6
- package/dist/src/functions/commands/db-reset.js +6 -2
- package/dist/src/functions/commands/deploy-apply.d.ts +10 -0
- package/dist/src/functions/commands/deploy-apply.js +8 -0
- package/dist/src/functions/commands/deploy-plan.js +1 -0
- package/dist/src/functions/commands/dev.js +18 -3
- package/dist/src/functions/commands/environment.d.ts +10 -0
- package/dist/src/functions/commands/environment.js +24 -0
- package/dist/src/functions/commands/persona.d.ts +18 -0
- package/dist/src/functions/commands/persona.js +41 -2
- package/dist/src/functions/commands/scenario-browser.d.ts +13 -5
- package/dist/src/functions/commands/serve-frontend.d.ts +11 -0
- package/dist/src/functions/commands/serve-frontend.js +17 -0
- package/dist/src/functions/commands/serve.js +16 -3
- package/dist/src/functions/db/annotation-parser.d.ts +8 -0
- package/dist/src/functions/db/annotation-parser.js +2 -0
- package/dist/src/functions/db/check-enums.d.ts +38 -0
- package/dist/src/functions/db/check-enums.js +103 -0
- package/dist/src/functions/db/db-codegen.js +35 -1
- package/dist/src/functions/db/postgres/postgres-introspector.d.ts +14 -0
- package/dist/src/functions/db/postgres/postgres-introspector.js +48 -0
- package/dist/src/functions/db/sqlite/sqlite-introspector.d.ts +3 -4
- package/dist/src/functions/db/sqlite/sqlite-introspector.js +5 -17
- package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.d.ts +9 -6
- package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.js +57 -30
- package/dist/src/server/actor-sign-in.d.ts +24 -1
- package/dist/src/server/actor-sign-in.js +45 -2
- package/dist/src/server/dev-server-runner.interface.d.ts +9 -0
- package/dist/src/server/node-server-runner.js +3 -0
- package/dist/src/server/server-ready.d.ts +6 -9
- package/dist/src/server/server-ready.js +6 -9
- package/dist/src/utils/frontend.d.ts +9 -0
- package/dist/src/utils/frontend.js +18 -0
- package/dist/src/utils/persona-credentials.d.ts +23 -2
- package/dist/src/utils/persona-credentials.js +55 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -5
- package/dist/src/utils/pikku-cli-config.js +57 -10
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
- package/snippets.json +2 -2
- package/surface.json +101 -51
- package/console-app/assets/architecture-TIHT7OUA-D4Hj6824.js +0 -1
- package/console-app/assets/channel-09aKDzM0.js +0 -1
- package/console-app/assets/chunk-XXDRQBXY-C1KaR4pt.js +0 -1
- package/console-app/assets/classDiagram-JCYQIIEL-23nagJMi.js +0 -1
- package/console-app/assets/classDiagram-v2-OCEON4UE-23nagJMi.js +0 -1
- package/console-app/assets/eventmodeling-45OFAUF4-RyG54ZHy.js +0 -1
- package/console-app/assets/flowDiagram-UKHOOZJN-DNdfrnRg.js +0 -1
- package/console-app/assets/railroad-abnf-AHOZXSZD-DX4FqVY6.js +0 -1
- package/console-app/assets/railroad-ebnf-EBAXGLYW-DdyOtX1l.js +0 -1
- package/console-app/assets/railroad-peg-LSFZ7HO6-CclC1sXF.js +0 -1
- package/console-app/assets/stateDiagram-v2-UEYNNEHI-I34jrzP0.js +0 -1
- 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.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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
|
-
|
|
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
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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 (
|
|
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
|
-
//
|
|
335
|
-
//
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
};
|