@pikku/cli 0.12.123 → 0.12.125
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 +158 -0
- package/console-app/assets/{abnfDiagram-N423BO3Z-BR5_-R36.js → abnfDiagram-N423BO3Z-B2suyn6i.js} +1 -1
- package/console-app/assets/architecture-TIHT7OUA-DmG0bXDT.js +1 -0
- package/console-app/assets/{architectureDiagram-T3A2C74G-PWMb8XVe.js → architectureDiagram-T3A2C74G-BQ5Dfvpo.js} +1 -1
- package/console-app/assets/{blockDiagram-VBNYF7ZC-BRFlIAtN.js → blockDiagram-VBNYF7ZC-D4pVRDiF.js} +1 -1
- package/console-app/assets/{c4Diagram-5PPSVZJV-DnxGac5c.js → c4Diagram-5PPSVZJV-Da04jGpq.js} +1 -1
- package/console-app/assets/channel-BgCT5gon.js +1 -0
- package/console-app/assets/{chunk-2GRJ4B5K-B09NFK9f.js → chunk-2GRJ4B5K-CwODIPP4.js} +1 -1
- package/console-app/assets/{chunk-4I5QYGJK-Di1FL5uh.js → chunk-4I5QYGJK-Bep4akjR.js} +1 -1
- package/console-app/assets/{chunk-5RXB4S5H-BkFSNR63.js → chunk-5RXB4S5H-CGyCRU9L.js} +1 -1
- package/console-app/assets/{chunk-6Q2QTUOP-L6D94YxI.js → chunk-6Q2QTUOP-D0IK0SMT.js} +1 -1
- package/console-app/assets/{chunk-7Z6QIM7H-DfzYcuKW.js → chunk-7Z6QIM7H-D12vS1jX.js} +1 -1
- package/console-app/assets/{chunk-GF5L2VYU-CA5m-Xs7.js → chunk-GF5L2VYU-kOLwTzIA.js} +1 -1
- package/console-app/assets/{chunk-I66GZJ75-Hl61byF7.js → chunk-I66GZJ75-Cb2nDoa3.js} +1 -1
- package/console-app/assets/{chunk-JQJVKLGR-CgLeeXhv.js → chunk-JQJVKLGR-B3a_ctfQ.js} +1 -1
- package/console-app/assets/{chunk-KBJHAD2P-9mRl0jD6.js → chunk-KBJHAD2P-DeP2Lqwp.js} +1 -1
- package/console-app/assets/{chunk-NSK5VX7P-D7NmS_w1.js → chunk-NSK5VX7P-BO8vlGrO.js} +1 -1
- package/console-app/assets/{chunk-QR6OTTB3-KdKTpLyy.js → chunk-QR6OTTB3-sX5V0Lok.js} +1 -1
- package/console-app/assets/{chunk-RYQCIY6F-DeEpMb3d.js → chunk-RYQCIY6F-DoCObEhk.js} +1 -1
- package/console-app/assets/{chunk-UBXNYLIW-DKYUw71c.js → chunk-UBXNYLIW-BndMXU5r.js} +1 -1
- package/console-app/assets/{chunk-W5SLKNZC-B2fxVl1I.js → chunk-W5SLKNZC--VrZN8EC.js} +1 -1
- package/console-app/assets/{chunk-WRU74C26-CHP8CDJx.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-Bv8nl8zW.js → cose-bilkent-JH36ORCC-C5EnHkFn.js} +1 -1
- package/console-app/assets/{cynefin-VYW2F7L2-CSj7rmbq.js → cynefin-VYW2F7L2-9irdkTt4.js} +1 -1
- package/console-app/assets/{cynefinDiagram-MW4NZA55-C3xwJ3tQ.js → cynefinDiagram-MW4NZA55-DY19660c.js} +1 -1
- package/console-app/assets/{dagre-VZM6K2ZE-B_2qJCCS.js → dagre-VZM6K2ZE-BYFZSaSb.js} +1 -1
- package/console-app/assets/{dagre-DUPxteSi.js → dagre-nXgDYqvf.js} +1 -1
- package/console-app/assets/{diagram-7IWD3JNH-IH1BOccH.js → diagram-7IWD3JNH-oDftiTp1.js} +1 -1
- package/console-app/assets/{diagram-B4RE2ZJO-BVvJvAvO.js → diagram-B4RE2ZJO-Cbj-pPbH.js} +1 -1
- package/console-app/assets/{diagram-LBJQPF4R-CyDL-OzR.js → diagram-LBJQPF4R-Ch53oSKw.js} +1 -1
- package/console-app/assets/{diagram-Q27KOJAE-BwUGm_12.js → diagram-Q27KOJAE-DA7K814v.js} +1 -1
- package/console-app/assets/{diagram-UB23O5K3-TPo3mAAN.js → diagram-UB23O5K3-B-_C-ctS.js} +1 -1
- package/console-app/assets/{ebnfDiagram-BXEA7PRR-D3zthE3L.js → ebnfDiagram-BXEA7PRR-DsOdsKXy.js} +1 -1
- package/console-app/assets/{erDiagram-JOGREHBK-DrJSdPyj.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-xWWCXZUc.js → ganttDiagram-PKOTCBZU-knk0XSHi.js} +1 -1
- package/console-app/assets/{gitGraph-TEB2WS4Q-DqccwZ0r.js → gitGraph-TEB2WS4Q-COJnK2tM.js} +1 -1
- package/console-app/assets/{gitGraphDiagram-DS77QQ5N-BrQMGv-z.js → gitGraphDiagram-DS77QQ5N-sF0v605q.js} +1 -1
- package/console-app/assets/{index-Mq-YbqNO.css → index-C8MC-uMB.css} +1 -1
- package/console-app/assets/{index-BP1o9ux1.js → index-DMnbsgzs.js} +175 -175
- package/console-app/assets/{info-DKCQHKI2-DYYsb_ec.js → info-DKCQHKI2-Cbatr0w6.js} +1 -1
- package/console-app/assets/{infoDiagram-6WML65LV-B659BK5Z.js → infoDiagram-6WML65LV-93TFPCu2.js} +1 -1
- package/console-app/assets/{ishikawaDiagram-WSZJBQD7-nAST6NVR.js → ishikawaDiagram-WSZJBQD7-BBR8_Qms.js} +1 -1
- package/console-app/assets/{journeyDiagram-NVQOT4AX-DvMfDp0L.js → journeyDiagram-NVQOT4AX-zG55yDoc.js} +1 -1
- package/console-app/assets/{kanban-definition-27J2QSJJ-XSWRq0KN.js → kanban-definition-27J2QSJJ-DonGcEAY.js} +1 -1
- package/console-app/assets/{line-BhOX1huR.js → line-D1WdVm1S.js} +1 -1
- package/console-app/assets/{linear-DmCFkJVF.js → linear-D2GQL4Cm.js} +1 -1
- package/console-app/assets/{mermaid-parser.core-3dL4TN1f.js → mermaid-parser.core-b4yKyO56.js} +3 -3
- package/console-app/assets/{mermaid.core-DaXl8RjK.js → mermaid.core-Cwfec1gr.js} +4 -4
- package/console-app/assets/{mindmap-definition-FAOFIHXS-BVSaEdh8.js → mindmap-definition-FAOFIHXS-D0G4yKgw.js} +1 -1
- package/console-app/assets/{packet-7NZHBO7P-DmXSSPjQ.js → packet-7NZHBO7P-DDa4HL2T.js} +1 -1
- package/console-app/assets/{pegDiagram-VL7TDLO6-Cd94zu6b.js → pegDiagram-VL7TDLO6-fPdN5VZs.js} +1 -1
- package/console-app/assets/{pie-RZYD4A2V-BfIstVk8.js → pie-RZYD4A2V-DRHURUqo.js} +1 -1
- package/console-app/assets/{pieDiagram-7S7Q4E2Y-Jxlih0Om.js → pieDiagram-7S7Q4E2Y-DMYn8ga_.js} +1 -1
- package/console-app/assets/{quadrantDiagram-CIZ2JOQS-DMa-9Zmv.js → quadrantDiagram-CIZ2JOQS-C190OamC.js} +1 -1
- package/console-app/assets/{radar-I7S5WNFK-BhvNZ__k.js → radar-I7S5WNFK-Djvqzz9A.js} +1 -1
- package/console-app/assets/{railroad-3IZDKUUU-C7yHVxVy.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-DsBXjXIE.js → railroadDiagram-AXF67PYL-IRFg1VrU.js} +1 -1
- package/console-app/assets/{requirementDiagram-LRYGKXZP-C5JX79TM.js → requirementDiagram-LRYGKXZP-L-7ubbcT.js} +1 -1
- package/console-app/assets/{sankeyDiagram-W5VNT64P-DFGcEBC2.js → sankeyDiagram-W5VNT64P-DBttV6Gt.js} +1 -1
- package/console-app/assets/{sequenceDiagram-SI44F4Z6-BUa6ak9R.js → sequenceDiagram-SI44F4Z6-Bg15oKAB.js} +1 -1
- package/console-app/assets/{src-BJFofs4v.js → src-DUC7tLWb.js} +1 -1
- package/console-app/assets/{stateDiagram-OKZ733FA-DFbCY_t8.js → stateDiagram-OKZ733FA-PWl0XGs5.js} +1 -1
- package/console-app/assets/stateDiagram-v2-UEYNNEHI-Celbgz4u.js +1 -0
- package/console-app/assets/{swimlanes-SLNWSIFB-Cl9G39FU.js → swimlanes-SLNWSIFB-CyXEtGBV.js} +1 -1
- package/console-app/assets/swimlanesDiagram-ULZ7WXOC-zxpNaB4U.js +8 -0
- package/console-app/assets/{timeline-definition-Z64GVDOM-ClWBr3pJ.js → timeline-definition-Z64GVDOM-BLA-DhBt.js} +1 -1
- package/console-app/assets/{treeView-QDETBFTQ-DIQ61Y8k.js → treeView-QDETBFTQ-Bfnmn2UY.js} +1 -1
- package/console-app/assets/{treemap-6X3UGDF4-KbZtNSyG.js → treemap-6X3UGDF4-DTA0wveO.js} +1 -1
- package/console-app/assets/{vennDiagram-T6HMQDX7-BY367OUV.js → vennDiagram-T6HMQDX7-CLXYZln0.js} +1 -1
- package/console-app/assets/{wardley-OPB4EBWU-BZc1RNrx.js → wardley-OPB4EBWU-zwxqisG0.js} +1 -1
- package/console-app/assets/{wardleyDiagram-T6FBY63Y-D45un7IA.js → wardleyDiagram-T6FBY63Y-hKtKvNlv.js} +1 -1
- package/console-app/assets/{xychartDiagram-ELKLHX3M-Ci5YwcnQ.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 +6 -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 +14 -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 +25 -6
- 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 +2 -2
- package/dist/.pikku/middleware/pikku-middleware-types.gen.js +2 -2
- 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 +1 -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 +5 -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/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 +7 -0
- package/dist/src/deploy/build-pipeline.d.ts +10 -0
- package/dist/src/deploy/build-pipeline.js +16 -1
- package/dist/src/deploy/bundler/bundler.js +1 -15
- package/dist/src/deploy/bundler/service-module-map.d.ts +17 -0
- package/dist/src/deploy/bundler/service-module-map.js +19 -0
- 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 +40 -0
- package/dist/src/fabric/fabric-commands.js +6 -0
- 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/validate.function.js +70 -7
- 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 +13 -2
- package/dist/src/functions/commands/environment.d.ts +10 -0
- package/dist/src/functions/commands/environment.js +24 -0
- 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/db-codegen.js +20 -1
- package/dist/src/functions/validate/shared-checks.d.ts +25 -0
- package/dist/src/functions/validate/shared-checks.js +86 -2
- package/dist/src/functions/wirings/middleware/serialize-middleware-types.js +1 -1
- package/dist/src/functions/wirings/variables/serialize-variables-types.js +5 -1
- package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.js +6 -3
- 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/pikku-cli-config.d.ts +10 -1
- package/dist/src/utils/pikku-cli-config.js +27 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/snippets.json +2 -2
- package/surface.json +88 -7
- package/console-app/assets/architecture-TIHT7OUA-B-7dd9iF.js +0 -1
- package/console-app/assets/channel-eaKvL3e5.js +0 -1
- package/console-app/assets/chunk-XXDRQBXY-CJZ5XPXr.js +0 -1
- package/console-app/assets/classDiagram-JCYQIIEL-CSV3IvA1.js +0 -1
- package/console-app/assets/classDiagram-v2-OCEON4UE-CSV3IvA1.js +0 -1
- package/console-app/assets/eventmodeling-45OFAUF4-TV8Whj2Z.js +0 -1
- package/console-app/assets/flowDiagram-UKHOOZJN-C0682uBh.js +0 -1
- package/console-app/assets/railroad-abnf-AHOZXSZD-BbrGgpop.js +0 -1
- package/console-app/assets/railroad-ebnf-EBAXGLYW-BMxBKnfa.js +0 -1
- package/console-app/assets/railroad-peg-LSFZ7HO6-i24YvrZ1.js +0 -1
- package/console-app/assets/stateDiagram-v2-UEYNNEHI-Ds7kyy87.js +0 -1
- package/console-app/assets/swimlanesDiagram-ULZ7WXOC-BAuvqF_W.js +0 -8
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pikkuSessionlessFunc } from '../../../.pikku/function/index.js';
|
|
3
|
+
import { findProjectConfig, resolveApiContext } from '../lib/config.js';
|
|
4
|
+
import { getFabricRPC } from '../lib/http.js';
|
|
5
|
+
import { dim } from '../lib/output.js';
|
|
6
|
+
export const FabricProjectsListInput = z.object({
|
|
7
|
+
apiUrl: z.string().optional(),
|
|
8
|
+
});
|
|
9
|
+
export const FabricProjectsListOutput = z.object({
|
|
10
|
+
projects: z.array(z.object({
|
|
11
|
+
projectId: z.string(),
|
|
12
|
+
name: z.string(),
|
|
13
|
+
slug: z.string(),
|
|
14
|
+
status: z.string(),
|
|
15
|
+
productionBranch: z.string(),
|
|
16
|
+
gitRepoUrl: z.string().nullable(),
|
|
17
|
+
createdAt: z.string(),
|
|
18
|
+
linked: z.boolean(),
|
|
19
|
+
})),
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* The only fabric command that does not need a linked project, which is the
|
|
23
|
+
* point of it: a checkout whose config still holds `__PROJECT_ID__` can run
|
|
24
|
+
* nothing else, and `fabric init` cannot recover the id either — it creates,
|
|
25
|
+
* so against an existing project it fails with a 409 that carries no id.
|
|
26
|
+
*/
|
|
27
|
+
export const FabricProjectsList = pikkuSessionlessFunc({
|
|
28
|
+
description: 'List the projects in your organization.',
|
|
29
|
+
input: FabricProjectsListInput,
|
|
30
|
+
output: FabricProjectsListOutput,
|
|
31
|
+
func: async (_services, { apiUrl: apiUrlOverride }) => {
|
|
32
|
+
const ctx = await resolveApiContext({ apiUrlOverride });
|
|
33
|
+
if (!ctx.token)
|
|
34
|
+
throw new Error('Not logged in. Run `pikku fabric login` first.');
|
|
35
|
+
const rpc = getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token });
|
|
36
|
+
const { projects } = await rpc.invoke('fabricCliProjects', {});
|
|
37
|
+
const local = await findProjectConfig();
|
|
38
|
+
const linkedId = local?.config.projectId;
|
|
39
|
+
return {
|
|
40
|
+
projects: projects.map((project) => ({
|
|
41
|
+
...project,
|
|
42
|
+
linked: linkedId !== undefined && project.projectId === linkedId,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
export const renderProjectsList = (_s, { projects }) => {
|
|
48
|
+
console.log('');
|
|
49
|
+
if (projects.length === 0) {
|
|
50
|
+
console.log(dim(' No projects yet. Run `pikku fabric link` to create one.'));
|
|
51
|
+
console.log('');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const width = Math.max(...projects.map((p) => p.name.length));
|
|
55
|
+
for (const project of projects) {
|
|
56
|
+
console.log(` ${project.linked ? '*' : ' '} ${project.name.padEnd(width)} ${project.projectId} ${dim(project.gitRepoUrl ?? 'no repo')}`);
|
|
57
|
+
}
|
|
58
|
+
console.log('');
|
|
59
|
+
if (projects.some((p) => p.linked)) {
|
|
60
|
+
console.log(dim(' * this checkout'));
|
|
61
|
+
console.log('');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -66,6 +66,15 @@ async function listSourceFiles(dir) {
|
|
|
66
66
|
return [];
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Blanks comment bodies so a raw-text scan cannot read prose as code. Prose in a
|
|
71
|
+
* scenario description ("Converted from the Gherkin scenario...") otherwise
|
|
72
|
+
* matches the import scanner's `from "..."` and reports a package that is really
|
|
73
|
+
* a sentence.
|
|
74
|
+
*/
|
|
75
|
+
const stripCommentText = (text) => text
|
|
76
|
+
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '))
|
|
77
|
+
.replace(/(^|[^:'"`\\])\/\/[^\n]*/g, (_m, p1) => p1);
|
|
69
78
|
// Heavy/generated dirs pruned during a source walk.
|
|
70
79
|
const SKIP_WALK_DIRS = new Set([
|
|
71
80
|
'node_modules',
|
|
@@ -487,11 +496,14 @@ export async function runValidate(startDir = process.cwd(), opts = {}) {
|
|
|
487
496
|
const txt = await readTextSafe(file);
|
|
488
497
|
if (!txt)
|
|
489
498
|
continue;
|
|
499
|
+
const src = stripCommentText(txt);
|
|
490
500
|
const re = /(?:from|import|require)\s*\(?\s*['"]([^'".#][^'"]*)['"]/g;
|
|
491
501
|
let m;
|
|
492
|
-
while ((m = re.exec(
|
|
502
|
+
while ((m = re.exec(src))) {
|
|
493
503
|
const spec = m[1];
|
|
494
|
-
if (spec
|
|
504
|
+
if (/\s/.test(spec) ||
|
|
505
|
+
spec.startsWith('node:') ||
|
|
506
|
+
spec.startsWith('bun:') ||
|
|
495
507
|
spec.startsWith('@/') ||
|
|
496
508
|
spec.startsWith('~') ||
|
|
497
509
|
spec.startsWith('virtual:') ||
|
|
@@ -1180,23 +1192,74 @@ export async function runValidate(startDir = process.cwd(), opts = {}) {
|
|
|
1180
1192
|
}
|
|
1181
1193
|
if (keysByValue.size > 0) {
|
|
1182
1194
|
const STRING_LITERAL = /(?<![A-Za-z0-9_$])(['"])((?:[^\\\n]|\\.){2,200}?)\1/g;
|
|
1195
|
+
// A literal in `someKey: '...'` position is only copy when the key names
|
|
1196
|
+
// something the browser renders. `unit: 'kg'` is an RPC payload field that
|
|
1197
|
+
// happens to read like the catalogue's `unit_kg` label for a form suffix —
|
|
1198
|
+
// rewriting it to a message lookup would bind a stored value to UI copy.
|
|
1199
|
+
const PROPERTY_KEY = /([A-Za-z_$][A-Za-z0-9_$]*)\s*:\s*$/;
|
|
1200
|
+
// The innermost call whose argument list `index` sits in. Walks back
|
|
1201
|
+
// balancing brackets, so in `expect(await page.getByText('Save'), ...)`
|
|
1202
|
+
// the literal belongs to `getByText`, which is a locator and is still
|
|
1203
|
+
// scanned.
|
|
1204
|
+
const enclosingCall = (code, index) => {
|
|
1205
|
+
let depth = 0;
|
|
1206
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
1207
|
+
const ch = code[i];
|
|
1208
|
+
if (ch === ')' || ch === ']' || ch === '}')
|
|
1209
|
+
depth++;
|
|
1210
|
+
else if (ch === '(' || ch === '[' || ch === '{') {
|
|
1211
|
+
if (depth > 0) {
|
|
1212
|
+
depth--;
|
|
1213
|
+
continue;
|
|
1214
|
+
}
|
|
1215
|
+
if (ch !== '(')
|
|
1216
|
+
return null;
|
|
1217
|
+
return (/([A-Za-z_$][A-Za-z0-9_$]*)\s*$/.exec(code.slice(0, i))?.[1] ??
|
|
1218
|
+
null);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return null;
|
|
1222
|
+
};
|
|
1223
|
+
const UI_TEXT_KEYS = new Set([
|
|
1224
|
+
'alt',
|
|
1225
|
+
'button',
|
|
1226
|
+
'caption',
|
|
1227
|
+
'heading',
|
|
1228
|
+
'label',
|
|
1229
|
+
'link',
|
|
1230
|
+
'name',
|
|
1231
|
+
'option',
|
|
1232
|
+
'placeholder',
|
|
1233
|
+
'tab',
|
|
1234
|
+
'text',
|
|
1235
|
+
'title',
|
|
1236
|
+
'value',
|
|
1237
|
+
]);
|
|
1183
1238
|
for (const file of await walkSourceFiles(root)) {
|
|
1184
1239
|
if (!/\.(steps|scenario)\.tsx?$/.test(file))
|
|
1185
1240
|
continue;
|
|
1186
1241
|
const text = await readTextSafe(file);
|
|
1187
1242
|
if (!text)
|
|
1188
1243
|
continue;
|
|
1189
|
-
const code = text
|
|
1190
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
1191
|
-
.replace(/(^|[^:'"`\\])\/\/[^\n]*/g, '$1');
|
|
1244
|
+
const code = stripCommentText(text);
|
|
1192
1245
|
const hits = [];
|
|
1193
1246
|
for (const match of code.matchAll(STRING_LITERAL)) {
|
|
1194
1247
|
const literal = match[2];
|
|
1195
1248
|
if (!literal)
|
|
1196
1249
|
continue;
|
|
1197
1250
|
const keys = keysByValue.get(literal);
|
|
1198
|
-
if (keys)
|
|
1199
|
-
|
|
1251
|
+
if (!keys)
|
|
1252
|
+
continue;
|
|
1253
|
+
// `expect(item.unit, 'kg')` asserts on a value the RPC returned,
|
|
1254
|
+
// not on anything the browser rendered. Reading it from the
|
|
1255
|
+
// catalogue would bind a stored value to UI copy, and the assertion
|
|
1256
|
+
// would then pass against whatever the label happened to say.
|
|
1257
|
+
if (enclosingCall(code, match.index) === 'expect')
|
|
1258
|
+
continue;
|
|
1259
|
+
const property = PROPERTY_KEY.exec(code.slice(0, match.index));
|
|
1260
|
+
if (property && !UI_TEXT_KEYS.has(property[1]))
|
|
1261
|
+
continue;
|
|
1262
|
+
hits.push(`"${literal}" → ${keys.join(' | ')}`);
|
|
1200
1263
|
}
|
|
1201
1264
|
if (hits.length === 0)
|
|
1202
1265
|
continue;
|
|
@@ -8,23 +8,33 @@ export declare function resolveProvider(config?: {
|
|
|
8
8
|
};
|
|
9
9
|
}, providerName?: string, options?: {
|
|
10
10
|
runtime?: string;
|
|
11
|
+
desktop?: boolean;
|
|
12
|
+
projectDir?: string;
|
|
13
|
+
desktopIdentifier?: string;
|
|
14
|
+
desktopUrl?: string;
|
|
11
15
|
}): Promise<ProviderAdapter>;
|
|
12
16
|
export declare const deployApply: import("#pikku/function").PikkuFunctionConfig<{
|
|
13
17
|
fromPlan?: boolean;
|
|
14
18
|
provider?: string;
|
|
15
19
|
runtime?: string;
|
|
20
|
+
desktop?: boolean;
|
|
21
|
+
desktopUrl?: string;
|
|
16
22
|
resultFile?: string;
|
|
17
23
|
debugArtifacts?: boolean;
|
|
18
24
|
}, void, "rpc" | "session", import("#pikku/function").PikkuFunctionSessionless<{
|
|
19
25
|
fromPlan?: boolean;
|
|
20
26
|
provider?: string;
|
|
21
27
|
runtime?: string;
|
|
28
|
+
desktop?: boolean;
|
|
29
|
+
desktopUrl?: string;
|
|
22
30
|
resultFile?: string;
|
|
23
31
|
debugArtifacts?: boolean;
|
|
24
32
|
}, void, "rpc" | "session", import("#pikku/function").WiredServices, unknown> | import("#pikku/function").PikkuFunction<{
|
|
25
33
|
fromPlan?: boolean;
|
|
26
34
|
provider?: string;
|
|
27
35
|
runtime?: string;
|
|
36
|
+
desktop?: boolean;
|
|
37
|
+
desktopUrl?: string;
|
|
28
38
|
resultFile?: string;
|
|
29
39
|
debugArtifacts?: boolean;
|
|
30
40
|
}, void, "rpc" | "session", import("#pikku/function").WiredServices>, undefined, undefined>;
|
|
@@ -178,8 +178,15 @@ async function runDeploy(provider, providerDir, logger, resultFile) {
|
|
|
178
178
|
export const deployApply = pikkuSessionlessFunc({
|
|
179
179
|
func: async ({ logger, config, getInspectorState, bundler }, data) => {
|
|
180
180
|
const projectDir = config.rootDir;
|
|
181
|
+
// A url on its own is a request for a shell — asking for both flags would
|
|
182
|
+
// only leave `--desktop-url` alone as a silent no-op.
|
|
183
|
+
const desktopUrl = data?.desktopUrl ?? config.deploy?.desktop?.url;
|
|
181
184
|
const provider = await resolveProvider(config, data?.provider, {
|
|
182
185
|
runtime: data?.runtime,
|
|
186
|
+
desktop: data?.desktop || Boolean(desktopUrl),
|
|
187
|
+
projectDir,
|
|
188
|
+
desktopIdentifier: config.deploy?.desktop?.identifier,
|
|
189
|
+
desktopUrl,
|
|
183
190
|
});
|
|
184
191
|
const fromPlan = data?.fromPlan ?? false;
|
|
185
192
|
const resultFile = data?.resultFile;
|
|
@@ -212,6 +219,7 @@ export const deployApply = pikkuSessionlessFunc({
|
|
|
212
219
|
defaultTarget: config.deploy?.defaultTarget,
|
|
213
220
|
globalHTTPPrefix: config.globalHTTPPrefix,
|
|
214
221
|
getEntryContext,
|
|
222
|
+
frontend: config.frontend,
|
|
215
223
|
outDir: config.outDir,
|
|
216
224
|
debugArtifacts: data?.debugArtifacts ?? false,
|
|
217
225
|
logger,
|
|
@@ -59,6 +59,7 @@ export const deployPlan = pikkuSessionlessFunc({
|
|
|
59
59
|
defaultTarget: config.deploy?.defaultTarget,
|
|
60
60
|
globalHTTPPrefix: config.globalHTTPPrefix,
|
|
61
61
|
getEntryContext,
|
|
62
|
+
frontend: config.frontend,
|
|
62
63
|
outDir: config.outDir,
|
|
63
64
|
debugArtifacts: data?.debugArtifacts ?? false,
|
|
64
65
|
logger,
|
|
@@ -18,6 +18,7 @@ import { resolveDb, createKysely, parseDatabaseUrl, } from '../db/local-db.js';
|
|
|
18
18
|
import { loadUserBootstrap, loadUserModule } from './load-user-project.js';
|
|
19
19
|
import { registerScenarioInstrumentation } from '../wirings/scenarios/register-scenario-instrumentation.js';
|
|
20
20
|
import { startCoverageService } from './start-coverage.js';
|
|
21
|
+
import { resolveDevEnvironmentName } from './environment.js';
|
|
21
22
|
import { createDevAgentRunner } from './dev-agent-runner.js';
|
|
22
23
|
import { resolveConsoleMount } from './serve-console.js';
|
|
23
24
|
import { serverReadyLine } from '../../server/server-ready.js';
|
|
@@ -28,6 +29,7 @@ export const dev = pikkuSessionlessFunc({
|
|
|
28
29
|
remote: true,
|
|
29
30
|
func: async ({ logger, config, getInspectorState, invalidateInspectorState, variables, devServerRunner, }, { port, watch, hmr, coverage, test, model }, { rpc }) => {
|
|
30
31
|
process.env.PIKKU_DEV_QUICK_LOGIN ??= 'true';
|
|
32
|
+
process.env.PIKKU_ENV ??= resolveDevEnvironmentName(config.environments ?? {});
|
|
31
33
|
enableDevActorSignIn(logger);
|
|
32
34
|
applyModelAliasOverride(logger, model, config.models);
|
|
33
35
|
if (test) {
|
|
@@ -296,10 +298,19 @@ export const dev = pikkuSessionlessFunc({
|
|
|
296
298
|
await lifecycle?.beforeStart?.(resolvedServices);
|
|
297
299
|
await pikkuServer.start();
|
|
298
300
|
await lifecycle?.afterStart?.(resolvedServices);
|
|
301
|
+
// Not `resolvedPort`: `--port 0` asks the OS for a free port, and every URL
|
|
302
|
+
// announced from here has to name the one it actually handed out.
|
|
303
|
+
const boundPort = pikkuServer.port;
|
|
299
304
|
if (consoleMount) {
|
|
300
|
-
logger.info(`Pikku Console available at http://${hostname}:${
|
|
305
|
+
logger.info(`Pikku Console available at http://${hostname}:${boundPort}${consoleMount.urlPrefix}`);
|
|
301
306
|
}
|
|
302
|
-
|
|
307
|
+
// Serving the built frontend here would hand you whatever the last build
|
|
308
|
+
// produced, with no HMR and no warning that it is stale. The frontend's own
|
|
309
|
+
// dev server owns dev; it proxies its API calls back to this port.
|
|
310
|
+
if (config.frontend) {
|
|
311
|
+
logger.info(`Frontend not served in dev — run your frontend dev server and proxy its API calls to http://${hostname}:${boundPort}`);
|
|
312
|
+
}
|
|
313
|
+
logger.info(serverReadyLine(hostname, boundPort));
|
|
303
314
|
let watcher;
|
|
304
315
|
process.once('SIGINT', async () => {
|
|
305
316
|
logger.info('Stopping dev server...');
|
|
@@ -60,3 +60,13 @@ export declare const parseAppUrls: (value: string) => {
|
|
|
60
60
|
base?: string;
|
|
61
61
|
byApp: Record<string, string>;
|
|
62
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* The environment name `pikku dev` is running as, for anything that gates on
|
|
65
|
+
* `PIKKU_ENV` — persona provisioning above all, which fails closed and so
|
|
66
|
+
* provisions nothing at all when nobody says where the process is.
|
|
67
|
+
*
|
|
68
|
+
* Local means a configured, non-production environment whose `apiUrl` is a
|
|
69
|
+
* loopback host; `local` wins when several qualify. A project that configures
|
|
70
|
+
* none gets `undefined` rather than a guess.
|
|
71
|
+
*/
|
|
72
|
+
export declare const resolveDevEnvironmentName: (environments: Record<string, PikkuEnvironment>) => string | undefined;
|
|
@@ -94,3 +94,27 @@ export const parseAppUrls = (value) => {
|
|
|
94
94
|
}
|
|
95
95
|
return { base, byApp };
|
|
96
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* The environment name `pikku dev` is running as, for anything that gates on
|
|
99
|
+
* `PIKKU_ENV` — persona provisioning above all, which fails closed and so
|
|
100
|
+
* provisions nothing at all when nobody says where the process is.
|
|
101
|
+
*
|
|
102
|
+
* Local means a configured, non-production environment whose `apiUrl` is a
|
|
103
|
+
* loopback host; `local` wins when several qualify. A project that configures
|
|
104
|
+
* none gets `undefined` rather than a guess.
|
|
105
|
+
*/
|
|
106
|
+
export const resolveDevEnvironmentName = (environments) => {
|
|
107
|
+
const candidates = Object.entries(environments).filter(([, environment]) => {
|
|
108
|
+
if (environment.production) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
return LOCAL_HOSTNAMES.has(new URL(environment.apiUrl).hostname);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const preferred = candidates.find(([name]) => name === 'local');
|
|
119
|
+
return (preferred ?? candidates[0])?.[0];
|
|
120
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StaticMount } from '@pikku/node-http-server';
|
|
2
|
+
import type { PikkuCLIConfig } from '../../../types/config.js';
|
|
3
|
+
/**
|
|
4
|
+
* Turn a resolved `frontend` config into the mount that serves it.
|
|
5
|
+
*
|
|
6
|
+
* The directory is checked rather than trusted because pikku only ever reads a
|
|
7
|
+
* frontend's output: an unbuilt `dir` means the project's own build has not run,
|
|
8
|
+
* and saying so here is far cheaper than a server that boots fine and answers
|
|
9
|
+
* every page with a 404.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveFrontendMount(frontend: NonNullable<PikkuCLIConfig['frontend']>): Promise<StaticMount>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { assertFrontendBuilt } from '../../utils/frontend.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turn a resolved `frontend` config into the mount that serves it.
|
|
4
|
+
*
|
|
5
|
+
* The directory is checked rather than trusted because pikku only ever reads a
|
|
6
|
+
* frontend's output: an unbuilt `dir` means the project's own build has not run,
|
|
7
|
+
* and saying so here is far cheaper than a server that boots fine and answers
|
|
8
|
+
* every page with a 404.
|
|
9
|
+
*/
|
|
10
|
+
export async function resolveFrontendMount(frontend) {
|
|
11
|
+
await assertFrontendBuilt(frontend.dir);
|
|
12
|
+
return {
|
|
13
|
+
urlPrefix: frontend.urlPrefix,
|
|
14
|
+
directory: frontend.dir,
|
|
15
|
+
spaFallback: frontend.spaFallback,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -16,6 +16,7 @@ import { loadUserBootstrap, loadUserModule } from './load-user-project.js';
|
|
|
16
16
|
import { registerScenarioInstrumentation } from '../wirings/scenarios/register-scenario-instrumentation.js';
|
|
17
17
|
import { createDevAgentRunner } from './dev-agent-runner.js';
|
|
18
18
|
import { resolveConsoleMount } from './serve-console.js';
|
|
19
|
+
import { resolveFrontendMount } from './serve-frontend.js';
|
|
19
20
|
import { serverReadyLine } from '../../server/server-ready.js';
|
|
20
21
|
import { createEphemeralContentSigningJWT } from '../../server/content-signing-jwt.js';
|
|
21
22
|
import { disableDevActorSignIn } from '../../server/actor-sign-in.js';
|
|
@@ -144,22 +145,34 @@ export const serve = pikkuSessionlessFunc({
|
|
|
144
145
|
if (serveConsole && !consoleMount) {
|
|
145
146
|
logger.warn('Console app not found. Please rebuild @pikku/cli with the console app bundled.');
|
|
146
147
|
}
|
|
148
|
+
const frontendMount = config.frontend
|
|
149
|
+
? await resolveFrontendMount(config.frontend)
|
|
150
|
+
: undefined;
|
|
151
|
+
// The console goes first so a frontend mounted at `/` cannot claim
|
|
152
|
+
// `/console` before the console's own mount is offered the request.
|
|
153
|
+
const staticMounts = [consoleMount, frontendMount].filter((mount) => Boolean(mount));
|
|
147
154
|
const pikkuServer = devServerRunner.createServer({
|
|
148
155
|
...userConfig,
|
|
149
156
|
hostname: bindHostname,
|
|
150
157
|
port: resolvedPort,
|
|
151
158
|
content: localContentConfig,
|
|
152
|
-
...(
|
|
159
|
+
...(staticMounts.length ? { staticMounts } : {}),
|
|
153
160
|
}, logger, { contentSigningJWT });
|
|
154
161
|
const lifecycle = await loadLifecycle();
|
|
155
162
|
await pikkuServer.init();
|
|
156
163
|
await lifecycle?.beforeStart?.(resolvedServices);
|
|
157
164
|
await pikkuServer.start();
|
|
158
165
|
await lifecycle?.afterStart?.(resolvedServices);
|
|
166
|
+
// Not `resolvedPort`: `--port 0` asks the OS for a free port, and every URL
|
|
167
|
+
// announced from here has to name the one it actually handed out.
|
|
168
|
+
const boundPort = pikkuServer.port;
|
|
159
169
|
if (consoleMount) {
|
|
160
|
-
logger.info(`Pikku Console available at http://${hostname}:${
|
|
170
|
+
logger.info(`Pikku Console available at http://${hostname}:${boundPort}${consoleMount.urlPrefix}`);
|
|
171
|
+
}
|
|
172
|
+
if (frontendMount) {
|
|
173
|
+
logger.info(`Frontend available at http://${hostname}:${boundPort}${frontendMount.urlPrefix}`);
|
|
161
174
|
}
|
|
162
|
-
logger.info(serverReadyLine(hostname,
|
|
175
|
+
logger.info(serverReadyLine(hostname, boundPort));
|
|
163
176
|
process.once('SIGINT', async () => {
|
|
164
177
|
logger.info('Stopping server...');
|
|
165
178
|
try {
|
|
@@ -30,6 +30,14 @@ export interface ColAnnotation {
|
|
|
30
30
|
* insert/update brand on the generated column type. Absent means `plain`.
|
|
31
31
|
*/
|
|
32
32
|
form?: ColumnForm;
|
|
33
|
+
/**
|
|
34
|
+
* Which key protects this column, for an encrypted `form`. Absent means the
|
|
35
|
+
* deployment's default key.
|
|
36
|
+
*
|
|
37
|
+
* Reported as authored rather than defaulted here, so the manifest emitter
|
|
38
|
+
* stays the single place the default is applied.
|
|
39
|
+
*/
|
|
40
|
+
keyId?: string;
|
|
33
41
|
}
|
|
34
42
|
/** Per-table, per-column annotation map sourced from `db/annotations.ts`. */
|
|
35
43
|
export type AnnotationMap = Record<string, Record<string, ColAnnotation>>;
|
|
@@ -117,6 +117,8 @@ export function loadAnnotations(rootDir) {
|
|
|
117
117
|
COLUMN_FORMS.includes(ann.form)) {
|
|
118
118
|
entry.form = ann.form;
|
|
119
119
|
}
|
|
120
|
+
if (ann.keyId)
|
|
121
|
+
entry.keyId = ann.keyId;
|
|
120
122
|
const strategy = parseStrategy(ann.classification);
|
|
121
123
|
if (strategy !== null)
|
|
122
124
|
entry.anonymize = strategy;
|
|
@@ -340,6 +340,14 @@ function emitInterface(table, camelCase, explicitAnnotations, dialect, enumByNam
|
|
|
340
340
|
return `export interface ${ifaceName} {\n${fields}\n}`;
|
|
341
341
|
}
|
|
342
342
|
// ─── Manifest emitter ────────────────────────────────────────────────────────
|
|
343
|
+
/**
|
|
344
|
+
* The key an encrypted column is protected by when it names none.
|
|
345
|
+
*
|
|
346
|
+
* Spelled out in every entry rather than left implicit, so the set of keys a
|
|
347
|
+
* deployment has to resolve can be read off the manifest without knowing the
|
|
348
|
+
* rule that produced it.
|
|
349
|
+
*/
|
|
350
|
+
const DEFAULT_COLUMN_KEY_ID = 'default';
|
|
343
351
|
function emitManifest(tables, explicitAnnotations) {
|
|
344
352
|
const tableEntries = tables
|
|
345
353
|
.map((table) => {
|
|
@@ -354,8 +362,15 @@ function emitManifest(tables, explicitAnnotations) {
|
|
|
354
362
|
// tell "held in the clear, stated" from "nobody has said yet", and a
|
|
355
363
|
// defaulted 'plain' would erase exactly that difference.
|
|
356
364
|
const formLiteral = ann?.form ? `, form: '${ann.form}'` : '';
|
|
365
|
+
// Only a column that is actually encrypted names a key. Emitting one
|
|
366
|
+
// on a plain or hashed column would claim a protection it has not
|
|
367
|
+
// got — and a hash has no key to be opened with in the first place.
|
|
368
|
+
const encrypted = ann?.form === 'wrapped' || ann?.form === 'sealed';
|
|
369
|
+
const keyIdLiteral = encrypted
|
|
370
|
+
? `, keyId: '${ann?.keyId ?? DEFAULT_COLUMN_KEY_ID}'`
|
|
371
|
+
: '';
|
|
357
372
|
return (` ${JSON.stringify(col.name)}: ` +
|
|
358
|
-
`{ classification: '${classification}', anonymize_strategy: ${strategyLiteral}${formLiteral} }`);
|
|
373
|
+
`{ classification: '${classification}', anonymize_strategy: ${strategyLiteral}${formLiteral}${keyIdLiteral} }`);
|
|
359
374
|
})
|
|
360
375
|
.join(',\n');
|
|
361
376
|
return ` ${JSON.stringify(table.name)}: {\n${colEntries}\n }`;
|
|
@@ -391,6 +406,10 @@ function emitClassificationMap(tables) {
|
|
|
391
406
|
` * real encrypt/seal/hash result can be written to it. Defaults to 'plain',`,
|
|
392
407
|
` * which on a \`secret\` column is warned about (PKU483) until stated here. */`,
|
|
393
408
|
` form?: 'plain' | 'hashed' | 'wrapped' | 'sealed'`,
|
|
409
|
+
` /** Which key protects this column, for a 'wrapped' or 'sealed' form. It is a`,
|
|
410
|
+
` * purpose, not a tenant: naming one here says these columns open together and`,
|
|
411
|
+
` * separately from the rest. Defaults to 'default'. */`,
|
|
412
|
+
` keyId?: string`,
|
|
394
413
|
` /** Anonymize strategy used by \`pikku db anonymize\`. */`,
|
|
395
414
|
` classification?: 'fake:email' | 'fake:name' | 'hash' | 'keep'`,
|
|
396
415
|
` /** Column kind override for codegen coercion + typing. */`,
|
|
@@ -55,6 +55,31 @@ export declare function readTextSafe(path: string): Promise<string | null>;
|
|
|
55
55
|
* optional schema qualifier, since `main.audit` is the same table.
|
|
56
56
|
*/
|
|
57
57
|
export declare function migrationCreatesTable(sql: string, tableName: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Every table name one better-auth model can be sitting under.
|
|
60
|
+
*
|
|
61
|
+
* `modelName` renames a model's table — `user: { modelName: 'authUser' }` is
|
|
62
|
+
* how an app keeps better-auth's rows out of a `user` table it already owns —
|
|
63
|
+
* and the adapter's CamelCasePlugin then writes that as `auth_user`. An app
|
|
64
|
+
* that renames all four models has none of the default names in its
|
|
65
|
+
* migrations, so a default-names-only check reported it as having no auth
|
|
66
|
+
* schema at all. Accept the default, the override, and the override's
|
|
67
|
+
* snake_case form.
|
|
68
|
+
*/
|
|
69
|
+
export declare const betterAuthTableAliases: (model: string, configText: string) => string[];
|
|
70
|
+
/**
|
|
71
|
+
* Static value imports of a package the deploy bundler stubs.
|
|
72
|
+
*
|
|
73
|
+
* A unit that does not require the service gets the package rewritten to
|
|
74
|
+
* `export {}`, so a static named import fails to bundle — once per unit, with
|
|
75
|
+
* an esbuild message that names the stub rather than the mistake. Type-only
|
|
76
|
+
* imports are erased before bundling and a side-effect import binds nothing,
|
|
77
|
+
* so neither is reported.
|
|
78
|
+
*/
|
|
79
|
+
export declare const staticStubbedImports: (code: string) => Array<{
|
|
80
|
+
module: string;
|
|
81
|
+
service: string;
|
|
82
|
+
}>;
|
|
58
83
|
/**
|
|
59
84
|
* Every check that is true of any pikku project, regardless of where it deploys.
|
|
60
85
|
*
|
|
@@ -8,6 +8,7 @@ import { runAuthPluginChecks } from './auth-plugin-checks.js';
|
|
|
8
8
|
import { runScenarioFileChecks } from './scenario-file-checks.js';
|
|
9
9
|
import { projectWiresChannels, runWebsocketDepsChecks, } from './websocket-deps-checks.js';
|
|
10
10
|
import { resolveFromProject } from '../../utils/resolve-from-project.js';
|
|
11
|
+
import { SERVICE_MODULE_MAP } from '../../deploy/bundler/service-module-map.js';
|
|
11
12
|
/**
|
|
12
13
|
* A malformed config is named, never reported as absent.
|
|
13
14
|
*
|
|
@@ -73,6 +74,81 @@ export function migrationCreatesTable(sql, tableName) {
|
|
|
73
74
|
}
|
|
74
75
|
/** better-auth's core schema — the tables its adapter queries on every request. */
|
|
75
76
|
const BETTER_AUTH_TABLES = ['user', 'session', 'account', 'verification'];
|
|
77
|
+
/**
|
|
78
|
+
* Every table name one better-auth model can be sitting under.
|
|
79
|
+
*
|
|
80
|
+
* `modelName` renames a model's table — `user: { modelName: 'authUser' }` is
|
|
81
|
+
* how an app keeps better-auth's rows out of a `user` table it already owns —
|
|
82
|
+
* and the adapter's CamelCasePlugin then writes that as `auth_user`. An app
|
|
83
|
+
* that renames all four models has none of the default names in its
|
|
84
|
+
* migrations, so a default-names-only check reported it as having no auth
|
|
85
|
+
* schema at all. Accept the default, the override, and the override's
|
|
86
|
+
* snake_case form.
|
|
87
|
+
*/
|
|
88
|
+
export const betterAuthTableAliases = (model, configText) => {
|
|
89
|
+
const override = configText.match(new RegExp(`\\b${model}\\s*:\\s*\\{[^{}]*?\\bmodelName\\s*:\\s*['"\`](\\w+)['"\`]`))?.[1];
|
|
90
|
+
if (!override)
|
|
91
|
+
return [model];
|
|
92
|
+
return [
|
|
93
|
+
model,
|
|
94
|
+
override,
|
|
95
|
+
override.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase(),
|
|
96
|
+
];
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Static value imports of a package the deploy bundler stubs.
|
|
100
|
+
*
|
|
101
|
+
* A unit that does not require the service gets the package rewritten to
|
|
102
|
+
* `export {}`, so a static named import fails to bundle — once per unit, with
|
|
103
|
+
* an esbuild message that names the stub rather than the mistake. Type-only
|
|
104
|
+
* imports are erased before bundling and a side-effect import binds nothing,
|
|
105
|
+
* so neither is reported.
|
|
106
|
+
*/
|
|
107
|
+
export const staticStubbedImports = (code) => {
|
|
108
|
+
const found = [];
|
|
109
|
+
const statements = code.matchAll(/^[ \t]*import\s+(?!type\s)([\s\S]*?)\s*from\s*['"`]([^'"`]+)['"`]/gm);
|
|
110
|
+
for (const statement of statements) {
|
|
111
|
+
const clause = statement[1];
|
|
112
|
+
const specifier = statement[2];
|
|
113
|
+
const named = clause.match(/^\{([\s\S]*)\}$/);
|
|
114
|
+
if (named &&
|
|
115
|
+
named[1]
|
|
116
|
+
.split(',')
|
|
117
|
+
.filter((binding) => binding.trim().length > 0)
|
|
118
|
+
.every((binding) => /^type\s/.test(binding.trim()))) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const [service, patterns] of Object.entries(SERVICE_MODULE_MAP)) {
|
|
122
|
+
if (patterns.some((pattern) => pattern.test(specifier))) {
|
|
123
|
+
found.push({ module: specifier, service });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return found;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* The text of every source file that configures better-auth, concatenated.
|
|
131
|
+
*
|
|
132
|
+
* Narrowed to files mentioning `betterAuth` so a `modelName` belonging to some
|
|
133
|
+
* other library cannot rename an auth table out from under the check.
|
|
134
|
+
*/
|
|
135
|
+
const readAuthConfigText = async (srcDir) => {
|
|
136
|
+
if (!existsSync(srcDir))
|
|
137
|
+
return '';
|
|
138
|
+
let entries;
|
|
139
|
+
try {
|
|
140
|
+
entries = (await readdir(srcDir, { recursive: true })).filter((f) => typeof f === 'string' &&
|
|
141
|
+
f.endsWith('.ts') &&
|
|
142
|
+
!f.includes('node_modules'));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return '';
|
|
146
|
+
}
|
|
147
|
+
const texts = await Promise.all(entries.map((f) => readTextSafe(join(srcDir, f))));
|
|
148
|
+
return texts
|
|
149
|
+
.filter((t) => Boolean(t) && /betterAuth/.test(t))
|
|
150
|
+
.join('\n');
|
|
151
|
+
};
|
|
76
152
|
/**
|
|
77
153
|
* Scaffold flags that gate a generated surface the pikku console calls.
|
|
78
154
|
*
|
|
@@ -223,9 +299,15 @@ export async function runSharedProjectChecks(root) {
|
|
|
223
299
|
}
|
|
224
300
|
}
|
|
225
301
|
const servicesPath = join(fnDir, 'src', 'services.ts');
|
|
226
|
-
|
|
302
|
+
const servicesText = await readTextSafe(servicesPath);
|
|
303
|
+
if (!servicesText) {
|
|
227
304
|
w('services-missing', 'packages/functions/src/services.ts not found', servicesPath, 'Create services.ts and export your service factory for the workspace');
|
|
228
305
|
}
|
|
306
|
+
else {
|
|
307
|
+
for (const { module, service } of staticStubbedImports(servicesText)) {
|
|
308
|
+
e('services-static-stubbed-import', `services.ts imports '${module}' statically, but the deploy bundler stubs it in every unit that does not require '${service}'`, servicesPath, lines(`Every unit without '${service}' gets '${module}' rewritten to \`export {}\`, so a static import fails to bundle there.`, 'Import the type only, then load the package when you build the service:', ` const mod = await import('${module}')`, ' if (mod.SomeExport) { ... }', 'See templates/starter-template/packages/functions/src/services.ts for the shape.'));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
229
311
|
// ── auth schema ──────────────────────────────────────────────────────
|
|
230
312
|
// The tables are better-auth's own (`user`, `session`, `account`,
|
|
231
313
|
// `verification`) because those are what the adapter queries. This check
|
|
@@ -257,8 +339,10 @@ export async function runSharedProjectChecks(root) {
|
|
|
257
339
|
const allSql = (await Promise.all(files.map((f) => readTextSafe(join(migrationsDir, f)))))
|
|
258
340
|
.filter((sql) => Boolean(sql))
|
|
259
341
|
.join('\n');
|
|
342
|
+
const authConfigText = await readAuthConfigText(join(fnDir, 'src'));
|
|
260
343
|
for (const table of BETTER_AUTH_TABLES) {
|
|
261
|
-
|
|
344
|
+
const aliases = betterAuthTableAliases(table, authConfigText);
|
|
345
|
+
if (!aliases.some((name) => migrationCreatesTable(allSql, name))) {
|
|
262
346
|
missingAuthTables.push(table);
|
|
263
347
|
}
|
|
264
348
|
}
|
|
@@ -24,7 +24,7 @@ import type { PikkuAgentMiddlewareHooks } from '@pikku/core/agent'
|
|
|
24
24
|
import type { Services, SingletonServices } from '${functionTypesImportPath}'
|
|
25
25
|
${requiredServicesTypeImport}
|
|
26
26
|
|
|
27
|
-
export { cors, authAPIKey, authBearer, authCookie } from '@pikku/core/middleware'
|
|
27
|
+
export { cors, requireOrigin, authAPIKey, authBearer, authCookie } from '@pikku/core/middleware'
|
|
28
28
|
export type { MiddlewarePriority }
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -24,7 +24,11 @@ export const serializeVariablesTypes = ({ definitions, schemaLookup, variablesFi
|
|
|
24
24
|
}
|
|
25
25
|
schemaImports.get(schemaRef.sourceFile).add(schemaRef.variableName);
|
|
26
26
|
mapEntries.push(` '${meta.variableId}': z.infer<typeof ${schemaRef.variableName}>`);
|
|
27
|
-
|
|
27
|
+
// The schema is emitted behind a thunk because this file and the one
|
|
28
|
+
// declaring the schema import each other: reading it while the modules
|
|
29
|
+
// are still initializing throws `Cannot access '<schema>' before
|
|
30
|
+
// initialization`, and deferring the read to first use avoids the cycle.
|
|
31
|
+
metaEntries.push(` '${meta.variableId}': { name: '${name}', displayName: ${literal(meta.displayName)}, schema: () => ${schemaRef.variableName} }`);
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
}
|