@pikku/cli 0.12.96 → 0.12.99
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/abnfDiagram-VRR7QNED-CytV-CG1.js +1 -0
- package/console-app/assets/arc-C5PvmnaA.js +1 -0
- package/console-app/assets/architecture-TIHT7OUA-C1_ScvPX.js +1 -0
- package/console-app/assets/architectureDiagram-ZJ3FMSHR-CJ2xb7C-.js +36 -0
- package/console-app/assets/array-BifhSqXX.js +1 -0
- package/console-app/assets/blockDiagram-677ZJIJ3-CCecrBrk.js +132 -0
- package/console-app/assets/c4Diagram-LMCZKHZV-CBnpukvQ.js +10 -0
- package/console-app/assets/channel-CwDOkXGI.js +1 -0
- package/console-app/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/console-app/assets/chunk-32BRIVSS-D8qWWZRQ.js +1 -0
- package/console-app/assets/chunk-52WLFC77-BEpXHMsp.js +10 -0
- package/console-app/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/console-app/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- package/console-app/assets/chunk-C7G6YPKG-DsHUMkOp.js +1 -0
- package/console-app/assets/chunk-EX3LRPZG-mM7TjVx9.js +231 -0
- package/console-app/assets/chunk-FWX5IMBZ-CndRAn18.js +2 -0
- package/console-app/assets/chunk-HOUHSVGY-D1kT8umn.js +1 -0
- package/console-app/assets/chunk-ICXQ74PX-CeSaGyro.js +2 -0
- package/console-app/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/console-app/assets/chunk-KEIR6QF5-DNzq6p3w.js +161 -0
- package/console-app/assets/chunk-MOJQB5TN-CaZOCHYr.js +88 -0
- package/console-app/assets/chunk-OGEWGWER-CnB1CsPt.js +1 -0
- package/console-app/assets/chunk-PUDLZKDR-BbGulHJm.js +156 -0
- package/console-app/assets/chunk-Q4XR5HBZ-BywwzeeR.js +70 -0
- package/console-app/assets/chunk-RYQCIY6F-CV0R1Adv.js +1 -0
- package/console-app/assets/chunk-V7JOEXUC-DGFaAWzB.js +206 -0
- package/console-app/assets/chunk-VAUOI2AC-DxPUd8Yb.js +1 -0
- package/console-app/assets/chunk-VR4S4FIN-D4-UaW_J.js +1 -0
- package/console-app/assets/chunk-WYO6CB5R-D_TFN0d9.js +127 -0
- package/console-app/assets/chunk-XXDRQBXY-BzVuweA_.js +1 -0
- package/console-app/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/console-app/assets/chunk-ZGVPDNZ5-C6hdkGQb.js +62 -0
- package/console-app/assets/chunk-ZIRB5QZD-H-kepumB.js +32 -0
- package/console-app/assets/classDiagram-OUVF2IWQ-CTYJkTT0.js +1 -0
- package/console-app/assets/classDiagram-v2-EOCWNBFH-CTYJkTT0.js +1 -0
- package/console-app/assets/cose-bilkent-JH36ORCC-B6ZPxN6v.js +1 -0
- package/console-app/assets/cynefin-VYW2F7L2-D_nmxNz_.js +1 -0
- package/console-app/assets/cynefinDiagram-TSTJHNR4-CHy5QN0S.js +62 -0
- package/console-app/assets/cytoscape.esm-h6BdjjI9.js +321 -0
- package/console-app/assets/dagre-CXRCoUWR.js +1 -0
- package/console-app/assets/dagre-VKFMJZFB-DYfukM34.js +4 -0
- package/console-app/assets/defaultLocale-C8Fc0cco.js +1 -0
- package/console-app/assets/diagram-FQU43EPY-Dgb9TPSB.js +3 -0
- package/console-app/assets/diagram-G47NLZAW-CnFNZs9Z.js +24 -0
- package/console-app/assets/diagram-NH7WQ7WH-DN7h2DU-.js +24 -0
- package/console-app/assets/diagram-OA4YK3LP-RLaQaNtK.js +30 -0
- package/console-app/assets/diagram-WEI45ONY-DxHWhVGd.js +41 -0
- package/console-app/assets/dist-BaJNIo4I.js +1 -0
- package/console-app/assets/ebnfDiagram-CCIWWBDH-UN3Z81-l.js +1 -0
- package/console-app/assets/erDiagram-Q63AITRT-C9lGAY3i.js +85 -0
- package/console-app/assets/eventmodeling-45OFAUF4-Dc5wNSSK.js +1 -0
- package/console-app/assets/flowDiagram-23GEKE2U-zPyGHMi4.js +1 -0
- package/console-app/assets/ganttDiagram-NO4QXBWP-CvBjBcdK.js +292 -0
- package/console-app/assets/gitGraph-TEB2WS4Q-Cs5Z9jMo.js +1 -0
- package/console-app/assets/gitGraphDiagram-IHSO6WYX-B0i_IJ5r.js +106 -0
- package/console-app/assets/graphlib-B8gBHxth.js +1 -0
- package/console-app/assets/{index-CeQodYfg.js → index-71U8EEj7.js} +155 -153
- package/console-app/assets/{index-CyYHTGWZ.css → index-BXMjqLQ5.css} +1 -1
- package/console-app/assets/info-DKCQHKI2-DHL0afNl.js +1 -0
- package/console-app/assets/infoDiagram-FWYZ7A6U-CBWykodX.js +2 -0
- package/console-app/assets/init-D6jRqBbL.js +1 -0
- package/console-app/assets/ishikawaDiagram-FXEZZL3T-DM377eW_.js +70 -0
- package/console-app/assets/journeyDiagram-5HDEW3XC-BpX_-Cns.js +139 -0
- package/console-app/assets/kanban-definition-HUTT4EX6-D3xFsQkO.js +89 -0
- package/console-app/assets/katex-Vhh-h91d.js +257 -0
- package/console-app/assets/line-CTSKHTE0.js +1 -0
- package/console-app/assets/linear-R5GlBvXT.js +1 -0
- package/console-app/assets/map-DsCK-0Cs.js +1 -0
- package/console-app/assets/mermaid-parser.core-CkHk4BPi.js +7 -0
- package/console-app/assets/mermaid.core-CcjGXuV6.js +11 -0
- package/console-app/assets/mindmap-definition-LN4V7U3C-CtolazqQ.js +96 -0
- package/console-app/assets/ordinal-hYBb2elL.js +1 -0
- package/console-app/assets/packet-7NZHBO7P-BxSOj_Ny.js +1 -0
- package/console-app/assets/path-BWPyau1x.js +1 -0
- package/console-app/assets/pegDiagram-2B236MQR-BNsMtxsM.js +1 -0
- package/console-app/assets/pie-RZYD4A2V-BbkKQBA5.js +1 -0
- package/console-app/assets/pieDiagram-ENE6RG2P-BAZLIz2f.js +39 -0
- package/console-app/assets/quadrantDiagram-ABIIQ3AL-Dpvn-1Fs.js +7 -0
- package/console-app/assets/radar-I7S5WNFK-B-uKXIAH.js +1 -0
- package/console-app/assets/railroad-3IZDKUUU-BHXXK04t.js +1 -0
- package/console-app/assets/railroad-abnf-AHOZXSZD-tXSQaBvY.js +1 -0
- package/console-app/assets/railroad-ebnf-EBAXGLYW-DG3aohR0.js +1 -0
- package/console-app/assets/railroad-peg-LSFZ7HO6-DY_gBA-x.js +1 -0
- package/console-app/assets/railroadDiagram-RFXS5EU6-DfUApEQj.js +1 -0
- package/console-app/assets/requirementDiagram-TGXJPOKE-B2zX0jqo.js +84 -0
- package/console-app/assets/rough.esm-CSKSodPl.js +1 -0
- package/console-app/assets/sankeyDiagram-HTMAVEWB-CbQ2zc7z.js +40 -0
- package/console-app/assets/sequenceDiagram-DBY2YBRQ-BLT8PXI_.js +162 -0
- package/console-app/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- package/console-app/assets/src-BLuPUFWW.js +1 -0
- package/console-app/assets/stateDiagram-2N3HPSRC-BvEyVp85.js +1 -0
- package/console-app/assets/stateDiagram-v2-6OUMAXLB-RGKS9iU4.js +1 -0
- package/console-app/assets/swimlanes-5IMT3BWC-1AZ459s6.js +2 -0
- package/console-app/assets/swimlanesDiagram-G3AALYLV-Ck_0-rfN.js +8 -0
- package/console-app/assets/timeline-definition-FHXFAJF6-dLuvH4s2.js +120 -0
- package/console-app/assets/treeView-QDETBFTQ-xL2msjo2.js +1 -0
- package/console-app/assets/treemap-6X3UGDF4-C98ichVP.js +1 -0
- package/console-app/assets/vennDiagram-L72KCM5P-HbUmidhv.js +34 -0
- package/console-app/assets/wardley-OPB4EBWU-C4gJS-m2.js +1 -0
- package/console-app/assets/wardleyDiagram-EHGQE667-B7b-LB02.js +78 -0
- package/console-app/assets/xychartDiagram-FW5EYKEG-Cm03zUGy.js +7 -0
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/auth/auth.types.d.ts +1 -1
- package/dist/.pikku/auth/auth.types.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/pikku-cli-channel.js +1 -6
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +36 -9
- 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 +7 -8
- 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 +18 -2
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +12 -6
- 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 +39 -30
- package/dist/.pikku/function/pikku-functions.gen.js +3 -3
- 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/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-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-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +2 -1
- package/dist/.pikku/pikku-services.gen.js +1 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.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 -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-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/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 +3 -3
- package/dist/.pikku/schemas/schemas/DbResetInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/{DbSeedInput.schema.json → PikkuVirtualUserFunctionsOutput.schema.json} +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/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/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.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/meta/allWorkflow.gen.json +20 -14
- package/dist/.pikku/workflow/pikku-personas.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +6 -6
- 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 +8 -7
- package/dist/src/fabric/functions/validate.function.js +76 -176
- package/dist/src/functions/commands/all.d.ts +1 -1
- package/dist/src/functions/commands/bootstrap.d.ts +1 -1
- package/dist/src/functions/commands/db-audit.js +1 -1
- package/dist/src/functions/commands/db-baseline.js +1 -1
- package/dist/src/functions/commands/db-check.js +6 -5
- package/dist/src/functions/commands/db-codegen.js +1 -1
- package/dist/src/functions/commands/db-generate.js +1 -1
- package/dist/src/functions/commands/db-migrate.js +1 -1
- package/dist/src/functions/commands/db-reset.d.ts +15 -1
- package/dist/src/functions/commands/db-reset.js +18 -6
- package/dist/src/functions/commands/db-shared.d.ts +14 -0
- package/dist/src/functions/commands/deploy-info.d.ts +1 -1
- package/dist/src/functions/commands/dev.js +1 -1
- package/dist/src/functions/commands/enable.d.ts +8 -8
- package/dist/src/functions/commands/new-addon.js +2 -2
- package/dist/src/functions/commands/persona-sync.d.ts +1 -1
- package/dist/src/functions/commands/persona-sync.js +1 -1
- package/dist/src/functions/commands/persona.js +16 -18
- package/dist/src/functions/commands/scenario-ladder.js +1 -1
- package/dist/src/functions/commands/scenario.js +4 -2
- package/dist/src/functions/commands/scopes-shared.d.ts +4 -0
- package/dist/src/functions/commands/scopes-shared.js +1 -1
- package/dist/src/functions/commands/serve.js +1 -1
- package/dist/src/functions/commands/versions-check.js +3 -3
- package/dist/src/functions/db/annotation-parser.d.ts +14 -0
- package/dist/src/functions/db/annotation-parser.js +50 -2
- package/dist/src/functions/db/better-auth-schema.js +2 -1
- package/dist/src/functions/db/db-codegen.d.ts +12 -0
- package/dist/src/functions/db/db-codegen.js +149 -16
- package/dist/src/functions/db/local-db.d.ts +87 -6
- package/dist/src/functions/db/local-db.js +202 -35
- package/dist/src/functions/db/sqlite/dev-seed.d.ts +12 -0
- package/dist/src/functions/db/sqlite/dev-seed.js +23 -0
- package/dist/src/functions/db/sqlite/sqlite-runtime-bun.js +1 -1
- package/dist/src/functions/validate/bootstrap-checks.d.ts +19 -0
- package/dist/src/functions/validate/bootstrap-checks.js +90 -0
- package/dist/src/functions/validate/persona-checks.d.ts +24 -0
- package/dist/src/functions/validate/persona-checks.js +136 -0
- package/dist/src/functions/validate/scenario-file-checks.d.ts +17 -0
- package/dist/src/functions/validate/scenario-file-checks.js +123 -0
- package/dist/src/functions/validate/shared-checks.d.ts +59 -0
- package/dist/src/functions/validate/shared-checks.js +311 -0
- package/dist/src/functions/validate/workspace-validate.d.ts +1 -2
- package/dist/src/functions/validate/workspace-validate.js +4 -196
- package/dist/src/functions/wirings/auth/serialize-auth-gen.js +16 -1
- package/dist/src/functions/wirings/auth/serialize-auth-types.d.ts +3 -1
- package/dist/src/functions/wirings/auth/serialize-auth-types.js +3 -1
- package/dist/src/functions/wirings/channels/pikku-channels.d.ts +1 -1
- package/dist/src/functions/wirings/channels/serialize-typed-channel-map.js +10 -2
- package/dist/src/functions/wirings/cli/pikku-command-cli-entry.js +9 -4
- package/dist/src/functions/wirings/cli/serialize-channel-cli-client.js +32 -10
- package/dist/src/functions/wirings/cli/serialize-cli-entrypoint-guard.d.ts +12 -0
- package/dist/src/functions/wirings/cli/serialize-cli-entrypoint-guard.js +28 -0
- package/dist/src/functions/wirings/cli/serialize-local-cli-bootstrap.js +4 -1
- package/dist/src/functions/wirings/console/serialize-console-functions.js +1 -1
- package/dist/src/functions/wirings/functions/serialize-addon-types.js +1 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +19 -5
- package/dist/src/functions/wirings/package/pikku-command-package-types.d.ts +3 -3
- package/dist/src/functions/wirings/personas/personas-secrets-file.d.ts +8 -0
- package/dist/src/functions/wirings/personas/personas-secrets-file.js +9 -0
- package/dist/src/functions/wirings/personas/pikku-command-personas.js +14 -0
- package/dist/src/functions/wirings/personas/serialize-personas-secrets.d.ts +16 -0
- package/dist/src/functions/wirings/personas/serialize-personas-secrets.js +34 -0
- package/dist/src/functions/wirings/queue/serialize-queue-map.js +2 -1
- package/dist/src/functions/wirings/queue/serialize-queue-wrapper.js +2 -1
- package/dist/src/functions/wirings/virtual-user/pikku-command-virtual-user-functions.d.ts +1 -0
- package/dist/src/functions/wirings/virtual-user/pikku-command-virtual-user-functions.js +42 -0
- package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.d.ts +28 -0
- package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.js +439 -0
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +2 -2
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +5 -11
- package/dist/src/functions/workflows/all.workflow.js +49 -16
- package/dist/src/server/bun-server-runner.d.ts +2 -2
- package/dist/src/server/bun-server-runner.js +5 -1
- package/dist/src/services/cli-logger.service.d.ts +28 -16
- package/dist/src/services/cli-logger.service.js +25 -16
- package/dist/src/services.js +8 -0
- package/dist/src/utils/file-import-path.js +9 -0
- package/dist/src/utils/pikku-cli-config.js +7 -0
- package/dist/src/utils/resolve-personas.d.ts +4 -9
- package/dist/src/utils/resolve-personas.js +4 -15
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/dist/.pikku/schemas/schemas/BootstrapInput.schema.json +0 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +0 -1
- package/dist/src/functions/commands/db-seed.d.ts +0 -1
- package/dist/src/functions/commands/db-seed.js +0 -24
- package/dist/src/functions/db/sqlite/seed.d.ts +0 -11
- package/dist/src/functions/db/sqlite/seed.js +0 -22
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export { readJsonSafe, readTextSafe } from './shared-checks.js';
|
|
2
3
|
export declare const FindingSchema: z.ZodObject<{
|
|
3
4
|
id: z.ZodString;
|
|
4
5
|
severity: z.ZodEnum<{
|
|
@@ -28,7 +29,5 @@ export declare const WorkspaceValidateOutput: z.ZodObject<{
|
|
|
28
29
|
}, z.core.$strip>>;
|
|
29
30
|
}, z.core.$strip>;
|
|
30
31
|
export declare function findProjectRoot(startDir: string): Promise<string>;
|
|
31
|
-
export declare function readJsonSafe<T>(path: string): Promise<T | null>;
|
|
32
|
-
export declare function readTextSafe(path: string): Promise<string | null>;
|
|
33
32
|
export declare function runWorkspaceValidate(startDir?: string): Promise<z.infer<typeof WorkspaceValidateOutput>>;
|
|
34
33
|
export declare const renderWorkspaceValidate: (_s: unknown, { ok, root, findings }: z.infer<typeof WorkspaceValidateOutput>) => void;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { added, changed, dim, removed } from '../../fabric/lib/output.js';
|
|
6
|
+
import { runSharedProjectChecks } from './shared-checks.js';
|
|
7
|
+
export { readJsonSafe, readTextSafe } from './shared-checks.js';
|
|
6
8
|
export const FindingSchema = z.object({
|
|
7
9
|
id: z.string(),
|
|
8
10
|
severity: z.enum(['error', 'warn', 'info']),
|
|
@@ -35,203 +37,9 @@ export async function findProjectRoot(startDir) {
|
|
|
35
37
|
dir = parent;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
|
-
export async function readJsonSafe(path) {
|
|
39
|
-
if (!existsSync(path))
|
|
40
|
-
return null;
|
|
41
|
-
try {
|
|
42
|
-
return JSON.parse(await readFile(path, 'utf8'));
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
-
throw new Error(`Invalid JSON in ${path}: ${message}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export async function readTextSafe(path) {
|
|
50
|
-
if (!existsSync(path))
|
|
51
|
-
return null;
|
|
52
|
-
try {
|
|
53
|
-
return await readFile(path, 'utf8');
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async function hasAuthSessionMiddleware(fnDir) {
|
|
60
|
-
const metaPath = join(fnDir, '.pikku', 'middleware', 'pikku-middleware-groups-meta.gen.json');
|
|
61
|
-
const meta = await readJsonSafe(metaPath);
|
|
62
|
-
if (!meta?.instances)
|
|
63
|
-
return false;
|
|
64
|
-
return Object.values(meta.instances).some((instance) => instance.definitionId === 'betterAuthSession');
|
|
65
|
-
}
|
|
66
|
-
function migrationCreatesTable(sql, tableName) {
|
|
67
|
-
const escapedTable = tableName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
68
|
-
const re = new RegExp(`\\bcreate\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?["'\`]?${escapedTable}["'\`]?\\b`, 'i');
|
|
69
|
-
return re.test(sql);
|
|
70
|
-
}
|
|
71
40
|
export async function runWorkspaceValidate(startDir = process.cwd()) {
|
|
72
41
|
const root = await findProjectRoot(startDir);
|
|
73
|
-
const findings =
|
|
74
|
-
const e = (id, message, path, fixHint) => {
|
|
75
|
-
findings.push({ id, severity: 'error', message, path, fixHint });
|
|
76
|
-
};
|
|
77
|
-
const w = (id, message, path, fixHint) => {
|
|
78
|
-
findings.push({ id, severity: 'warn', message, path, fixHint });
|
|
79
|
-
};
|
|
80
|
-
const info = (id, message, path, fixHint) => {
|
|
81
|
-
findings.push({ id, severity: 'info', message, path, fixHint });
|
|
82
|
-
};
|
|
83
|
-
const pikkuConfigPath = join(root, 'pikku.config.json');
|
|
84
|
-
const pikkuConfig = await readJsonSafe(pikkuConfigPath);
|
|
85
|
-
if (!pikkuConfig) {
|
|
86
|
-
e('pikku-config-missing', 'pikku.config.json not found at project root', pikkuConfigPath, 'Create pikku.config.json with srcDirectories pointing to packages/functions/src, outDir, and clientFiles');
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
if (!pikkuConfig.srcDirectories) {
|
|
90
|
-
e('pikku-config-no-src-dirs', 'pikku.config.json missing "srcDirectories"', pikkuConfigPath, 'Add "srcDirectories": ["packages/functions/src"] to pikku.config.json');
|
|
91
|
-
}
|
|
92
|
-
if (!pikkuConfig.outDir) {
|
|
93
|
-
e('pikku-config-no-out-dir', 'pikku.config.json missing "outDir"', pikkuConfigPath, 'Add "outDir": "packages/functions/.pikku" to pikku.config.json');
|
|
94
|
-
}
|
|
95
|
-
if (!pikkuConfig.clientFiles) {
|
|
96
|
-
info('pikku-config-no-client-files', 'pikku.config.json missing "clientFiles" — generated RPC client files and React Query hooks will not be written', pikkuConfigPath, 'Add clientFiles.rpcMapDeclarationFile and clientFiles.reactQueryFile pointing to packages/functions-sdk/src/pikku/ (for example: rpc-map.gen.d.ts and api.gen.ts)');
|
|
97
|
-
}
|
|
98
|
-
const scaffold = pikkuConfig.scaffold;
|
|
99
|
-
if (!scaffold?.console) {
|
|
100
|
-
e('pikku-config-no-console-scaffold', 'pikku.config.json missing "scaffold.console" — Fabric cannot introspect the running app (console:getFunctionsMeta and friends 404), so the sandbox builder shows no functions', pikkuConfigPath, 'Add "console": true under "scaffold" in pikku.config.json — the console requires an authenticated session, so Better Auth must be set up (see the pikku-better-auth skill)');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
const rootPkgPath = join(root, 'package.json');
|
|
104
|
-
const rootPkg = await readJsonSafe(rootPkgPath);
|
|
105
|
-
if (!rootPkg) {
|
|
106
|
-
e('root-package-missing', 'root package.json not found', rootPkgPath, 'Create a root package.json with workspaces: {"workspaces": ["packages/*", "apps/*"]}');
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
if (!rootPkg.workspaces) {
|
|
110
|
-
w('root-package-no-workspaces', 'root package.json missing "workspaces"', rootPkgPath, 'Add "workspaces": ["packages/*", "apps/*"] to enable yarn workspaces');
|
|
111
|
-
}
|
|
112
|
-
const allDeps = {
|
|
113
|
-
...rootPkg.dependencies,
|
|
114
|
-
...rootPkg.devDependencies,
|
|
115
|
-
};
|
|
116
|
-
if (!allDeps['@pikku/core']) {
|
|
117
|
-
e('missing-core', '@pikku/core not in dependencies', rootPkgPath, 'Add "@pikku/core" to dependencies');
|
|
118
|
-
}
|
|
119
|
-
for (const [pkg, spec] of Object.entries(allDeps)) {
|
|
120
|
-
if (typeof spec !== 'string' || !spec.startsWith('file:'))
|
|
121
|
-
continue;
|
|
122
|
-
const relPath = spec.slice(5);
|
|
123
|
-
if (!relPath.includes('vendor'))
|
|
124
|
-
continue;
|
|
125
|
-
const absPath = join(root, relPath);
|
|
126
|
-
if (!existsSync(absPath)) {
|
|
127
|
-
w(`vendor-missing-${pkg.replace(/[@/]/g, '-')}`, `Vendor file missing for ${pkg}: ${relPath}`, absPath, `Restore or replace the missing vendor package at ${relPath}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const fnDir = join(root, 'packages', 'functions');
|
|
132
|
-
if (!existsSync(fnDir)) {
|
|
133
|
-
e('functions-pkg-missing', 'packages/functions/ directory not found', fnDir, 'Create packages/functions/ as a workspace containing src/, tests/, config.ts, and any local db assets you use');
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
const fnPkgPath = join(fnDir, 'package.json');
|
|
137
|
-
const fnPkg = await readJsonSafe(fnPkgPath);
|
|
138
|
-
if (!fnPkg) {
|
|
139
|
-
e('functions-package-json-missing', 'packages/functions/package.json not found', fnPkgPath, 'Create packages/functions/package.json and declare the workspace package');
|
|
140
|
-
}
|
|
141
|
-
else if (fnPkg.type !== 'module') {
|
|
142
|
-
w('functions-pkg-no-esm', 'packages/functions/package.json is missing "type": "module"', fnPkgPath, 'Add "type": "module" to packages/functions/package.json');
|
|
143
|
-
}
|
|
144
|
-
// zod v4 must be installed in the functions package: pikku's generated
|
|
145
|
-
// schemas and the auth scaffold (auth-secrets.gen.ts) both `import { z }
|
|
146
|
-
// from 'zod'`, so a missing/old zod fails codegen (PKU489) or type-checks.
|
|
147
|
-
if (fnPkg) {
|
|
148
|
-
const fnDeps = { ...fnPkg.dependencies, ...fnPkg.devDependencies };
|
|
149
|
-
const zodRange = fnDeps.zod;
|
|
150
|
-
const zodMajor = zodRange?.match(/(\d+)/)?.[1];
|
|
151
|
-
if (!zodRange) {
|
|
152
|
-
e('functions-missing-zod', 'packages/functions/package.json does not declare "zod" — pikku schemas and the generated auth scaffold import it', fnPkgPath, 'Add "zod": "^4" to packages/functions dependencies');
|
|
153
|
-
}
|
|
154
|
-
else if (zodMajor !== '4') {
|
|
155
|
-
e('functions-zod-not-v4', `packages/functions requires zod v4 but found "${zodRange}"`, fnPkgPath, 'Set "zod": "^4" in packages/functions dependencies');
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const servicesPath = join(fnDir, 'src', 'services.ts');
|
|
159
|
-
const servicesText = await readTextSafe(servicesPath);
|
|
160
|
-
if (!servicesText) {
|
|
161
|
-
w('services-missing', 'packages/functions/src/services.ts not found', servicesPath, 'Create services.ts and export your service factory for the workspace');
|
|
162
|
-
}
|
|
163
|
-
const authEnabled = await hasAuthSessionMiddleware(fnDir);
|
|
164
|
-
const configText = await readTextSafe(join(fnDir, 'src', 'config.ts'));
|
|
165
|
-
const hasConfiguredDevDb = /sqliteDb/.test(configText ?? '');
|
|
166
|
-
const hasPostgresUrl = /postgresUrl/.test(configText ?? '');
|
|
167
|
-
const migrationsDir = hasPostgresUrl
|
|
168
|
-
? join(fnDir, 'db', 'postgres')
|
|
169
|
-
: join(fnDir, 'db', 'sqlite');
|
|
170
|
-
let createsAppUser = false;
|
|
171
|
-
let createsAuthVerificationToken = false;
|
|
172
|
-
if (existsSync(migrationsDir)) {
|
|
173
|
-
try {
|
|
174
|
-
const files = (await readdir(migrationsDir))
|
|
175
|
-
.filter((f) => f.endsWith('.sql'))
|
|
176
|
-
.sort();
|
|
177
|
-
const nums = [];
|
|
178
|
-
for (const f of files) {
|
|
179
|
-
const m = f.match(/^(\d+)/);
|
|
180
|
-
if (m)
|
|
181
|
-
nums.push(parseInt(m[1], 10));
|
|
182
|
-
}
|
|
183
|
-
for (let idx = 1; idx < nums.length; idx++) {
|
|
184
|
-
if (nums[idx] !== nums[idx - 1] + 1) {
|
|
185
|
-
const missing = `${nums[idx - 1] + 1}..${nums[idx] - 1}`;
|
|
186
|
-
e('migration-gap', `Migration numbering gap: IDs ${missing} are missing`, migrationsDir, 'Migrations must be consecutive. Add the missing .sql file or renumber if not yet applied.');
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
for (const f of files) {
|
|
191
|
-
const sql = await readTextSafe(join(migrationsDir, f));
|
|
192
|
-
if (!sql)
|
|
193
|
-
continue;
|
|
194
|
-
createsAppUser ||= migrationCreatesTable(sql, 'app_user');
|
|
195
|
-
createsAuthVerificationToken ||= migrationCreatesTable(sql, 'auth_verification_token');
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
// readdir failure — skip
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (authEnabled && !hasConfiguredDevDb) {
|
|
203
|
-
e('auth-dev-db-missing', 'Auth middleware is registered, but createConfig is missing sqliteDb so local auth schema validation and db migrate cannot run', pikkuConfigPath, 'Add sqliteDb to createConfig so `pikku db migrate` can create and validate the local auth schema');
|
|
204
|
-
}
|
|
205
|
-
if (authEnabled && !createsAppUser) {
|
|
206
|
-
e('auth-schema-missing-app-user', 'Auth middleware is registered, but no SQL migration creates the app_user table', migrationsDir, 'Add a migration that creates app_user before enabling auth');
|
|
207
|
-
}
|
|
208
|
-
if (authEnabled && !createsAuthVerificationToken) {
|
|
209
|
-
e('auth-schema-missing-verification-token', 'Auth middleware is registered, but no SQL migration creates the auth_verification_token table', migrationsDir, 'Add a migration that creates auth_verification_token before enabling auth');
|
|
210
|
-
}
|
|
211
|
-
const dbTypesPath = join(fnDir, 'src', 'types', 'db.types.ts');
|
|
212
|
-
const dbTypesText = await readTextSafe(dbTypesPath);
|
|
213
|
-
if (dbTypesText) {
|
|
214
|
-
const isReexport = dbTypesText.includes('.pikku/db/schema') ||
|
|
215
|
-
dbTypesText.includes('.pikku\\db\\schema');
|
|
216
|
-
const hasInlineTypes = /(?:^|\n)\s*(?:export\s+)?(?:interface\s+\w|type\s+\w+\s*=)/.test(dbTypesText);
|
|
217
|
-
if (hasInlineTypes && !isReexport) {
|
|
218
|
-
w('db-types-hand-edited', 'src/types/db.types.ts contains inline type definitions — it should only re-export from .pikku', dbTypesPath, "Replace the file with a single line: export type { DB } from '../../.pikku/db/schema.gen.js' then regenerate");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (!existsSync(join(fnDir, 'src', 'functions'))) {
|
|
222
|
-
info('functions-dir-missing', 'packages/functions/src/functions/ not found', join(fnDir, 'src', 'functions'), 'Create src/functions/ to hold pikkuSessionlessFunc definitions');
|
|
223
|
-
}
|
|
224
|
-
if (!existsSync(join(fnDir, 'src', 'wirings'))) {
|
|
225
|
-
info('wirings-dir-missing', 'packages/functions/src/wirings/ not found', join(fnDir, 'src', 'wirings'), 'Create src/wirings/ for transport bindings such as *.http.ts or *.queue.ts');
|
|
226
|
-
}
|
|
227
|
-
if (!existsSync(join(fnDir, 'src', 'config.ts'))) {
|
|
228
|
-
info('config-missing', 'packages/functions/src/config.ts not found', join(fnDir, 'src', 'config.ts'), 'Create src/config.ts and export your workspace config factory');
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const sdkDir = join(root, 'packages', 'functions-sdk');
|
|
232
|
-
if (!existsSync(sdkDir)) {
|
|
233
|
-
info('functions-sdk-missing', 'packages/functions-sdk/ not found — generated RPC client and React Query hooks will not be available', sdkDir, 'Create packages/functions-sdk/ as a workspace with src/pikku/ as the generated output root; point clientFiles.rpcMapDeclarationFile and clientFiles.reactQueryFile there');
|
|
234
|
-
}
|
|
42
|
+
const { findings } = await runSharedProjectChecks(root);
|
|
235
43
|
const ok = !findings.some((f) => f.severity === 'error');
|
|
236
44
|
return { ok, root, findings };
|
|
237
45
|
}
|
|
@@ -40,11 +40,26 @@ function variableSchemaName(name, field) {
|
|
|
40
40
|
// addHTTPMiddleware('*') call as the session middleware: the inspector keys
|
|
41
41
|
// route-middleware groups by pattern, so a second '*' registration from another
|
|
42
42
|
// file would silently displace this one in deployed units.
|
|
43
|
+
//
|
|
44
|
+
// The session carries the two scope roots the console addon gates itself on.
|
|
45
|
+
// Without them this token authenticates but authorizes nothing: `wireAddon`
|
|
46
|
+
// gates the whole addon on `admin`, so every console:* RPC — reads included —
|
|
47
|
+
// answers MissingScopeError, and an external console can reach the deployment
|
|
48
|
+
// while being unable to do a single thing in it.
|
|
49
|
+
//
|
|
50
|
+
// Roots rather than a wildcard: a parent grant satisfies its children, so
|
|
51
|
+
// `admin` covers `admin:*` and `pikku` covers `pikku:scopes:*`/`pikku:audit:*`,
|
|
52
|
+
// which is every scope the console's own functions require. A `*` would also
|
|
53
|
+
// hand the token every scope the HOST app declares, which is authority the
|
|
54
|
+
// console never asks for.
|
|
43
55
|
const consoleTokenMiddlewareLines = () => [
|
|
44
56
|
` authBearer({`,
|
|
45
57
|
` token: {`,
|
|
46
58
|
` secretId: 'PIKKU_CONSOLE_TOKEN',`,
|
|
47
|
-
` userSession: {
|
|
59
|
+
` userSession: {`,
|
|
60
|
+
` userId: 'pikku-console-token',`,
|
|
61
|
+
` scopes: ['admin', 'pikku'],`,
|
|
62
|
+
` },`,
|
|
48
63
|
` },`,
|
|
49
64
|
` }),`,
|
|
50
65
|
];
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
* them at runtime — the same treatment addon services get from
|
|
17
17
|
* `pikkuAddonServices`. That gives the factory typed, map-aware access:
|
|
18
18
|
*
|
|
19
|
-
* socialProviders: {
|
|
19
|
+
* socialProviders: {
|
|
20
|
+
* github: (await secrets.getSecret('GITHUB_OAUTH')).reveal(),
|
|
21
|
+
* }
|
|
20
22
|
*
|
|
21
23
|
* with no inline `getSecrets<{ ... }>()` generic, because the secret types flow
|
|
22
24
|
* from the generated `CredentialsMap`.
|
|
@@ -17,7 +17,9 @@ import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
|
17
17
|
* them at runtime — the same treatment addon services get from
|
|
18
18
|
* `pikkuAddonServices`. That gives the factory typed, map-aware access:
|
|
19
19
|
*
|
|
20
|
-
* socialProviders: {
|
|
20
|
+
* socialProviders: {
|
|
21
|
+
* github: (await secrets.getSecret('GITHUB_OAUTH')).reveal(),
|
|
22
|
+
* }
|
|
21
23
|
*
|
|
22
24
|
* with no inline `getSecrets<{ ... }>()` generic, because the secret types flow
|
|
23
25
|
* from the generated `CredentialsMap`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const pikkuChannels: import("#pikku").
|
|
1
|
+
export declare const pikkuChannels: import("#pikku").PikkuFunctionSessionlessConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|
|
@@ -109,15 +109,23 @@ function generateChannels(logger, typesMap, functionsMeta, addonFunctions, chann
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* A route or message key that is not a bare identifier has to be quoted to be
|
|
114
|
+
* a legal property name. Channel routes are author-chosen strings and a CLI
|
|
115
|
+
* channel's are command ids, where `app-smoke` and `registry.search` are the
|
|
116
|
+
* norm — unquoted, each one ends the property early and the whole map fails
|
|
117
|
+
* to parse. Quoted only when it has to be, so existing output is unchanged.
|
|
118
|
+
*/
|
|
119
|
+
const propertyKey = (key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : `'${key}'`;
|
|
112
120
|
let routesStr = 'export type ChannelsMap = {\n';
|
|
113
121
|
for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
|
|
114
122
|
routesStr += ` readonly '${channelPath}': {\n`;
|
|
115
123
|
// Add `routes` object
|
|
116
124
|
routesStr += ` readonly routes: {\n`;
|
|
117
125
|
for (const [key, methods] of Object.entries(routes)) {
|
|
118
|
-
routesStr += ` readonly ${key}: {\n`;
|
|
126
|
+
routesStr += ` readonly ${propertyKey(key)}: {\n`;
|
|
119
127
|
for (const [method, handler] of Object.entries(methods)) {
|
|
120
|
-
routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
|
|
128
|
+
routesStr += ` readonly ${propertyKey(method)}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
|
|
121
129
|
}
|
|
122
130
|
routesStr += ' },\n';
|
|
123
131
|
}
|
|
@@ -64,15 +64,20 @@ export const pikkuCLIEntry = pikkuSessionlessFunc({
|
|
|
64
64
|
// Generate client code if clientPath is provided
|
|
65
65
|
if (channelClientPath) {
|
|
66
66
|
const channelClientFile = join(config.rootDir, channelClientPath);
|
|
67
|
-
//
|
|
67
|
+
// A renderer for a CLI-over-channel program runs on the client, where
|
|
68
|
+
// there is no service container to resolve from — the only thing the
|
|
69
|
+
// runtime can hand it is a logger. Anything else it destructures
|
|
70
|
+
// would be undefined at runtime, so it fails generation instead.
|
|
68
71
|
const rendererNames = collectRendererNames(programMeta);
|
|
69
72
|
const problematicRenderers = [];
|
|
70
73
|
for (const rendererName of rendererNames) {
|
|
71
74
|
const rendererMeta = visitState.cli.meta.renderers[rendererName];
|
|
72
|
-
|
|
75
|
+
const services = rendererMeta?.services?.services ?? [];
|
|
76
|
+
const unavailable = services.filter((name) => name !== 'logger');
|
|
77
|
+
if (unavailable.length > 0) {
|
|
73
78
|
problematicRenderers.push({
|
|
74
79
|
name: rendererName,
|
|
75
|
-
services:
|
|
80
|
+
services: unavailable,
|
|
76
81
|
});
|
|
77
82
|
}
|
|
78
83
|
}
|
|
@@ -81,7 +86,7 @@ export const pikkuCLIEntry = pikkuSessionlessFunc({
|
|
|
81
86
|
const details = problematicRenderers
|
|
82
87
|
.map((r) => ` - ${r.name} depends on: ${r.services.join(', ')}`)
|
|
83
88
|
.join('\n');
|
|
84
|
-
logger.critical(ErrorCode.CLI_CLIENTSIDE_RENDERER_HAS_SERVICES, `Cannot generate CLI channel client for '${programName}':
|
|
89
|
+
logger.critical(ErrorCode.CLI_CLIENTSIDE_RENDERER_HAS_SERVICES, `Cannot generate CLI channel client for '${programName}': a renderer reached for a service that does not exist on the client\n${details}\n\nRenderers in a CLI-over-channel program run on the client side of the socket, where the only available service is 'logger'.`);
|
|
85
90
|
// Delete existing client file if it exists
|
|
86
91
|
if (existsSync(channelClientFile)) {
|
|
87
92
|
await rm(channelClientFile);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
2
|
+
import { DIRECT_EXECUTION_GUARD } from './serialize-cli-entrypoint-guard.js';
|
|
2
3
|
/**
|
|
3
4
|
* Collect all unique renderer names from CLI metadata (populated by inspector)
|
|
4
5
|
*/
|
|
@@ -107,10 +108,11 @@ export function serializeChannelCLIClient(programName, programMeta, clientFile,
|
|
|
107
108
|
? resolveRendererBinding(programMeta.defaultRenderName, renderersMeta)
|
|
108
109
|
: null;
|
|
109
110
|
const defaultRendererCode = defaultRendererBinding
|
|
110
|
-
? `,\n defaultRenderer: ${defaultRendererBinding}
|
|
111
|
+
? `,\n defaultRenderer: ${defaultRendererBinding} as CorePikkuCLIClientRender<any>`
|
|
111
112
|
: '';
|
|
112
113
|
return `
|
|
113
114
|
import { executeRawCLIViaChannel } from '@pikku/core/cli/channel'
|
|
115
|
+
import type { CorePikkuCLIClientRender } from '@pikku/core/cli/channel'
|
|
114
116
|
import type { Capabilities } from '@pikku/core/channel'
|
|
115
117
|
import { CorePikkuWebsocket } from '@pikku/websocket'
|
|
116
118
|
${rendererImports}
|
|
@@ -136,8 +138,12 @@ export async function ${capitalizedName}CLIClient(
|
|
|
136
138
|
// Create Pikku WebSocket wrapper
|
|
137
139
|
const pikkuWS = new CorePikkuWebsocket(ws)
|
|
138
140
|
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
+
// Renderers are declared against this app's \`SingletonServices\`, but on this
|
|
142
|
+
// side of the socket the only service that exists is a logger. The cast is
|
|
143
|
+
// sound because generation refuses to emit this file at all when a renderer
|
|
144
|
+
// reaches for anything else — see CLI_CLIENTSIDE_RENDERER_HAS_SERVICES. It is
|
|
145
|
+
// localised here so \`executeRawCLIViaChannel\` can keep an honest signature.
|
|
146
|
+
const renderers = ${renderersMap} as Record<string, CorePikkuCLIClientRender<any>>
|
|
141
147
|
|
|
142
148
|
return executeRawCLIViaChannel({
|
|
143
149
|
pikkuWS,
|
|
@@ -151,15 +157,17 @@ export async function ${capitalizedName}CLIClient(
|
|
|
151
157
|
export default ${capitalizedName}CLIClient
|
|
152
158
|
|
|
153
159
|
// For direct execution (if this file is run directly)
|
|
154
|
-
|
|
160
|
+
${DIRECT_EXECUTION_GUARD}
|
|
161
|
+
|
|
162
|
+
if (isDirectExecution) {
|
|
155
163
|
const url = process.env.PIKKU_WS_URL || 'ws://localhost:4002${finalChannelRoute}'
|
|
156
164
|
|
|
157
165
|
// Attach credentials so the channel authenticates like any other pikku client.
|
|
158
166
|
// A machine API key (PIKKU_API_KEY -> x-api-key) takes precedence; otherwise
|
|
159
167
|
// the human session token saved by \`pikku login\` (~/.pikku/session.json ->
|
|
160
|
-
// Authorization: Bearer) is used. This block only runs
|
|
161
|
-
// execution), so reading the session file
|
|
162
|
-
//
|
|
168
|
+
// Authorization: Bearer) is used. This block only runs on a server runtime
|
|
169
|
+
// (direct execution), so reading the session file is safe — a browser could
|
|
170
|
+
// neither reach it nor set custom headers on its WebSocket.
|
|
163
171
|
const headers: Record<string, string> = {}
|
|
164
172
|
if (process.env.PIKKU_API_KEY) {
|
|
165
173
|
headers['x-api-key'] = process.env.PIKKU_API_KEY
|
|
@@ -186,12 +194,26 @@ if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
|
186
194
|
}
|
|
187
195
|
const hasAuth = Object.keys(headers).length > 0
|
|
188
196
|
|
|
189
|
-
//
|
|
190
|
-
//
|
|
197
|
+
// Node's global WebSocket reads its second argument as subprotocols and drops
|
|
198
|
+
// custom headers on the floor, so credentials there need the 'ws' module.
|
|
199
|
+
// Bun's honours them natively, and reaching for 'ws' under Bun would load its
|
|
200
|
+
// compatibility shim for nothing. Detected once, the way the CLI picks its
|
|
201
|
+
// dev-server runner.
|
|
202
|
+
const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined'
|
|
203
|
+
|
|
204
|
+
// Only the header-carrying Bun call needs the cast: the DOM lib types the
|
|
205
|
+
// second argument as subprotocols, which is what Node implements.
|
|
206
|
+
type WebSocketWithHeaders = new (
|
|
207
|
+
url: string,
|
|
208
|
+
options: { headers: Record<string, string> }
|
|
209
|
+
) => WebSocket
|
|
210
|
+
|
|
191
211
|
let ws: WebSocket
|
|
192
|
-
if (hasAuth || typeof WebSocket === 'undefined') {
|
|
212
|
+
if (!isBun && (hasAuth || typeof WebSocket === 'undefined')) {
|
|
193
213
|
const wsModule = await import('ws')
|
|
194
214
|
ws = new wsModule.default(url, { headers }) as unknown as WebSocket
|
|
215
|
+
} else if (hasAuth) {
|
|
216
|
+
ws = new (WebSocket as unknown as WebSocketWithHeaders)(url, { headers })
|
|
195
217
|
} else {
|
|
196
218
|
ws = new WebSocket(url)
|
|
197
219
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The snippet every generated CLI entrypoint uses to decide whether it is being
|
|
3
|
+
* run or merely imported. It declares `isDirectExecution`; the caller writes the
|
|
4
|
+
* `if`.
|
|
5
|
+
*
|
|
6
|
+
* `import.meta.url === \`file://${process.argv[1]}\`` — the shape this replaces —
|
|
7
|
+
* is false for any CLI invoked through a symlinked bin, because Node reports the
|
|
8
|
+
* symlink in argv and the realpath in the URL, so the block never ran for an
|
|
9
|
+
* installed `node_modules/.bin/<name>`. It also fails on paths the URL has to
|
|
10
|
+
* percent-encode, such as one containing a space.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DIRECT_EXECUTION_GUARD = "const isDirectExecution = await (async () => {\n if (typeof import.meta.main === 'boolean') {\n return import.meta.main\n }\n // Node exposes import.meta.main from 24.2; earlier 24.x compares realpaths,\n // which is what it is shorthand for.\n try {\n const { fileURLToPath } = await import('node:url')\n const { realpathSync } = await import('node:fs')\n return (\n process.argv[1] !== undefined &&\n realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)\n )\n } catch {\n return false\n }\n})()";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The snippet every generated CLI entrypoint uses to decide whether it is being
|
|
3
|
+
* run or merely imported. It declares `isDirectExecution`; the caller writes the
|
|
4
|
+
* `if`.
|
|
5
|
+
*
|
|
6
|
+
* `import.meta.url === \`file://${process.argv[1]}\`` — the shape this replaces —
|
|
7
|
+
* is false for any CLI invoked through a symlinked bin, because Node reports the
|
|
8
|
+
* symlink in argv and the realpath in the URL, so the block never ran for an
|
|
9
|
+
* installed `node_modules/.bin/<name>`. It also fails on paths the URL has to
|
|
10
|
+
* percent-encode, such as one containing a space.
|
|
11
|
+
*/
|
|
12
|
+
export const DIRECT_EXECUTION_GUARD = `const isDirectExecution = await (async () => {
|
|
13
|
+
if (typeof import.meta.main === 'boolean') {
|
|
14
|
+
return import.meta.main
|
|
15
|
+
}
|
|
16
|
+
// Node exposes import.meta.main from 24.2; earlier 24.x compares realpaths,
|
|
17
|
+
// which is what it is shorthand for.
|
|
18
|
+
try {
|
|
19
|
+
const { fileURLToPath } = await import('node:url')
|
|
20
|
+
const { realpathSync } = await import('node:fs')
|
|
21
|
+
return (
|
|
22
|
+
process.argv[1] !== undefined &&
|
|
23
|
+
realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
24
|
+
)
|
|
25
|
+
} catch {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
})()`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
2
|
+
import { DIRECT_EXECUTION_GUARD } from './serialize-cli-entrypoint-guard.js';
|
|
2
3
|
/**
|
|
3
4
|
* Serializes the local (in-program) CLI bootstrap code
|
|
4
5
|
*/
|
|
@@ -40,7 +41,9 @@ ${wireServicesFactory ? ' createWireServices,' : ''}
|
|
|
40
41
|
export default ${capitalizedName}CLI
|
|
41
42
|
|
|
42
43
|
// For direct execution (if this file is run directly)
|
|
43
|
-
|
|
44
|
+
${DIRECT_EXECUTION_GUARD}
|
|
45
|
+
|
|
46
|
+
if (isDirectExecution) {
|
|
44
47
|
${capitalizedName}CLI(process.argv.slice(2)).catch(error => {
|
|
45
48
|
console.error('Fatal error:', error.message)
|
|
46
49
|
process.exit(1)
|
|
@@ -115,7 +115,7 @@ export const pikkuConsoleGetSecret = pikkuFunc({
|
|
|
115
115
|
return { exists: false, value: null }
|
|
116
116
|
}
|
|
117
117
|
const value = await secrets.getSecret(secretId)
|
|
118
|
-
return { exists: true, value }
|
|
118
|
+
return { exists: true, value: value.reveal() }
|
|
119
119
|
},
|
|
120
120
|
})
|
|
121
121
|
|
|
@@ -53,7 +53,7 @@ export const pikkuAddonConfig = <ExistingServices extends Omit<Partial<Singleton
|
|
|
53
53
|
* { secrets }
|
|
54
54
|
* ) => {
|
|
55
55
|
* const creds = await secrets.getSecret<GithubCredentials>('GITHUB_CREDENTIALS')
|
|
56
|
-
* const github = new GithubService(creds)
|
|
56
|
+
* const github = new GithubService(creds.reveal())
|
|
57
57
|
* return { github }
|
|
58
58
|
* })
|
|
59
59
|
* \`\`\`
|
|
@@ -16,7 +16,7 @@ export const serializeFunctionTypes = (userSessionTypeImport, userSessionTypeNam
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { CorePikkuMiddleware, CorePermissionGroup, ListInput, ListOutput, PikkuWire, PickRequired, SecretlessServices, SecretService } from '@pikku/core'
|
|
19
|
-
import type { CorePikkuFunctionConfig, CorePikkuAuth, CorePikkuAuthConfig, CorePikkuPermission } from '@pikku/core/function'
|
|
19
|
+
import type { CorePikkuFunctionConfig, CorePikkuSessionlessFunctionConfig, CorePikkuAuth, CorePikkuAuthConfig, CorePikkuPermission } from '@pikku/core/function'
|
|
20
20
|
import { pikkuAuth as pikkuAuthCore } from '@pikku/core/function'
|
|
21
21
|
import {
|
|
22
22
|
addTagMiddleware as addTagMiddlewareCore,
|
|
@@ -358,6 +358,19 @@ export type PikkuFunctionConfig<
|
|
|
358
358
|
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
359
359
|
> = CorePikkuFunctionConfig<PikkuFunc, PikkuPermission<In>, PikkuMiddleware, InputSchema, OutputSchema, ScopeId>
|
|
360
360
|
|
|
361
|
+
/**
|
|
362
|
+
* {@link PikkuFunctionConfig} for a function that runs without a session.
|
|
363
|
+
* Has no \`scopes\`: an anonymous caller holds none, so none can ever be met.
|
|
364
|
+
*/
|
|
365
|
+
export type PikkuFunctionSessionlessConfig<
|
|
366
|
+
In = unknown,
|
|
367
|
+
Out = unknown,
|
|
368
|
+
RequiredWires extends keyof PikkuWire = never,
|
|
369
|
+
PikkuFunc extends PikkuFunctionSessionless<In, Out, RequiredWires, any> = PikkuFunctionSessionless<In, Out, RequiredWires>,
|
|
370
|
+
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
371
|
+
OutputSchema extends StandardSchemaV1 | undefined = undefined
|
|
372
|
+
> = CorePikkuSessionlessFunctionConfig<PikkuFunc, PikkuPermission<In>, PikkuMiddleware, InputSchema, OutputSchema>
|
|
373
|
+
|
|
361
374
|
/**
|
|
362
375
|
* Configuration object for Pikku functions with Zod schema validation.
|
|
363
376
|
* Use this when you want to define input/output schemas using Zod.
|
|
@@ -479,7 +492,8 @@ export const pikkuListFunc = <
|
|
|
479
492
|
*/
|
|
480
493
|
/**
|
|
481
494
|
* Schema-overload variant for pikkuSessionlessFunc. Derived from
|
|
482
|
-
*
|
|
495
|
+
* CorePikkuSessionlessFunctionConfig to stay in sync with the generic-typed
|
|
496
|
+
* config — so it has no \`scopes\` either.
|
|
483
497
|
*/
|
|
484
498
|
export type PikkuFunctionSessionlessConfigWithSchema<
|
|
485
499
|
InputSchema extends StandardSchemaV1 | undefined = undefined,
|
|
@@ -487,7 +501,7 @@ export type PikkuFunctionSessionlessConfigWithSchema<
|
|
|
487
501
|
RequiredWires extends keyof PikkuWire = never,
|
|
488
502
|
RequiredServices extends SecretlessServices<Services> = WiredServices
|
|
489
503
|
> = Omit<
|
|
490
|
-
|
|
504
|
+
CorePikkuSessionlessFunctionConfig<
|
|
491
505
|
PikkuFunctionSessionless<SchemaInferred<InputSchema>, SchemaInferred<OutputSchema>, RequiredWires, RequiredServices>
|
|
492
506
|
>,
|
|
493
507
|
'func' | 'input' | 'output' | 'permissions' | 'approvalDescription'
|
|
@@ -542,7 +556,7 @@ export function pikkuSessionlessFunc<
|
|
|
542
556
|
export function pikkuSessionlessFunc<In, Out = unknown, RequiredServices extends SecretlessServices<Services> = WiredServices>(
|
|
543
557
|
func:
|
|
544
558
|
| PikkuFunctionSessionless<In, Out, 'session' | 'rpc', RequiredServices>
|
|
545
|
-
|
|
|
559
|
+
| PikkuFunctionSessionlessConfig<In, Out, 'session' | 'rpc', PikkuFunctionSessionless<In, Out, 'session' | 'rpc', RequiredServices>>
|
|
546
560
|
): PikkuFunctionConfig<In, Out, 'session' | 'rpc'>
|
|
547
561
|
export function pikkuSessionlessFunc(func: any) {
|
|
548
562
|
return typeof func === 'function' ? { func } : func
|
|
@@ -567,7 +581,7 @@ export function pikkuSessionlessFunc(func: any) {
|
|
|
567
581
|
export const pikkuVoidFunc = (
|
|
568
582
|
func:
|
|
569
583
|
| PikkuFunctionSessionless<void, void, 'session' | 'rpc'>
|
|
570
|
-
|
|
|
584
|
+
| PikkuFunctionSessionlessConfig<void, void, 'session' | 'rpc'>
|
|
571
585
|
) => {
|
|
572
586
|
return typeof func === 'function' ? { func } : func
|
|
573
587
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const pikkuSecretDefinitionTypes: import("#pikku").
|
|
2
|
-
export declare const pikkuScopeDefinitionTypes: import("#pikku").
|
|
3
|
-
export declare const pikkuVariableDefinitionTypes: import("#pikku").
|
|
1
|
+
export declare const pikkuSecretDefinitionTypes: import("#pikku").PikkuFunctionSessionlessConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|
|
2
|
+
export declare const pikkuScopeDefinitionTypes: import("#pikku").PikkuFunctionSessionlessConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|
|
3
|
+
export declare const pikkuVariableDefinitionTypes: import("#pikku").PikkuFunctionSessionlessConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the generated `SCENARIO_ACTOR_SECRET` declaration lives — beside the
|
|
3
|
+
* personas file, like `auth-secrets.gen.ts` sits beside the auth scaffold.
|
|
4
|
+
*
|
|
5
|
+
* Shared with the inspector's scaffold-file list: nothing imports this file, so
|
|
6
|
+
* it is unreachable through the import graph and has to be inspected explicitly.
|
|
7
|
+
*/
|
|
8
|
+
export declare const personasSecretsFilePath: (personasFile: string) => string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { join, dirname } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Where the generated `SCENARIO_ACTOR_SECRET` declaration lives — beside the
|
|
4
|
+
* personas file, like `auth-secrets.gen.ts` sits beside the auth scaffold.
|
|
5
|
+
*
|
|
6
|
+
* Shared with the inspector's scaffold-file list: nothing imports this file, so
|
|
7
|
+
* it is unreachable through the import graph and has to be inspected explicitly.
|
|
8
|
+
*/
|
|
9
|
+
export const personasSecretsFilePath = (personasFile) => join(dirname(personasFile), 'pikku-personas-secrets.gen.ts');
|