@pikku/cli 0.12.160 → 0.12.163
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/console-app/assets/{HelpPanel-C06T226y.js → HelpPanel-C__s-OXa.js} +1 -1
- package/console-app/assets/{abnfDiagram-VCTEODGH-BVwdT3Es.js → abnfDiagram-VCTEODGH-DLIFOOvF.js} +1 -1
- package/console-app/assets/architecture-7GRP2DOG-C3aOtis2.js +1 -0
- package/console-app/assets/{architectureDiagram-5GKGNRK7-XfzqZ3mW.js → architectureDiagram-5GKGNRK7-DTilS9zr.js} +1 -1
- package/console-app/assets/{blockDiagram-I7D4REHJ-B5omSqDK.js → blockDiagram-I7D4REHJ-CCTMqaSo.js} +1 -1
- package/console-app/assets/{c4Diagram-7LVT6UL2-DkPe7xCg.js → c4Diagram-7LVT6UL2-HTxceuVS.js} +1 -1
- package/console-app/assets/channel-C9rJmzgz.js +1 -0
- package/console-app/assets/{chunk-4HAMMTFA-QfSXT_X7.js → chunk-4HAMMTFA-CB4W3eSt.js} +1 -1
- package/console-app/assets/{chunk-75Z2AOVW-h7UnPWNo.js → chunk-75Z2AOVW-C9TP1VXB.js} +1 -1
- package/console-app/assets/{chunk-DU6HZSFF-VaMy-LOI.js → chunk-DU6HZSFF-84ww5mPe.js} +1 -1
- package/console-app/assets/{chunk-F27PBJKO-toywqOqS.js → chunk-F27PBJKO-B6nEGqlt.js} +1 -1
- package/console-app/assets/{chunk-GMAD6QVW-Cpa-YKLB.js → chunk-GMAD6QVW-SJ1Qwv1p.js} +1 -1
- package/console-app/assets/{chunk-GVQU2GXP-BWSHPLNL.js → chunk-GVQU2GXP-CpvfZAir.js} +1 -1
- package/console-app/assets/{chunk-IMKFNOWR-yhQzfQuj.js → chunk-IMKFNOWR-CdZpInOk.js} +1 -1
- package/console-app/assets/{chunk-L3NEJ4N5-C8pAfDlo.js → chunk-L3NEJ4N5-DDwTgcch.js} +1 -1
- package/console-app/assets/{chunk-OSK3NFVY-749yk2fa.js → chunk-OSK3NFVY-Ce8laAeV.js} +1 -1
- package/console-app/assets/{chunk-P2QGCYS3-C1Y9GyYT.js → chunk-P2QGCYS3-CfBNms3b.js} +1 -1
- package/console-app/assets/{chunk-POPQ4Y6H-DzI9aRsX.js → chunk-POPQ4Y6H-BZI0KZav.js} +1 -1
- package/console-app/assets/{chunk-PWAF6VOD-D3fAPSwz.js → chunk-PWAF6VOD-Car_F-5i.js} +1 -1
- package/console-app/assets/{chunk-SHT3W25Y-D9w7LzM9.js → chunk-SHT3W25Y-B7o3qSVw.js} +1 -1
- package/console-app/assets/{chunk-SVP7TREG-D55MjOJw.js → chunk-SVP7TREG-8bi0TugS.js} +1 -1
- package/console-app/assets/{chunk-TICWLB2K-DV8q7H-z.js → chunk-TICWLB2K-BT94BHEH.js} +1 -1
- package/console-app/assets/chunk-XXDRQBXY-CN-XariJ.js +1 -0
- package/console-app/assets/classDiagram-ZZMXUADV-C-G692c4.js +1 -0
- package/console-app/assets/classDiagram-v2-VYDZK3BY-C-G692c4.js +1 -0
- package/console-app/assets/{cose-bilkent-JH36ORCC-CLedPW9a.js → cose-bilkent-JH36ORCC-Bpn1bn9K.js} +1 -1
- package/console-app/assets/{cynefin-OW5HDTMX-CS5NKw2p.js → cynefin-OW5HDTMX-CfFkO8xq.js} +1 -1
- package/console-app/assets/{cynefinDiagram-5FMLGOSQ-DGTHW90E.js → cynefinDiagram-5FMLGOSQ-E66AVAFL.js} +1 -1
- package/console-app/assets/{dagre-BNQdos_2.js → dagre-54kLhRyV.js} +1 -1
- package/console-app/assets/{dagre-GXQ25YYZ-DHZ8wtwQ.js → dagre-GXQ25YYZ-D4En0mXW.js} +1 -1
- package/console-app/assets/{diagram-S7CK7UJ4-C41Begsy.js → diagram-S7CK7UJ4-DhFYC_I5.js} +1 -1
- package/console-app/assets/{diagram-UQ7AKVKN-CU8D-sRT.js → diagram-UQ7AKVKN-QV1teZ2Z.js} +1 -1
- package/console-app/assets/{diagram-VSXAHHWV-DTTiXYnQ.js → diagram-VSXAHHWV-CTZbzeS4.js} +1 -1
- package/console-app/assets/{diagram-VX7I27RA-BBy91pxm.js → diagram-VX7I27RA-BFoMlx0h.js} +1 -1
- package/console-app/assets/{diagram-Z3DM3KII-D50xTYe5.js → diagram-Z3DM3KII-DXYj_9Q8.js} +1 -1
- package/console-app/assets/{ebnfDiagram-PWID7BFC-BHjnFZgE.js → ebnfDiagram-PWID7BFC-C7TLD6M3.js} +1 -1
- package/console-app/assets/{erDiagram-RLTQ6QDP-B4-yVo9b.js → erDiagram-RLTQ6QDP-hPkM-ewN.js} +1 -1
- package/console-app/assets/eventmodeling-NTZA5JFV-U-EsOY6h.js +1 -0
- package/console-app/assets/flowDiagram-HODETNUW-LmjHrpKd.js +1 -0
- package/console-app/assets/{ganttDiagram-EL5Y4UJY-D1T-2BlO.js → ganttDiagram-EL5Y4UJY-B6TmOQZX.js} +1 -1
- package/console-app/assets/{gitGraph-4MIJSDKK-ClqKTUfQ.js → gitGraph-4MIJSDKK-BwbHr20B.js} +1 -1
- package/console-app/assets/{gitGraphDiagram-WWUBYQGX-ruq2MAhM.js → gitGraphDiagram-WWUBYQGX-Dl1TcmWc.js} +1 -1
- package/console-app/assets/{graphlib-D-vLYPdw.js → graphlib-DHZpPJUN.js} +1 -1
- package/console-app/assets/{index-BIEZPuyK.js → index-BzStIuLU.js} +137 -137
- package/console-app/assets/{info-A6RAGUB7-BGI-8HNB.js → info-A6RAGUB7-D708VGlV.js} +1 -1
- package/console-app/assets/{infoDiagram-27XIBGKW-BGURgKHv.js → infoDiagram-27XIBGKW-UHD7ySe3.js} +1 -1
- package/console-app/assets/{ishikawaDiagram-5VMMS53U-DzgAaPTR.js → ishikawaDiagram-5VMMS53U-GyFZr765.js} +1 -1
- package/console-app/assets/{journeyDiagram-3NMN7TZE-BsyWad8z.js → journeyDiagram-3NMN7TZE-CoewHpEg.js} +1 -1
- package/console-app/assets/{kanban-definition-UXKFOSKX-g1nO2rWF.js → kanban-definition-UXKFOSKX-F0W6Aec5.js} +1 -1
- package/console-app/assets/{line-CeFoQ5y-.js → line-C4wYKh6f.js} +1 -1
- package/console-app/assets/{linear-C4Pk-YMX.js → linear-nPQacEjt.js} +1 -1
- package/console-app/assets/{mermaid-parser.core-U7wquvx8.js → mermaid-parser.core-BVBt0Hmw.js} +3 -3
- package/console-app/assets/{mermaid.core-8TRpFRm9.js → mermaid.core-BMrHbMBm.js} +4 -4
- package/console-app/assets/{mindmap-definition-YA3MSWOX-C7lzwqBX.js → mindmap-definition-YA3MSWOX-Dhdn4hmh.js} +1 -1
- package/console-app/assets/{packet-AYTQ26CC-DiQV_rU3.js → packet-AYTQ26CC-CleVGuC-.js} +1 -1
- package/console-app/assets/{pegDiagram-XKGWAZYB-63ajP7-W.js → pegDiagram-XKGWAZYB-NDJ5URs9.js} +1 -1
- package/console-app/assets/{pie-WAS4IAKB-B5q_o6dr.js → pie-WAS4IAKB-DCgq6z8V.js} +1 -1
- package/console-app/assets/{pieDiagram-E7YTZNPT-BTbvj-by.js → pieDiagram-E7YTZNPT-BPo__c-e.js} +1 -1
- package/console-app/assets/{quadrantDiagram-AXDQQJYC-CulqsAYd.js → quadrantDiagram-AXDQQJYC-C6AlGJWn.js} +1 -1
- package/console-app/assets/{radar-RG4KPBEZ-CW_KoURS.js → radar-RG4KPBEZ-iKELPo6S.js} +1 -1
- package/console-app/assets/{railroad-74A4TZTK-CUmF6uBQ.js → railroad-74A4TZTK-D7o-4Y2z.js} +1 -1
- package/console-app/assets/railroad-abnf-HS5TGJTU-SJ0ZNV52.js +1 -0
- package/console-app/assets/railroad-ebnf-LZEXJU2U-CoxgM6s2.js +1 -0
- package/console-app/assets/railroad-peg-WCYAUIDC-Dt1jr0ie.js +1 -0
- package/console-app/assets/{railroadDiagram-O6MQD6OU-WlkBu_N3.js → railroadDiagram-O6MQD6OU-Bxb416Ip.js} +1 -1
- package/console-app/assets/{requirementDiagram-BXWQKSXE-CJK_CbPR.js → requirementDiagram-BXWQKSXE-wpPz84xe.js} +1 -1
- package/console-app/assets/{sankeyDiagram-P5KCCOFB-C466WOH8.js → sankeyDiagram-P5KCCOFB-DCtqI-U8.js} +1 -1
- package/console-app/assets/{sequenceDiagram-WJ2MYXX4-CV0dCcj0.js → sequenceDiagram-WJ2MYXX4-B9qErfQU.js} +1 -1
- package/console-app/assets/{src-P4Nw8sY0.js → src-CrUEtLgb.js} +1 -1
- package/console-app/assets/{stateDiagram-D77RDMKH-HaLGm8V9.js → stateDiagram-D77RDMKH-DVQO4UZZ.js} +1 -1
- package/console-app/assets/stateDiagram-v2-MP3YSRHH-qOQfgOOB.js +1 -0
- package/console-app/assets/{swimlanes-42K2YHIH-Bi-O5vWa.js → swimlanes-42K2YHIH-CfBqlUg-.js} +1 -1
- package/console-app/assets/swimlanesDiagram-VR7AAH4N-D6fTU5Cq.js +8 -0
- package/console-app/assets/{timeline-definition-24CTP7MA-B4h-gx-i.js → timeline-definition-24CTP7MA-CPFn_B-h.js} +1 -1
- package/console-app/assets/{treeView-Q6P3EWNA-CXJ_pHQw.js → treeView-Q6P3EWNA-CVWAH-EI.js} +1 -1
- package/console-app/assets/{treemap-WGGIJYW6-M84p2a_3.js → treemap-WGGIJYW6-DEBgfaYx.js} +1 -1
- package/console-app/assets/{vennDiagram-4TSXK5OY-BesF4k_r.js → vennDiagram-4TSXK5OY-BA4GGrwY.js} +1 -1
- package/console-app/assets/{wardley-WFR3VGLG-n9ulickP.js → wardley-WFR3VGLG-TajUo-aF.js} +1 -1
- package/console-app/assets/{wardleyDiagram-VM6X3IG4-BG0nnWDf.js → wardleyDiagram-VM6X3IG4-Bd1y8DdK.js} +1 -1
- package/console-app/assets/{xychartDiagram-S5SC5T6Z-BtOW7fpF.js → xychartDiagram-S5SC5T6Z-CWQmkOFg.js} +1 -1
- package/console-app/index.html +1 -1
- 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/analytics/index.d.ts +1 -1
- package/dist/.pikku/analytics/index.js +1 -1
- package/dist/.pikku/analytics/pikku-analytics-types.gen.d.ts +1 -1
- package/dist/.pikku/analytics/pikku-analytics-types.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 +1 -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-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 +20 -2
- 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 +16 -16
- 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/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 +1 -1
- package/dist/.pikku/schemas/schemas/KnowledgePlanProgressOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/KnowledgePlanSetOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/KnowledgePlanShowOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
- package/dist/.pikku/scopes/index.d.ts +1 -1
- package/dist/.pikku/scopes/index.js +1 -1
- package/dist/.pikku/scopes/pikku-flags.gen.d.ts +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 +20 -2
- package/dist/src/deploy/analyzer/analyzer.js +7 -1
- package/dist/src/functions/commands/dev-credentials.d.ts +18 -0
- package/dist/src/functions/commands/dev-credentials.js +59 -0
- package/dist/src/functions/commands/dev.js +11 -2
- package/dist/src/functions/commands/install-addon.d.ts +45 -0
- package/dist/src/functions/commands/install-addon.js +225 -0
- package/dist/src/functions/commands/knowledge-plan.d.ts +9 -0
- package/dist/src/functions/commands/knowledge-plan.js +13 -3
- package/dist/src/functions/commands/new-addon.d.ts +47 -1
- package/dist/src/functions/commands/new-addon.js +284 -106
- package/dist/src/functions/commands/serve.js +7 -2
- package/dist/src/functions/db/better-auth-schema.d.ts +1 -0
- package/dist/src/functions/db/better-auth-schema.js +75 -2
- package/dist/src/functions/db/ensure-db-types.d.ts +12 -0
- package/dist/src/functions/db/ensure-db-types.js +29 -0
- package/dist/src/functions/knowledge/console-url.d.ts +13 -0
- package/dist/src/functions/knowledge/console-url.js +18 -0
- package/dist/src/functions/knowledge/render.d.ts +7 -3
- package/dist/src/functions/knowledge/render.js +10 -3
- package/dist/src/functions/knowledge/schemas.d.ts +3 -0
- package/dist/src/functions/knowledge/schemas.js +4 -3
- package/dist/src/functions/surface/collect-snippets.d.ts +1 -13
- package/dist/src/functions/surface/collect-snippets.js +1 -83
- package/dist/src/functions/validate/type-identity-checks.d.ts +3 -2
- package/dist/src/functions/validate/type-identity-checks.js +74 -5
- package/dist/src/functions/validate/validate-registry.js +3 -3
- package/dist/src/functions/wirings/auth/serialize-auth-gen.js +33 -1
- package/dist/src/functions/wirings/functions/serialize-addon-types.js +4 -2
- package/dist/src/functions/wirings/rpc/pikku-command-react-query.js +3 -2
- package/dist/src/functions/wirings/rpc/serialize-react-query-hooks.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/serialize-react-query-hooks.js +60 -3
- package/dist/src/functions/workflows/all.workflow.js +7 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/snippets-meta.json +1 -0
- package/snippets.json +1 -0
- package/surface.json +37 -3
- package/console-app/assets/architecture-7GRP2DOG-3y7bWtag.js +0 -1
- package/console-app/assets/channel-CTiluQVw.js +0 -1
- package/console-app/assets/chunk-XXDRQBXY-DBtYQykd.js +0 -1
- package/console-app/assets/classDiagram-ZZMXUADV-BnWa-i9n.js +0 -1
- package/console-app/assets/classDiagram-v2-VYDZK3BY-BnWa-i9n.js +0 -1
- package/console-app/assets/eventmodeling-NTZA5JFV-C_IpFSCw.js +0 -1
- package/console-app/assets/flowDiagram-HODETNUW-Q90rgVpx.js +0 -1
- package/console-app/assets/railroad-abnf-HS5TGJTU-CcPw9q8a.js +0 -1
- package/console-app/assets/railroad-ebnf-LZEXJU2U-Ci_fZics.js +0 -1
- package/console-app/assets/railroad-peg-WCYAUIDC-DTsDykSf.js +0 -1
- package/console-app/assets/stateDiagram-v2-MP3YSRHH--GM14Hz5.js +0 -1
- package/console-app/assets/swimlanesDiagram-VR7AAH4N-_6rRi6Wt.js +0 -8
|
@@ -5,7 +5,8 @@ import { spawnSync } from 'node:child_process';
|
|
|
5
5
|
import { findInstallRoot } from './update.js';
|
|
6
6
|
import { createEmptyManifest, saveManifest, } from '../../utils/contract-versions.js';
|
|
7
7
|
import { pikkuSessionlessFunc } from '#pikku/function';
|
|
8
|
-
import { parseOpenAPISpec, computeContractHash, generateAddonFromOpenAPI, loadAuthConfig, } from '@pikku/openapi-parser';
|
|
8
|
+
import { parseOpenAPISpec, computeContractHash, detectLoginOperation, filterOperations, generateAddonFromOpenAPI, loadAuthConfig, specCoverageWarning, } from '@pikku/openapi-parser';
|
|
9
|
+
import { installAddonIntoApp } from './install-addon.js';
|
|
9
10
|
/**
|
|
10
11
|
* Pick the protocol the generated test app uses to depend on its parent addon.
|
|
11
12
|
*
|
|
@@ -128,6 +129,27 @@ const literal = (value) => JSON.stringify(value);
|
|
|
128
129
|
const inTemplate = (value) => value.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
129
130
|
/** The same prose on a `//` comment line, where a newline ends the comment. */
|
|
130
131
|
const inComment = (value) => value.replace(/\s+/g, ' ').trim();
|
|
132
|
+
const CREDENTIAL_SHAPES = {
|
|
133
|
+
apikey: '{ apiKey: string }',
|
|
134
|
+
bearer: '{ token: string }',
|
|
135
|
+
basic: '{ username: string; password: string }',
|
|
136
|
+
};
|
|
137
|
+
const CREDENTIAL_FIELDS = { apikey: 'apiKey', bearer: 'token' };
|
|
138
|
+
const ICON_COLOURS = [
|
|
139
|
+
'#2563eb',
|
|
140
|
+
'#7c3aed',
|
|
141
|
+
'#db2777',
|
|
142
|
+
'#ea580c',
|
|
143
|
+
'#16a34a',
|
|
144
|
+
'#0891b2',
|
|
145
|
+
];
|
|
146
|
+
function placeholderIcon(displayName) {
|
|
147
|
+
const letter = (displayName.match(/[A-Za-z0-9]/)?.[0] ?? '?').toUpperCase();
|
|
148
|
+
const colour = ICON_COLOURS[[...displayName].reduce((sum, c) => sum + c.charCodeAt(0), 0) %
|
|
149
|
+
ICON_COLOURS.length];
|
|
150
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="${colour}"/><text x="32" y="43" font-family="system-ui, sans-serif" font-size="30" font-weight="600" fill="#fff" text-anchor="middle">${letter}</text></svg>
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
131
153
|
export function getAddonFiles(vars, flags) {
|
|
132
154
|
const { name, camelName, pascalName, screamingName, displayName, description, category, } = vars;
|
|
133
155
|
const files = {};
|
|
@@ -183,14 +205,15 @@ export function getAddonFiles(vars, flags) {
|
|
|
183
205
|
tsconfig: './tsconfig.json',
|
|
184
206
|
srcDirectories: ['src', 'types'],
|
|
185
207
|
outDir: './.pikku',
|
|
186
|
-
addon:
|
|
187
|
-
node: {
|
|
208
|
+
addon: {
|
|
188
209
|
displayName,
|
|
189
210
|
description,
|
|
190
211
|
categories: [category],
|
|
191
212
|
icon: `./${name}.svg`,
|
|
192
213
|
},
|
|
214
|
+
forceRequiredServices: [camelName],
|
|
193
215
|
}, null, 2);
|
|
216
|
+
files[`${name}.svg`] = placeholderIcon(displayName);
|
|
194
217
|
// tsconfig.json
|
|
195
218
|
files['tsconfig.json'] = JSON.stringify({
|
|
196
219
|
compilerOptions: {
|
|
@@ -222,7 +245,7 @@ ${description}
|
|
|
222
245
|
|
|
223
246
|
## Setup
|
|
224
247
|
|
|
225
|
-
1.
|
|
248
|
+
1. Replace the placeholder icon at \`${name}.svg\`
|
|
226
249
|
2. Update secret schema with required fields
|
|
227
250
|
3. Implement API service methods
|
|
228
251
|
4. Create function files for each operation
|
|
@@ -234,11 +257,7 @@ ${description}
|
|
|
234
257
|
// export { ${camelName}Operation } from './functions/operation.function.js'
|
|
235
258
|
`;
|
|
236
259
|
// src/services.ts
|
|
237
|
-
|
|
238
|
-
// Delegated login: the credential is the upstream token captured at
|
|
239
|
-
// sign-in; an expired token is the re-auth signal (UnauthorizedError).
|
|
240
|
-
files['src/services.ts'] =
|
|
241
|
-
`import { UnauthorizedError } from '@pikku/core/errors'
|
|
260
|
+
const wireCredential = (shape, check, missing, extra = '') => `import { ${missing.startsWith('new MissingCredentialError') ? 'MissingCredentialError' : 'CredentialRejectedError'} } from '@pikku/core/errors'
|
|
242
261
|
import { ${pascalName}Service } from './${name}-api.service.js'
|
|
243
262
|
import { pikkuAddonWireServices } from '#pikku/addon/setup'
|
|
244
263
|
|
|
@@ -247,67 +266,36 @@ export const createWireServices = pikkuAddonWireServices(
|
|
|
247
266
|
if (!wire.getCredential) {
|
|
248
267
|
throw new Error('Credential resolution is not available in this runtime')
|
|
249
268
|
}
|
|
250
|
-
const cred = await wire.getCredential
|
|
251
|
-
if (
|
|
252
|
-
throw
|
|
253
|
-
}
|
|
254
|
-
if (cred.expiresAt && cred.expiresAt * 1000 < Date.now()) {
|
|
255
|
-
throw new UnauthorizedError(${literal(`${displayName} session expired — sign in again`)})
|
|
256
|
-
}
|
|
269
|
+
const cred = await wire.getCredential<${shape}>('${camelName}')
|
|
270
|
+
if (!${check}) {
|
|
271
|
+
throw ${missing}
|
|
272
|
+
}${extra}
|
|
257
273
|
const ${camelName} = new ${pascalName}Service(cred, variables)
|
|
258
274
|
|
|
259
275
|
return { ${camelName} }
|
|
260
276
|
}
|
|
261
277
|
)
|
|
262
278
|
`;
|
|
279
|
+
if (flags.delegated) {
|
|
280
|
+
// Delegated login: the credential is the upstream token captured at
|
|
281
|
+
// sign-in, so a missing or expired one means signing in again.
|
|
282
|
+
files['src/services.ts'] = wireCredential('{ token: string; expiresAt?: number }', 'cred?.token', `new CredentialRejectedError('${camelName}', 'sign-in', ${literal(`No ${displayName} session — sign in again`)})`, `
|
|
283
|
+
if (cred.expiresAt && cred.expiresAt * 1000 < Date.now()) {
|
|
284
|
+
throw new CredentialRejectedError('${camelName}', 'sign-in', ${literal(`${displayName} session expired — sign in again`)})
|
|
285
|
+
}`);
|
|
263
286
|
}
|
|
264
287
|
else if (flags.credential && flags.credential !== 'oauth2') {
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
export const createWireServices = pikkuAddonWireServices(
|
|
272
|
-
async ({ variables }, wire) => {
|
|
273
|
-
if (!wire.getCredential) {
|
|
274
|
-
throw new Error('Credential resolution is not available in this runtime')
|
|
275
|
-
}
|
|
276
|
-
const cred = await wire.getCredential<{ ${credField}: string }>('${camelName}')
|
|
277
|
-
if (!cred?.${credField}) {
|
|
278
|
-
throw new Error('Missing ${camelName} credential')
|
|
279
|
-
}
|
|
280
|
-
const ${camelName} = new ${pascalName}Service(cred, variables)
|
|
281
|
-
|
|
282
|
-
return { ${camelName} }
|
|
283
|
-
}
|
|
284
|
-
)
|
|
285
|
-
`;
|
|
288
|
+
const shape = CREDENTIAL_SHAPES[flags.credential];
|
|
289
|
+
const field = flags.credential === 'basic'
|
|
290
|
+
? 'username'
|
|
291
|
+
: CREDENTIAL_FIELDS[flags.credential];
|
|
292
|
+
files['src/services.ts'] = wireCredential(shape, `cred?.${field}`, `new MissingCredentialError('${camelName}', 'apikey')`);
|
|
286
293
|
}
|
|
287
294
|
else if (flags.oauth || flags.credential === 'oauth2') {
|
|
288
295
|
// The OAuth2 access token is owned and refreshed by the platform credential
|
|
289
296
|
// service (better-auth). Resolve a ready token per-request via the wire and
|
|
290
297
|
// hand it to the service — the addon does not do its own token exchange.
|
|
291
|
-
files['src/services.ts'] =
|
|
292
|
-
`import { UnauthorizedError } from '@pikku/core/errors'
|
|
293
|
-
import { ${pascalName}Service } from './${name}-api.service.js'
|
|
294
|
-
import { pikkuAddonWireServices } from '#pikku/addon/setup'
|
|
295
|
-
|
|
296
|
-
export const createWireServices = pikkuAddonWireServices(
|
|
297
|
-
async ({ variables }, wire) => {
|
|
298
|
-
if (!wire.getCredential) {
|
|
299
|
-
throw new Error('Credential resolution is not available in this runtime')
|
|
300
|
-
}
|
|
301
|
-
const cred = await wire.getCredential<{ accessToken: string }>('${camelName}')
|
|
302
|
-
if (!cred?.accessToken) {
|
|
303
|
-
throw new UnauthorizedError(${literal(`No ${displayName} connection — connect ${displayName} first`)})
|
|
304
|
-
}
|
|
305
|
-
const ${camelName} = new ${pascalName}Service(cred, variables)
|
|
306
|
-
|
|
307
|
-
return { ${camelName} }
|
|
308
|
-
}
|
|
309
|
-
)
|
|
310
|
-
`;
|
|
298
|
+
files['src/services.ts'] = wireCredential('{ accessToken: string }', 'cred?.accessToken', `new MissingCredentialError('${camelName}', 'oauth2')`);
|
|
311
299
|
}
|
|
312
300
|
else if (flags.secret) {
|
|
313
301
|
files['src/services.ts'] =
|
|
@@ -317,24 +305,25 @@ import { pikkuAddonServices } from '#pikku/addon/setup'
|
|
|
317
305
|
|
|
318
306
|
export const createSingletonServices = pikkuAddonServices(async (
|
|
319
307
|
config,
|
|
320
|
-
{ secrets }
|
|
308
|
+
{ secrets, variables }
|
|
321
309
|
) => {
|
|
322
310
|
const creds = await secrets.getSecret<${pascalName}Secrets>('${screamingName}_CREDENTIALS')
|
|
323
|
-
const ${camelName} = new ${pascalName}Service(creds.reveal())
|
|
311
|
+
const ${camelName} = new ${pascalName}Service(creds.reveal(), variables)
|
|
324
312
|
|
|
325
313
|
return { ${camelName} }
|
|
326
314
|
})
|
|
327
315
|
`;
|
|
328
316
|
}
|
|
329
317
|
else {
|
|
330
|
-
// The plain service takes no constructor argument — the secret, credential
|
|
331
|
-
// and oauth variants are the ones handed something to authenticate with.
|
|
332
318
|
files['src/services.ts'] =
|
|
333
319
|
`import { ${pascalName}Service } from './${name}-api.service.js'
|
|
334
320
|
import { pikkuAddonServices } from '#pikku/addon/setup'
|
|
335
321
|
|
|
336
|
-
export const createSingletonServices = pikkuAddonServices(async (
|
|
337
|
-
|
|
322
|
+
export const createSingletonServices = pikkuAddonServices(async (
|
|
323
|
+
config,
|
|
324
|
+
{ variables }
|
|
325
|
+
) => {
|
|
326
|
+
const ${camelName} = new ${pascalName}Service(variables)
|
|
338
327
|
|
|
339
328
|
return { ${camelName} }
|
|
340
329
|
})
|
|
@@ -342,16 +331,16 @@ export const createSingletonServices = pikkuAddonServices(async () => {
|
|
|
342
331
|
}
|
|
343
332
|
// src/{name}-api.service.ts
|
|
344
333
|
if (flags.credential && flags.credential !== 'oauth2') {
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
: `this.creds.
|
|
350
|
-
|
|
351
|
-
? `'Authorization': ${authHeader},`
|
|
352
|
-
: `'Authorization': \`Bearer \${this.creds.apiKey}\`,`;
|
|
334
|
+
const credType = CREDENTIAL_SHAPES[flags.credential];
|
|
335
|
+
const authLine = {
|
|
336
|
+
bearer: `'Authorization': \`Bearer \${this.creds.token}\`,`,
|
|
337
|
+
apikey: `'Authorization': \`Bearer \${this.creds.apiKey}\`,`,
|
|
338
|
+
basic: `'Authorization': \`Basic \${btoa(\`\${this.creds.username}:\${this.creds.password}\`)}\`,`,
|
|
339
|
+
}[flags.credential];
|
|
353
340
|
files[`src/${name}-api.service.ts`] =
|
|
354
|
-
`
|
|
341
|
+
`import type { TypedVariablesService } from '#pikku/addon/variables/pikku-variables.gen.js'
|
|
342
|
+
|
|
343
|
+
const BASE_URL = 'https://api.example.com/v1'
|
|
355
344
|
|
|
356
345
|
export interface RequestOptions {
|
|
357
346
|
body?: unknown
|
|
@@ -359,7 +348,10 @@ export interface RequestOptions {
|
|
|
359
348
|
}
|
|
360
349
|
|
|
361
350
|
export class ${pascalName}Service {
|
|
362
|
-
constructor(
|
|
351
|
+
constructor(
|
|
352
|
+
private creds: ${credType},
|
|
353
|
+
_variables?: TypedVariablesService
|
|
354
|
+
) {}
|
|
363
355
|
|
|
364
356
|
async request<T>(
|
|
365
357
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
|
|
@@ -451,6 +443,7 @@ export class ${pascalName}Service {
|
|
|
451
443
|
else if (flags.secret) {
|
|
452
444
|
files[`src/${name}-api.service.ts`] =
|
|
453
445
|
`import type { ${pascalName}Secrets } from './${name}.secret.js'
|
|
446
|
+
import type { TypedVariablesService } from '#pikku/addon/variables/pikku-variables.gen.js'
|
|
454
447
|
|
|
455
448
|
const BASE_URL = 'https://api.example.com/v1'
|
|
456
449
|
|
|
@@ -460,7 +453,10 @@ export interface RequestOptions {
|
|
|
460
453
|
}
|
|
461
454
|
|
|
462
455
|
export class ${pascalName}Service {
|
|
463
|
-
constructor(
|
|
456
|
+
constructor(
|
|
457
|
+
private creds: ${pascalName}Secrets,
|
|
458
|
+
_variables?: TypedVariablesService
|
|
459
|
+
) {}
|
|
464
460
|
|
|
465
461
|
async request<T>(
|
|
466
462
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
|
|
@@ -498,7 +494,9 @@ export class ${pascalName}Service {
|
|
|
498
494
|
}
|
|
499
495
|
else {
|
|
500
496
|
files[`src/${name}-api.service.ts`] =
|
|
501
|
-
`
|
|
497
|
+
`import type { TypedVariablesService } from '#pikku/addon/variables/pikku-variables.gen.js'
|
|
498
|
+
|
|
499
|
+
const BASE_URL = 'https://api.example.com/v1'
|
|
502
500
|
|
|
503
501
|
export interface RequestOptions {
|
|
504
502
|
body?: unknown
|
|
@@ -506,6 +504,8 @@ export interface RequestOptions {
|
|
|
506
504
|
}
|
|
507
505
|
|
|
508
506
|
export class ${pascalName}Service {
|
|
507
|
+
constructor(_variables?: TypedVariablesService) {}
|
|
508
|
+
|
|
509
509
|
async request<T>(
|
|
510
510
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
|
|
511
511
|
endpoint: string,
|
|
@@ -580,6 +580,24 @@ export const ${camelName}CredentialSchema = z.object({
|
|
|
580
580
|
apiKey: z.string().describe(${literal(`${displayName} API key`)}),
|
|
581
581
|
})
|
|
582
582
|
|
|
583
|
+
defineCredential({
|
|
584
|
+
name: '${camelName}',
|
|
585
|
+
displayName: ${literal(displayName)},
|
|
586
|
+
description: ${literal(description)},
|
|
587
|
+
type: 'wire',
|
|
588
|
+
schema: ${camelName}CredentialSchema,
|
|
589
|
+
})
|
|
590
|
+
`;
|
|
591
|
+
}
|
|
592
|
+
else if (flags.credential === 'basic') {
|
|
593
|
+
files[`src/${name}.credential.ts`] = `import { z } from 'zod'
|
|
594
|
+
import { defineCredential } from '#pikku/addon/auth'
|
|
595
|
+
|
|
596
|
+
export const ${camelName}CredentialSchema = z.object({
|
|
597
|
+
username: z.string().describe(${literal(`${displayName} username`)}),
|
|
598
|
+
password: z.string().describe(${literal(`${displayName} password`)}),
|
|
599
|
+
})
|
|
600
|
+
|
|
583
601
|
defineCredential({
|
|
584
602
|
name: '${camelName}',
|
|
585
603
|
displayName: ${literal(displayName)},
|
|
@@ -926,8 +944,95 @@ export const buildGeneratedAddon = (addonDir, logger, run = spawnAddonBuildStep)
|
|
|
926
944
|
}
|
|
927
945
|
return true;
|
|
928
946
|
};
|
|
947
|
+
/**
|
|
948
|
+
* `string[]` options split on commas, which would cut a header value like
|
|
949
|
+
* `Accept: a, b` in two; a piece that does not start a new `Name:` rejoins the
|
|
950
|
+
* previous one.
|
|
951
|
+
*/
|
|
952
|
+
export function parseHeaderOptions(raw = []) {
|
|
953
|
+
const joined = [];
|
|
954
|
+
for (const piece of raw) {
|
|
955
|
+
if (/^[A-Za-z0-9!#$%&'*+.^_`|~-]+\s*:/.test(piece) || joined.length === 0) {
|
|
956
|
+
joined.push(piece);
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
joined[joined.length - 1] += `, ${piece}`;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
const headers = {};
|
|
963
|
+
for (const header of joined) {
|
|
964
|
+
const at = header.indexOf(':');
|
|
965
|
+
if (at <= 0) {
|
|
966
|
+
throw new Error(`--openapi-header "${header}" is not "Name: value"`);
|
|
967
|
+
}
|
|
968
|
+
headers[header.slice(0, at).trim()] = header.slice(at + 1).trim();
|
|
969
|
+
}
|
|
970
|
+
return headers;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* How the addon authenticates, from the flags first and the spec second.
|
|
974
|
+
* Per-user is the default for anything the spec can authenticate: each user
|
|
975
|
+
* acts upstream as themselves. `--auth shared` puts one secret behind every
|
|
976
|
+
* user; `--auth none` is for public APIs.
|
|
977
|
+
*/
|
|
978
|
+
export function resolveAddonAuth(spec, flags) {
|
|
979
|
+
if (flags.auth && !['user', 'shared', 'none'].includes(flags.auth)) {
|
|
980
|
+
throw new Error(`--auth must be user, shared or none (got "${flags.auth}")`);
|
|
981
|
+
}
|
|
982
|
+
if (flags.authConfig?.delegated) {
|
|
983
|
+
return {
|
|
984
|
+
mode: 'delegated',
|
|
985
|
+
credential: 'bearer',
|
|
986
|
+
secret: false,
|
|
987
|
+
oauth: false,
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
if (flags.auth === 'none') {
|
|
991
|
+
return { mode: 'none', secret: false, oauth: false };
|
|
992
|
+
}
|
|
993
|
+
if (flags.auth === 'shared' ||
|
|
994
|
+
(flags.secret && !flags.credential && !flags.oauth)) {
|
|
995
|
+
return { mode: 'shared', secret: true, oauth: false };
|
|
996
|
+
}
|
|
997
|
+
const explicit = flags.credential ?? (flags.oauth ? 'oauth2' : undefined);
|
|
998
|
+
const fromSpec = flags.authConfig?.headerName
|
|
999
|
+
? 'apikey'
|
|
1000
|
+
: {
|
|
1001
|
+
oauth2: 'oauth2',
|
|
1002
|
+
apiKey: 'apikey',
|
|
1003
|
+
bearer: 'bearer',
|
|
1004
|
+
basic: 'basic',
|
|
1005
|
+
none: undefined,
|
|
1006
|
+
}[spec.authType];
|
|
1007
|
+
const credential = (explicit ?? fromSpec);
|
|
1008
|
+
if (!credential) {
|
|
1009
|
+
throw new Error(`${spec.info.title} declares no security scheme, so the addon cannot tell how to authenticate. ` +
|
|
1010
|
+
'Pass --auth none for a public API, --credential apikey|bearer|basic|oauth2 for a per-user key, ' +
|
|
1011
|
+
'--auth shared for one key behind every user, or --auth-config <file> for a custom header or a delegated login (see pikku-build references/openapi.md).');
|
|
1012
|
+
}
|
|
1013
|
+
if (!['apikey', 'bearer', 'basic', 'oauth2'].includes(credential)) {
|
|
1014
|
+
throw new Error(`Invalid credential type "${credential}": must be one of apikey, bearer, basic, oauth2`);
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
mode: credential === 'oauth2' ? 'oauth2' : 'connect',
|
|
1018
|
+
credential,
|
|
1019
|
+
secret: false,
|
|
1020
|
+
oauth: credential === 'oauth2',
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
/** The project `pikku new addon` runs in, when it is an app rather than an addon. */
|
|
1024
|
+
function findAppProject(config) {
|
|
1025
|
+
const root = config?.rootDir;
|
|
1026
|
+
if (!root || config.addon || !existsSync(join(root, 'pikku.config.json'))) {
|
|
1027
|
+
return undefined;
|
|
1028
|
+
}
|
|
1029
|
+
const src = config.srcDirectories?.[0];
|
|
1030
|
+
if (!src)
|
|
1031
|
+
return undefined;
|
|
1032
|
+
return { root, srcDir: join(root, src) };
|
|
1033
|
+
}
|
|
929
1034
|
export const pikkuNewAddon = pikkuSessionlessFunc({
|
|
930
|
-
func: async ({ logger, config }, { name, displayName, description, category = 'General', dir, secret = false, variable = false, oauth = false, credential, test = true, openapi, authConfig, mcp = false, camelCase = false, build = true, }) => {
|
|
1035
|
+
func: async ({ logger, config }, { name, displayName, description, category = 'General', dir, secret = false, variable = false, oauth = false, credential, test = true, openapi, openapiHeader, tags, include, exclude, auth, install, authConfig, mcp = false, camelCase = false, build = true, }) => {
|
|
931
1036
|
name = sanitizeAddonName(name);
|
|
932
1037
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) {
|
|
933
1038
|
logger.error(`Invalid addon name "${name}": must start with a lowercase letter and contain only lowercase alphanumerics, hyphens, and underscores`);
|
|
@@ -936,8 +1041,19 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
|
|
|
936
1041
|
const pascalName = toPascalCase(name);
|
|
937
1042
|
const resolvedDisplayName = displayName || pascalName;
|
|
938
1043
|
const resolvedDescription = description || `${resolvedDisplayName} integration for Pikku`;
|
|
1044
|
+
const app = findAppProject(config);
|
|
1045
|
+
const installing = Boolean(openapi) && (install ?? Boolean(app));
|
|
1046
|
+
if (installing && !app) {
|
|
1047
|
+
logger.error('--install needs to run inside a pikku app (a pikku.config.json that is not an addon)');
|
|
1048
|
+
process.exit(1);
|
|
1049
|
+
}
|
|
939
1050
|
// Resolve target directory
|
|
940
|
-
const
|
|
1051
|
+
const workspacePackages = app ? join(app.root, 'packages') : undefined;
|
|
1052
|
+
const baseDir = dir ||
|
|
1053
|
+
config.scaffold?.addonDir ||
|
|
1054
|
+
(installing && workspacePackages && existsSync(workspacePackages)
|
|
1055
|
+
? workspacePackages
|
|
1056
|
+
: process.cwd());
|
|
941
1057
|
// Folder mirrors the package name (@pikku/addon-<name>) so a packages/
|
|
942
1058
|
// listing reads as packages/addon-<name>, distinct from app workspaces.
|
|
943
1059
|
const addonDir = join(baseDir, `addon-${name}`);
|
|
@@ -955,53 +1071,88 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
|
|
|
955
1071
|
category,
|
|
956
1072
|
addonDepProtocol: resolveAddonDepProtocol(baseDir),
|
|
957
1073
|
};
|
|
958
|
-
// Load the auth config (custom auth header / delegated login overrides)
|
|
959
1074
|
let loadedAuthConfig;
|
|
960
1075
|
if (authConfig) {
|
|
961
1076
|
loadedAuthConfig = await loadAuthConfig(authConfig);
|
|
962
|
-
if (loadedAuthConfig.delegated) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1077
|
+
if (loadedAuthConfig.delegated && credential && credential !== 'bearer') {
|
|
1078
|
+
logger.error(`--auth-config with delegated login stores the upstream token per user, so it cannot be combined with --credential ${credential}`);
|
|
1079
|
+
process.exit(1);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
let spec;
|
|
1083
|
+
let resolved;
|
|
1084
|
+
try {
|
|
1085
|
+
if (openapi) {
|
|
1086
|
+
spec = await parseOpenAPISpec(openapi, {
|
|
1087
|
+
headers: parseHeaderOptions(openapiHeader),
|
|
1088
|
+
});
|
|
1089
|
+
const total = spec.operations.length;
|
|
1090
|
+
spec = filterOperations(spec, { tags, include, exclude });
|
|
1091
|
+
if (spec.operations.length === 0) {
|
|
1092
|
+
throw new Error(`No operations left out of ${total} after --tags/--include/--exclude`);
|
|
1093
|
+
}
|
|
1094
|
+
const warning = specCoverageWarning(spec);
|
|
1095
|
+
if (warning) {
|
|
1096
|
+
logger.warn(`\n⚠️ ${warning}\n`);
|
|
968
1097
|
}
|
|
969
|
-
|
|
1098
|
+
resolved = resolveAddonAuth(spec, {
|
|
1099
|
+
auth,
|
|
1100
|
+
credential,
|
|
1101
|
+
oauth,
|
|
1102
|
+
secret,
|
|
1103
|
+
authConfig: loadedAuthConfig,
|
|
1104
|
+
});
|
|
1105
|
+
const login = detectLoginOperation(spec);
|
|
1106
|
+
if (login && resolved.mode !== 'delegated') {
|
|
1107
|
+
logger.info(`${spec.info.title} has a login route (${login.method.toUpperCase()} ${login.path}). To let users sign in to the app with their ${resolvedDisplayName} account, pass --auth-config with a "delegated" block (see pikku-build references/openapi.md).`);
|
|
1108
|
+
}
|
|
1109
|
+
logger.info(`${spec.operations.length} operations, auth: ${resolved.mode}${resolved.credential ? ` (${resolved.credential})` : ''}`);
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
const credentialType = credential;
|
|
1113
|
+
if (credentialType &&
|
|
1114
|
+
!['apikey', 'bearer', 'basic', 'oauth2'].includes(credentialType)) {
|
|
1115
|
+
throw new Error(`Invalid credential type "${credential}": must be one of apikey, bearer, basic, oauth2`);
|
|
1116
|
+
}
|
|
1117
|
+
const effectiveOAuth = oauth || credentialType === 'oauth2';
|
|
1118
|
+
resolved = {
|
|
1119
|
+
mode: effectiveOAuth
|
|
1120
|
+
? 'oauth2'
|
|
1121
|
+
: credentialType
|
|
1122
|
+
? 'connect'
|
|
1123
|
+
: secret
|
|
1124
|
+
? 'shared'
|
|
1125
|
+
: 'none',
|
|
1126
|
+
credential: loadedAuthConfig?.delegated ? 'bearer' : credentialType,
|
|
1127
|
+
secret: (secret || effectiveOAuth) && !credentialType,
|
|
1128
|
+
oauth: effectiveOAuth,
|
|
1129
|
+
};
|
|
1130
|
+
if (loadedAuthConfig?.delegated)
|
|
1131
|
+
resolved.mode = 'delegated';
|
|
970
1132
|
}
|
|
971
1133
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
if (credentialType &&
|
|
975
|
-
!['apikey', 'bearer', 'oauth2'].includes(credentialType)) {
|
|
976
|
-
logger.error(`Invalid credential type "${credential}": must be one of apikey, bearer, oauth2`);
|
|
1134
|
+
catch (error) {
|
|
1135
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
977
1136
|
process.exit(1);
|
|
978
1137
|
}
|
|
979
|
-
// oauth implies secret (unless credential flag is used); credential oauth2 implies oauth
|
|
980
|
-
const effectiveOAuth = oauth || credentialType === 'oauth2';
|
|
981
1138
|
const addonFiles = getAddonFiles(vars, {
|
|
982
|
-
secret:
|
|
1139
|
+
secret: resolved.secret,
|
|
983
1140
|
variable,
|
|
984
|
-
oauth:
|
|
985
|
-
credential:
|
|
986
|
-
delegated:
|
|
1141
|
+
oauth: resolved.oauth,
|
|
1142
|
+
credential: resolved.credential,
|
|
1143
|
+
delegated: resolved.mode === 'delegated',
|
|
987
1144
|
});
|
|
988
|
-
|
|
989
|
-
if (openapi) {
|
|
990
|
-
const spec = await parseOpenAPISpec(openapi);
|
|
1145
|
+
if (spec) {
|
|
991
1146
|
const openapiFiles = generateAddonFromOpenAPI(spec, vars, {
|
|
992
|
-
oauth:
|
|
993
|
-
secret:
|
|
994
|
-
credential:
|
|
1147
|
+
oauth: resolved.oauth,
|
|
1148
|
+
secret: resolved.secret,
|
|
1149
|
+
credential: resolved.credential,
|
|
995
1150
|
mcp,
|
|
996
1151
|
camelCase,
|
|
997
1152
|
authConfig: loadedAuthConfig,
|
|
998
1153
|
});
|
|
999
1154
|
Object.assign(addonFiles, openapiFiles);
|
|
1000
|
-
// Inject openapi metadata into pikku.config.json
|
|
1001
1155
|
const config = JSON.parse(addonFiles['pikku.config.json']);
|
|
1002
|
-
if (typeof config.addon === 'boolean' || !config.addon) {
|
|
1003
|
-
config.addon = {};
|
|
1004
|
-
}
|
|
1005
1156
|
config.addon.openapi = {
|
|
1006
1157
|
version: spec.info.version,
|
|
1007
1158
|
hash: computeContractHash(spec),
|
|
@@ -1024,6 +1175,33 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
|
|
|
1024
1175
|
for (const f of written) {
|
|
1025
1176
|
logger.debug({ message: ` ${f}`, type: 'success' });
|
|
1026
1177
|
}
|
|
1178
|
+
if (installing && app && spec) {
|
|
1179
|
+
const functions = Object.fromEntries(Object.entries(addonFiles)
|
|
1180
|
+
.filter(([path]) => /^src\/functions\/[^/]+\.function\.ts$/.test(path))
|
|
1181
|
+
.map(([path, source]) => [
|
|
1182
|
+
path.slice('src/functions/'.length, -'.function.ts'.length),
|
|
1183
|
+
source,
|
|
1184
|
+
]));
|
|
1185
|
+
const baseUrl = spec.serverUrls.find((url) => /^https?:\/\//.test(url));
|
|
1186
|
+
const { written: installed, notes } = installAddonIntoApp({
|
|
1187
|
+
projectRoot: app.root,
|
|
1188
|
+
srcDir: app.srcDir,
|
|
1189
|
+
name,
|
|
1190
|
+
camelName: vars.camelName,
|
|
1191
|
+
pascalName,
|
|
1192
|
+
screamingName: vars.screamingName,
|
|
1193
|
+
packageName: `@pikku/addon-${name}`,
|
|
1194
|
+
addonDir,
|
|
1195
|
+
inWorkspace: workspaceCovers(app.root, addonDir),
|
|
1196
|
+
mode: resolved.mode,
|
|
1197
|
+
functions,
|
|
1198
|
+
baseUrl: baseUrl?.replace(/\/+$/, ''),
|
|
1199
|
+
});
|
|
1200
|
+
for (const f of installed)
|
|
1201
|
+
logger.info(` updated ${f}`);
|
|
1202
|
+
for (const note of notes)
|
|
1203
|
+
logger.warn(note);
|
|
1204
|
+
}
|
|
1027
1205
|
if (build && !buildGeneratedAddon(addonDir, logger)) {
|
|
1028
1206
|
process.exit(1);
|
|
1029
1207
|
}
|
|
@@ -180,8 +180,13 @@ export const serve = pikkuSessionlessFunc({
|
|
|
180
180
|
? await resolveFrontendMount(config.frontend)
|
|
181
181
|
: undefined;
|
|
182
182
|
// The console goes first so a frontend mounted at `/` cannot claim
|
|
183
|
-
// `/console` before the console's own mount is offered the request
|
|
184
|
-
|
|
183
|
+
// `/console` before the console's own mount is offered the request, and
|
|
184
|
+
// the app's own mounts are kept ahead of the catch-all frontend.
|
|
185
|
+
const staticMounts = [
|
|
186
|
+
...(consoleMount ? [consoleMount] : []),
|
|
187
|
+
...(userConfig.staticMounts ?? []),
|
|
188
|
+
...(frontendMount ? [frontendMount] : []),
|
|
189
|
+
];
|
|
185
190
|
const pikkuServer = devServerRunner.createServer({
|
|
186
191
|
...userConfig,
|
|
187
192
|
hostname: bindHostname,
|
|
@@ -12,6 +12,7 @@ export interface GetMigrationsResult {
|
|
|
12
12
|
runMigrations: () => Promise<void>;
|
|
13
13
|
compileMigrations: () => Promise<string>;
|
|
14
14
|
}
|
|
15
|
+
export declare function withoutAuthSchemaCheck<DB>(kysely: Kysely<DB>): Kysely<DB>;
|
|
15
16
|
export declare function loadAuthOptions(opts: {
|
|
16
17
|
rootDir: string;
|
|
17
18
|
srcDirectories: string[];
|