@pikku/cli 0.12.90 → 0.12.92
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/LICENSE +106 -0
- package/README.md +25 -2
- package/console-app/assets/{index-CSzCJzBb.css → index-D0HG8q0B.css} +1 -1
- package/console-app/assets/{index-C5Bd44e4.js → index-DDpIMCpy.js} +149 -149
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +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 +6 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +15 -0
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +43 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +4 -4
- 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 -44
- package/dist/.pikku/function/pikku-functions.gen.js +1 -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 +9 -0
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +9 -0
- 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 +1 -1
- 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.d.ts +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +10 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.json +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.js +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.d.ts +1 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +10 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.js +1 -0
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +5 -3
- package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +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 +2 -8
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +19 -0
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +17 -0
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +152 -3
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +39 -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 +28 -0
- package/dist/src/deploy/analyzer/analyzer.js +22 -5
- package/dist/src/deploy/build-pipeline.js +5 -1
- package/dist/src/fabric/fabric-commands.d.ts +37 -9
- package/dist/src/fabric/fabric-commands.js +12 -0
- package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
- package/dist/src/fabric/functions/secrets-list.function.js +12 -10
- package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
- package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
- package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
- package/dist/src/fabric/functions/secrets-set.function.js +18 -7
- package/dist/src/fabric/lib/http.d.ts +7 -1
- package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
- package/dist/src/fabric/lib/sealed-box.js +72 -0
- package/dist/src/functions/commands/dev.js +11 -0
- package/dist/src/functions/commands/load-user-project.d.ts +7 -0
- package/dist/src/functions/commands/load-user-project.js +21 -0
- package/dist/src/functions/commands/pikku-command-bootstrap.js +13 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +84 -0
- package/dist/src/functions/commands/scenario-browser.js +68 -0
- package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
- package/dist/src/functions/commands/scenario-environment.js +61 -0
- package/dist/src/functions/commands/scenario-formatter.d.ts +81 -0
- package/dist/src/functions/commands/scenario-formatter.js +120 -0
- package/dist/src/functions/commands/scenario-ladder.d.ts +66 -0
- package/dist/src/functions/commands/scenario-ladder.js +132 -0
- package/dist/src/functions/commands/scenario-plan.d.ts +61 -0
- package/dist/src/functions/commands/scenario-plan.js +106 -0
- package/dist/src/functions/commands/scenario.d.ts +24 -0
- package/dist/src/functions/commands/scenario.js +322 -50
- package/dist/src/functions/commands/serve.js +2 -0
- package/dist/src/functions/commands/skills.js +27 -61
- package/dist/src/functions/db/db-codegen.d.ts +6 -0
- package/dist/src/functions/db/db-codegen.js +9 -0
- package/dist/src/functions/db/db-migrator.js +14 -0
- package/dist/src/functions/db/local-db.d.ts +8 -0
- package/dist/src/functions/db/local-db.js +24 -2
- package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
- package/dist/src/functions/db/migration-identifiers.js +262 -0
- package/dist/src/functions/db/migration-provenance.d.ts +35 -0
- package/dist/src/functions/db/migration-provenance.js +80 -0
- package/dist/src/functions/db/schema-sql.d.ts +43 -0
- package/dist/src/functions/db/schema-sql.js +135 -0
- package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
- package/dist/src/functions/wirings/functions/pikku-command-functions.js +26 -8
- package/dist/src/functions/wirings/functions/schemas.js +13 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +3 -3
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +42 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.js +71 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
- package/dist/src/functions/wirings/scenarios/serialize-feature-meta.d.ts +14 -0
- package/dist/src/functions/wirings/scenarios/serialize-feature-meta.js +29 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.d.ts +12 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.js +56 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.d.ts +7 -0
- package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.js +40 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +43 -8
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +13 -2
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.d.ts +4 -0
- package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +62 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-bootstrap-map.js +10 -3
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +10 -3
- package/dist/src/functions/wirings/workflow/serialize-workflow-meta.js +4 -4
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +232 -3
- package/dist/src/functions/workflows/all.workflow.js +2 -7
- package/dist/src/server/server-ready.d.ts +12 -0
- package/dist/src/server/server-ready.js +12 -0
- package/dist/src/server/spawn-dev-server.d.ts +50 -0
- package/dist/src/server/spawn-dev-server.js +112 -0
- package/dist/src/services.js +12 -1
- package/dist/src/utils/file-writer.js +14 -2
- package/dist/src/utils/meta-diff.js +5 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -0
- package/dist/src/utils/pikku-cli-config.js +60 -0
- package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
- package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
- package/dist/src/utils/resolve-scenario-actors.d.ts +23 -0
- package/dist/src/utils/resolve-scenario-actors.js +74 -0
- package/dist/src/utils/serialize-schemas.d.ts +3 -1
- package/dist/src/utils/serialize-schemas.js +39 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -8
- package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
- package/skills/pikku-addon/SKILL.md +0 -243
- package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
- package/skills/pikku-ai-agent/SKILL.md +0 -231
- package/skills/pikku-ai-vercel/SKILL.md +0 -82
- package/skills/pikku-ai-voice/SKILL.md +0 -88
- package/skills/pikku-audit/SKILL.md +0 -175
- package/skills/pikku-aws/SKILL.md +0 -111
- package/skills/pikku-backblaze/SKILL.md +0 -71
- package/skills/pikku-better-auth/SKILL.md +0 -298
- package/skills/pikku-cli/SKILL.md +0 -198
- package/skills/pikku-cli/references/complete-example.md +0 -82
- package/skills/pikku-concepts/SKILL.md +0 -250
- package/skills/pikku-concepts/references/concept-mapping.md +0 -556
- package/skills/pikku-concepts/references/packages.md +0 -29
- package/skills/pikku-config/SKILL.md +0 -212
- package/skills/pikku-cron/SKILL.md +0 -214
- package/skills/pikku-deploy-azure/SKILL.md +0 -71
- package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
- package/skills/pikku-deploy-express/SKILL.md +0 -86
- package/skills/pikku-deploy-fastify/SKILL.md +0 -73
- package/skills/pikku-deploy-lambda/SKILL.md +0 -110
- package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
- package/skills/pikku-deploy-uws/SKILL.md +0 -88
- package/skills/pikku-deps/SKILL.md +0 -98
- package/skills/pikku-emails/SKILL.md +0 -163
- package/skills/pikku-fabric/SKILL.md +0 -318
- package/skills/pikku-fabric-debug/SKILL.md +0 -112
- package/skills/pikku-feature/SKILL.md +0 -258
- package/skills/pikku-gateway-slack/SKILL.md +0 -115
- package/skills/pikku-http/SKILL.md +0 -220
- package/skills/pikku-http/references/http-options.md +0 -55
- package/skills/pikku-i18n/SKILL.md +0 -137
- package/skills/pikku-info/SKILL.md +0 -100
- package/skills/pikku-jose/SKILL.md +0 -105
- package/skills/pikku-kysely/SKILL.md +0 -219
- package/skills/pikku-machine-auth/SKILL.md +0 -183
- package/skills/pikku-mcp/SKILL.md +0 -241
- package/skills/pikku-middleware/SKILL.md +0 -231
- package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
- package/skills/pikku-mongodb/SKILL.md +0 -105
- package/skills/pikku-n8n-import/SKILL.md +0 -109
- package/skills/pikku-n8n-import/SPEC.md +0 -84
- package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
- package/skills/pikku-n8n-import/references/code-translation.md +0 -121
- package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
- package/skills/pikku-paraglide/SKILL.md +0 -117
- package/skills/pikku-permissions/SKILL.md +0 -192
- package/skills/pikku-pino/SKILL.md +0 -79
- package/skills/pikku-product-second-opinion/README.md +0 -43
- package/skills/pikku-product-second-opinion/SKILL.md +0 -158
- package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
- package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
- package/skills/pikku-queue/SKILL.md +0 -240
- package/skills/pikku-react/SKILL.md +0 -212
- package/skills/pikku-react-query/SKILL.md +0 -242
- package/skills/pikku-realtime/SKILL.md +0 -236
- package/skills/pikku-realtime/references/other-routes.md +0 -23
- package/skills/pikku-redis/SKILL.md +0 -90
- package/skills/pikku-rpc/SKILL.md +0 -171
- package/skills/pikku-rtl/SKILL.md +0 -219
- package/skills/pikku-scenario/SKILL.md +0 -215
- package/skills/pikku-schedule/SKILL.md +0 -57
- package/skills/pikku-schema-ajv/SKILL.md +0 -62
- package/skills/pikku-schema-cfworker/SKILL.md +0 -63
- package/skills/pikku-security/SKILL.md +0 -108
- package/skills/pikku-services/SKILL.md +0 -248
- package/skills/pikku-services/references/audit-wire-service.md +0 -34
- package/skills/pikku-software-archaeology/README.md +0 -70
- package/skills/pikku-software-archaeology/SKILL.md +0 -186
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
- package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
- package/skills/pikku-tag-middleware/SKILL.md +0 -13
- package/skills/pikku-template-clone/SKILL.md +0 -40
- package/skills/pikku-trigger/SKILL.md +0 -181
- package/skills/pikku-versioning/SKILL.md +0 -173
- package/skills/pikku-websocket/SKILL.md +0 -243
- package/skills/pikku-workflow/SKILL.md +0 -172
- package/skills/pikku-workflow/references/workflow-reference.md +0 -63
- package/skills/pikku-workflows-client/SKILL.md +0 -150
- package/skills/pikku-ws/SKILL.md +0 -47
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pikku-better-auth
|
|
3
|
-
description: >-
|
|
4
|
-
Use when integrating Better Auth with a Pikku app. Covers pikkuBetterAuth, betterAuth config,
|
|
5
|
-
the generated catch-all auth routes, betterAuthSession middleware, OAuth/social providers,
|
|
6
|
-
email+password credentials, database adapters, and session mapping. TRIGGER when: code uses
|
|
7
|
-
pikkuBetterAuth, betterAuth, betterAuthSession, createAuthHandler, user asks about Better Auth,
|
|
8
|
-
OAuth/social providers, MFA, organizations, login/logout, or @pikku/better-auth. TRIGGER when:
|
|
9
|
-
user asks about ANY form of authentication, login, logout, sessions, or user identity — always
|
|
10
|
-
answer with this skill. DO NOT TRIGGER when: user asks about JWT middleware (use pikku-security)
|
|
11
|
-
or custom session services (use pikku-services).
|
|
12
|
-
installGroups: [core]
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Pikku Better Auth Integration
|
|
16
|
-
|
|
17
|
-
## ⚠️ MANDATORY RULE — READ FIRST
|
|
18
|
-
|
|
19
|
-
**ALL authentication in Pikku apps MUST use `@pikku/better-auth`. No exceptions.**
|
|
20
|
-
|
|
21
|
-
- Do NOT write custom login/logout endpoints.
|
|
22
|
-
- Do NOT implement JWT signing/verification by hand.
|
|
23
|
-
- Do NOT build a custom session store.
|
|
24
|
-
- Do NOT use passport, jose, jsonwebtoken, or any other auth library directly.
|
|
25
|
-
- Do NOT invent a bespoke auth flow because the task seems "simple" or "custom".
|
|
26
|
-
|
|
27
|
-
If the project does not yet have `@pikku/better-auth` wired up, add it. Do not work around it.
|
|
28
|
-
The only acceptable auth implementation in a Pikku app is the one described in this skill.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Agent Operating Procedure
|
|
33
|
-
|
|
34
|
-
Use this skill as an execution checklist, not reference material.
|
|
35
|
-
|
|
36
|
-
1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
37
|
-
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, or build artifacts.
|
|
38
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated.
|
|
39
|
-
4. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
|
|
40
|
-
5. If validation fails, fix the source cause and rerun. Do not edit generated files.
|
|
41
|
-
|
|
42
|
-
`@pikku/better-auth` provides [Better Auth](https://better-auth.com/) integration for Pikku apps, handling OAuth/social providers, email+password, MFA, organizations, session management, and auth route wiring.
|
|
43
|
-
|
|
44
|
-
## Installation
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
yarn add @pikku/better-auth better-auth
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Core Concepts
|
|
51
|
-
|
|
52
|
-
Better Auth owns its own HTTP surface, database tables, and session cookie. The Pikku integration is thin:
|
|
53
|
-
|
|
54
|
-
1. **`pikkuBetterAuth(factory)`** — you export ONE `pikkuBetterAuth` call whose factory returns a configured `betterAuth({...})` instance. The pikku CLI inspects this export and generates everything else.
|
|
55
|
-
2. **Generated `auth.gen.ts`** — a catch-all `${basePath}{/*splat}` HTTP route per method (GET + POST) that forwards every request under the base path to better-auth's own internal router. The enabled providers and plugins are written to `auth/pikku-auth-meta.gen.json` (read by the console SSO page via `getAuthProviders`).
|
|
56
|
-
3. **Generated session middleware** — with `session.cookieCache` enabled (recommended), a separate `auth-middleware.gen.ts` adds the lean stateless `betterAuthStatelessSession()`; without it, `auth.gen.ts` adds the stateful `betterAuthSession()` that bundles the full server into every unit. See "Stateless session" below.
|
|
57
|
-
4. **Generated `auth-secrets.gen.ts`** — a `wireSecret` for `BETTER_AUTH_SECRET` and for each social provider's OAuth credentials, plus a `wireVariable` for any non-secret provider config (e.g. `tenantId`).
|
|
58
|
-
|
|
59
|
-
You do NOT hand-write routes, the session middleware, or the secret wiring — `pikkuBetterAuth` + the CLI generate all of it. Re-run `pikku all` to regenerate.
|
|
60
|
-
|
|
61
|
-
### The console requires Better Auth
|
|
62
|
-
|
|
63
|
-
The Pikku console (`@pikku/addon-console`, enabled via `scaffold.console` in `pikku.config.json`) is an admin surface: **every console RPC now requires an authenticated session** (the functions are `pikkuFunc`; unauthenticated calls return `403`). So `scaffold.console` alone is **no longer the minimum** — you also need an auth strategy, and Better Auth is the supported one. `pikku all` **throws** if `scaffold.console` is set but no `pikkuBetterAuth(...)` is found in the project. Baseline is "must be logged in"; finer policy (admin-only, org scoping) is layered host-side via tag/HTTP middleware. See `pikku-deps` for the console's Security screen.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Standard Setup
|
|
68
|
-
|
|
69
|
-
### 1. Auth definition — `src/auth.ts`
|
|
70
|
-
|
|
71
|
-
Export ONE `pikkuBetterAuth` call. The factory **must destructure** `services` (`{ secrets, variables, ... }`) — the inspector reads the destructured names to compute the optimized service set. A non-destructured `(services) => ...` falls back to "unoptimized".
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { betterAuth } from 'better-auth'
|
|
75
|
-
import { memoryAdapter } from 'better-auth/adapters/memory'
|
|
76
|
-
import { pikkuBetterAuth } from '@pikku/better-auth'
|
|
77
|
-
|
|
78
|
-
export const auth = pikkuBetterAuth(async ({ secrets }) => {
|
|
79
|
-
// Fetch every secret in ONE batch rather than awaiting each individually.
|
|
80
|
-
const { BETTER_AUTH_SECRET, GITHUB_OAUTH } = await secrets.getSecrets<{
|
|
81
|
-
BETTER_AUTH_SECRET: string
|
|
82
|
-
GITHUB_OAUTH: { clientId: string; clientSecret: string }
|
|
83
|
-
}>(['BETTER_AUTH_SECRET', 'GITHUB_OAUTH'])
|
|
84
|
-
|
|
85
|
-
return betterAuth({
|
|
86
|
-
secret: BETTER_AUTH_SECRET,
|
|
87
|
-
// memoryAdapter needs an array per model — `{}` throws "Model user not found"
|
|
88
|
-
// at runtime. Swap for the Kysely adapter in production (see below).
|
|
89
|
-
database: memoryAdapter({ user: [], session: [], account: [], verification: [] }),
|
|
90
|
-
emailAndPassword: { enabled: true },
|
|
91
|
-
// ALWAYS enable for deployed apps — see "Stateless session" below.
|
|
92
|
-
session: { cookieCache: { enabled: true } },
|
|
93
|
-
socialProviders: {
|
|
94
|
-
github: GITHUB_OAUTH,
|
|
95
|
-
},
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Key points:**
|
|
101
|
-
- `socialProviders` keys must be string literals — the CLI reads them statically to emit a `wireSecret` per provider. Provider keys mirror better-auth's built-in ids exactly (e.g. `microsoft`, NOT `microsoft-entra-id`; `cognito`; `github`).
|
|
102
|
-
- The factory runs lazily on the first auth request, so it pulls secrets/DB off the injected `services`.
|
|
103
|
-
- The default `basePath` is `/api/auth`. Override it by passing `basePath` to `betterAuth`.
|
|
104
|
-
- **Enable `session: { cookieCache: { enabled: true } }`** so non-auth units tree-shake the better-auth server out (see below).
|
|
105
|
-
|
|
106
|
-
## ⚠️ Stateless session — ALWAYS enable `cookieCache` for deployed apps
|
|
107
|
-
|
|
108
|
-
By default the CLI wires the **stateful** `betterAuthSession` bridge globally — it calls `services.auth()`, so EVERY unit/worker bundles the full better-auth server (~2.5MB each). On per-unit deploy targets (Fabric/Cloudflare) that bloats every bundle and the serial upload phase.
|
|
109
|
-
|
|
110
|
-
Enabling `session: { cookieCache: { enabled: true } }` makes the CLI split out a lean `betterAuthStatelessSession` (`src/scaffold/auth-middleware.gen.ts`) that verifies the signed session cookie using only `BETTER_AUTH_SECRET` — no `services.auth()`, no server bundled. Non-auth units drop from ~2.5MB to ~20KB. Only the auth unit carries the server. `pikku fabric validate` warns (`better-auth-stateless-session-disabled`) when it's off.
|
|
111
|
-
|
|
112
|
-
**Tradeoff:** server-side session revocation isn't seen until the cookie cache expires (sign-out is still immediate — it deletes the cookie).
|
|
113
|
-
|
|
114
|
-
**Don't add a redundant default `addHTTPMiddleware('*', [betterAuthSession()])`** — with cookieCache on, that re-drags the stateful server into every unit and defeats the split (validate flags it as `better-auth-stateful-session-global`). If you don't need to customize the session, the generated middleware is enough.
|
|
115
|
-
|
|
116
|
-
**Customizing the session bridge (`mapSession`, `impersonation`, `apiKey`, …):** you do NOT chain a second middleware on top of the generated one — register your OWN global session middleware and the CLI steps aside (it stops generating its default). This works on both paths and is detected the same way:
|
|
117
|
-
|
|
118
|
-
- **Stateless (cookieCache on):** register `betterAuthStatelessSession({ mapSession })` **globally** — `addHTTPMiddleware('*', [...])` or `addGlobalMiddleware([...])`. The CLI sees the global registration and skips emitting `auth-middleware.gen.ts` (pikkujs/pikku#754), so you keep cookieCache's lean bundles *and* your custom fields.
|
|
119
|
-
- **Stateful (cookieCache off):** register `betterAuthSession({ mapSession, impersonation })` **globally**. The CLI detects it (`hasUserSessionMiddleware`) and omits its own `addHTTPMiddleware('*', [betterAuthSession()])` from `auth.gen.ts` — so there's exactly one session bridge in the chain, yours.
|
|
120
|
-
|
|
121
|
-
In both cases a **route-scoped** registration (`addHTTPMiddleware('/some/path', [...])`) does NOT count — only a global one suppresses the generated default. The generated middleware in a `.gen.ts` file is also ignored by the detector, so regeneration never self-suppresses.
|
|
122
|
-
|
|
123
|
-
### Admin capabilities are scopes, not a role
|
|
124
|
-
|
|
125
|
-
Pikku does **not** use better-auth's `admin()` plugin, and nothing in this
|
|
126
|
-
package reads a `role` column. A role is not a permission: "who may impersonate"
|
|
127
|
-
and "who may rebind a shared credential" are different capabilities one user can
|
|
128
|
-
hold independently, which a single `role` string cannot express. Every gate the
|
|
129
|
-
package owns therefore resolves the caller's scopes through the registered
|
|
130
|
-
`ScopeService` and checks the `admin:*` tree:
|
|
131
|
-
|
|
132
|
-
| Gate | Scope required |
|
|
133
|
-
| --- | --- |
|
|
134
|
-
| `impersonation` (`betterAuthSession` / `betterAuthStatelessSession`) | `admin:impersonate` |
|
|
135
|
-
| `credentialOAuth`'s `canLinkSingleton` | `admin:credentials:link` |
|
|
136
|
-
| the console's user directory | `admin:users:list` |
|
|
137
|
-
|
|
138
|
-
Holding the bare `admin` scope satisfies all of them — a parent grant covers
|
|
139
|
-
everything nested beneath it — so `admin` is the direct replacement for the old
|
|
140
|
-
`role === 'admin'`.
|
|
141
|
-
|
|
142
|
-
Declare the tree in your own `wireScope` (the CLI extracts it by AST, so it must
|
|
143
|
-
be an inline literal; `ADMIN_SCOPE_TREE` is exported from `@pikku/better-auth`
|
|
144
|
-
as the reference shape). Apps wiring `@pikku/addon-console` inherit it already.
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
wireScope({
|
|
148
|
-
admin: {
|
|
149
|
-
displayName: 'Administration',
|
|
150
|
-
description: 'Capabilities that act on the application as a whole',
|
|
151
|
-
scopes: {
|
|
152
|
-
impersonate: { description: 'Act as another user' },
|
|
153
|
-
credentials: {
|
|
154
|
-
description: 'Application-wide credentials',
|
|
155
|
-
scopes: {
|
|
156
|
-
link: { description: 'Bind a shared credential for every user' },
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
users: {
|
|
160
|
-
description: 'The user directory',
|
|
161
|
-
scopes: { list: { description: 'List and search users' } },
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
})
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Then grant it — via a role (`scopeService.createRole({ name: 'admin', scopes: ['admin'] })` plus `addUserToRole`) or directly with `addScopeToUser`.
|
|
169
|
-
|
|
170
|
-
Every gate **fails closed**: with no `ScopeService` registered nothing can hold
|
|
171
|
-
a scope, so nothing is authorized, and the denial is logged at `warn` because
|
|
172
|
-
that is a configuration bug rather than a permissions decision. Pass your own
|
|
173
|
-
`canImpersonate` / `canLinkSingleton` to override the default entirely.
|
|
174
|
-
|
|
175
|
-
Sibling concerns — banning a user, listing users from your own screens — are
|
|
176
|
-
actions your app *invokes*, not things pikku gates. Put them on your own
|
|
177
|
-
functions with `scopes: ['admin:users:ban']` and friends.
|
|
178
|
-
|
|
179
|
-
### 2. Production database adapter
|
|
180
|
-
|
|
181
|
-
For real deployments swap `memoryAdapter` for the Kysely adapter backed by an injected DB. Better Auth owns its own tables (`user`, `session`, `account`, `verification`, plus plugin tables) — generate its schema with `npx @better-auth/cli generate` and apply it as a migration.
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
import { kyselyAdapter } from 'better-auth/adapters/kysely'
|
|
185
|
-
|
|
186
|
-
export const auth = pikkuBetterAuth(async ({ secrets, kysely }) => {
|
|
187
|
-
const { BETTER_AUTH_SECRET } = await secrets.getSecrets<{ BETTER_AUTH_SECRET: string }>([
|
|
188
|
-
'BETTER_AUTH_SECRET',
|
|
189
|
-
])
|
|
190
|
-
return betterAuth({
|
|
191
|
-
secret: BETTER_AUTH_SECRET,
|
|
192
|
-
database: kyselyAdapter(kysely, { type: 'postgres' }),
|
|
193
|
-
emailAndPassword: { enabled: true },
|
|
194
|
-
session: { cookieCache: { enabled: true } },
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### 3. Configure `pikku.config.json`
|
|
200
|
-
|
|
201
|
-
If you place `auth.ts` under `srcDirectories` it is inspected automatically. The generated `auth.gen.ts` + `auth-secrets.gen.ts` land in the scaffold dir (`scaffold.pikkuDir`, default `src/scaffold`). No extra config is required for auth in the common case.
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
## Social Providers needing extra config
|
|
206
|
-
|
|
207
|
-
Some providers require non-secret config alongside the OAuth secret — the CLI emits a `wireVariable` for these:
|
|
208
|
-
|
|
209
|
-
- `microsoft` → `MICROSOFT_TENANT_ID` (or `"common"`)
|
|
210
|
-
- `cognito` → `COGNITO_DOMAIN`, `COGNITO_REGION`, `COGNITO_USER_POOL_ID`
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
export const auth = pikkuBetterAuth(async ({ secrets, variables }) => {
|
|
214
|
-
const { BETTER_AUTH_SECRET, MICROSOFT_OAUTH } = await secrets.getSecrets<{
|
|
215
|
-
BETTER_AUTH_SECRET: string
|
|
216
|
-
MICROSOFT_OAUTH: { clientId: string; clientSecret: string }
|
|
217
|
-
}>(['BETTER_AUTH_SECRET', 'MICROSOFT_OAUTH'])
|
|
218
|
-
const { MICROSOFT_TENANT_ID } = await variables.getVariables<{
|
|
219
|
-
MICROSOFT_TENANT_ID: string
|
|
220
|
-
}>(['MICROSOFT_TENANT_ID'])
|
|
221
|
-
|
|
222
|
-
return betterAuth({
|
|
223
|
-
secret: BETTER_AUTH_SECRET,
|
|
224
|
-
database: memoryAdapter({ user: [], session: [], account: [], verification: [] }),
|
|
225
|
-
socialProviders: {
|
|
226
|
-
microsoft: { ...MICROSOFT_OAUTH, tenantId: MICROSOFT_TENANT_ID },
|
|
227
|
-
},
|
|
228
|
-
})
|
|
229
|
-
})
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
---
|
|
233
|
-
|
|
234
|
-
## Auth-Protected Functions
|
|
235
|
-
|
|
236
|
-
Functions that require a session use `pikkuFunc` — anonymous callers are rejected automatically. `betterAuthSession` has already bridged better-auth's session into `session`:
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
import { pikkuFunc } from '#pikku'
|
|
240
|
-
|
|
241
|
-
export const me = pikkuFunc({
|
|
242
|
-
expose: true,
|
|
243
|
-
func: async ({ kysely }, _input, { session }) => {
|
|
244
|
-
return kysely
|
|
245
|
-
.selectFrom('appUser')
|
|
246
|
-
.where('userId', '=', session.userId)
|
|
247
|
-
.select(['userId', 'email', 'name'])
|
|
248
|
-
.executeTakeFirstOrThrow()
|
|
249
|
-
},
|
|
250
|
-
})
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
For public endpoints that optionally vary by viewer, use `pikkuSessionlessFunc` and read `await session?.get()` (`undefined` for anonymous callers).
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
## HTTP surface (call the real endpoints)
|
|
258
|
-
|
|
259
|
-
Better Auth serves everything under `basePath` (default `/api/auth`). Call these directly — the Pikku SDK does not wrap them.
|
|
260
|
-
|
|
261
|
-
| Action | Request | Result |
|
|
262
|
-
|---|---|---|
|
|
263
|
-
| Sign up | `POST /api/auth/sign-up/email` `{ name, email, password }` | 200 + `better-auth.session_token` cookie |
|
|
264
|
-
| Log in | `POST /api/auth/sign-in/email` `{ email, password }` | 200 + cookie; wrong creds → 401 `{ code: "INVALID_EMAIL_OR_PASSWORD" }` |
|
|
265
|
-
| Session | `GET /api/auth/get-session` | `{ session, user }` or `null` |
|
|
266
|
-
| Social sign-in | `POST /api/auth/sign-in/social` `{ provider, callbackURL }` | 200 `{ url, redirect }` (authorize URL) |
|
|
267
|
-
| Sign out | `POST /api/auth/sign-out` | 200, clears cookie |
|
|
268
|
-
|
|
269
|
-
**`Origin` header on state-changing POSTs:** better-auth enforces an `Origin` header matching `baseURL` on POSTs such as sign-out — omit it and you get `403`. Browsers send it automatically; server-to-server callers must set it.
|
|
270
|
-
|
|
271
|
-
The session cookie is `better-auth.session_token` (dev) / `__Secure-better-auth.session_token` (prod).
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## Secret Management
|
|
276
|
-
|
|
277
|
-
All auth secrets are managed through the secrets service and fetched in one batch via `secrets.getSecrets<T>(keys)` (typed — no cast). Wired automatically in the generated `auth-secrets.gen.ts`, so they show up in the Pikku console.
|
|
278
|
-
|
|
279
|
-
- **`BETTER_AUTH_SECRET`** — random ≥32-char string better-auth uses to sign sessions. Always required.
|
|
280
|
-
- **Provider credentials** — each social provider stores a JSON object, e.g. `GITHUB_OAUTH = { clientId, clientSecret }`. The secret id is `<PROVIDER>_OAUTH`.
|
|
281
|
-
|
|
282
|
-
Never register `BETTER_AUTH_SECRET` as a JoseJWT signing key in `services.ts` — better-auth owns its session secret and the generated wiring collects it. The `config.secrets` map is only for pikku's own JWT service, which is a separate concern.
|
|
283
|
-
|
|
284
|
-
---
|
|
285
|
-
|
|
286
|
-
## `pikkuBetterAuth` API
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
import { pikkuBetterAuth } from '@pikku/better-auth'
|
|
290
|
-
|
|
291
|
-
// The factory receives the singleton services (destructure them!) and must
|
|
292
|
-
// return a betterAuth(...) instance (or a Promise of one).
|
|
293
|
-
export const auth = pikkuBetterAuth(async ({ secrets, variables, kysely }) => betterAuth({ ... }))
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
- Export exactly ONE `pikkuBetterAuth` per project; the CLI generates a single catch-all worker for all auth routes.
|
|
297
|
-
- `betterAuthSession({ auth })` (generated) bridges the better-auth session into the Pikku session on every request — you never add it by hand.
|
|
298
|
-
- MFA, organizations, passkeys, etc. are better-auth plugins: add them to `betterAuth({ plugins: [...] })`. The catch-all route already forwards their endpoints.
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pikku-cli
|
|
3
|
-
description: >-
|
|
4
|
-
Use when building CLI commands with Pikku. Covers wireCLI, pikkuCLICommand, subcommands,
|
|
5
|
-
options, parameters, custom renderers, and nested command groups. TRIGGER when: code uses
|
|
6
|
-
wireCLI/pikkuCLICommand, user asks about CLI commands, terminal tools, command-line interface,
|
|
7
|
-
or adding subcommands. DO NOT TRIGGER when: user asks about the pikku CLI tool itself (use
|
|
8
|
-
pikku-info) or HTTP endpoints (use pikku-http).
|
|
9
|
-
installGroups: [core]
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Pikku CLI Wiring
|
|
13
|
-
|
|
14
|
-
## Agent Operating Procedure
|
|
15
|
-
|
|
16
|
-
Use this skill as an execution checklist, not reference material.
|
|
17
|
-
|
|
18
|
-
1. Discover before editing. Prefer OpenCode tools such as `pikku-meta` when available; otherwise run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
19
|
-
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
|
|
20
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
21
|
-
4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
|
|
22
|
-
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
23
|
-
|
|
24
|
-
Wire Pikku functions as CLI commands with parameters, options, subcommands, and custom terminal renderers.
|
|
25
|
-
|
|
26
|
-
## Before You Start
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pikku info functions --verbose # See existing functions and their types
|
|
30
|
-
pikku info tags --verbose # Understand project organization
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
See `pikku-concepts` for the core mental model.
|
|
34
|
-
|
|
35
|
-
## API Reference
|
|
36
|
-
|
|
37
|
-
### `wireCLI(config)`
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
import { wireCLI } from '@pikku/core/cli'
|
|
41
|
-
|
|
42
|
-
wireCLI({
|
|
43
|
-
program: string, // Program name (e.g. 'todos')
|
|
44
|
-
options?: { // Global options
|
|
45
|
-
[key: string]: {
|
|
46
|
-
description: string,
|
|
47
|
-
short?: string, // Single char alias (e.g. 'v')
|
|
48
|
-
default?: any,
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
render?: PikkuCLIRender, // Default renderer for all commands
|
|
52
|
-
commands: {
|
|
53
|
-
[name: string]: PikkuCLICommand | {
|
|
54
|
-
description: string,
|
|
55
|
-
subcommands: { [name: string]: PikkuCLICommand }
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### `pikkuCLICommand(config)`
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
import { pikkuCLICommand } from '#pikku'
|
|
65
|
-
|
|
66
|
-
pikkuCLICommand({
|
|
67
|
-
parameters?: string, // Positional args (e.g. '<text>', '<username> <email>')
|
|
68
|
-
func: PikkuFunc, // Business logic function
|
|
69
|
-
description?: string,
|
|
70
|
-
render?: PikkuCLIRender, // Custom output renderer
|
|
71
|
-
options?: {
|
|
72
|
-
[key: string]: {
|
|
73
|
-
description: string,
|
|
74
|
-
short?: string,
|
|
75
|
-
default?: any,
|
|
76
|
-
choices?: string[], // Restrict to values
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
})
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### `pikkuCLIRender(fn)`
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
import { pikkuCLIRender } from '@pikku/core/cli'
|
|
86
|
-
|
|
87
|
-
const renderer = pikkuCLIRender<OutputType>((services, data) => {
|
|
88
|
-
// Format and print output to terminal
|
|
89
|
-
console.log(data)
|
|
90
|
-
})
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Usage Patterns
|
|
94
|
-
|
|
95
|
-
### Basic Commands
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
wireCLI({
|
|
99
|
-
program: 'todos',
|
|
100
|
-
commands: {
|
|
101
|
-
add: pikkuCLICommand({
|
|
102
|
-
parameters: '<text>',
|
|
103
|
-
func: createTodo,
|
|
104
|
-
description: 'Add a new todo',
|
|
105
|
-
render: todoRenderer,
|
|
106
|
-
options: {
|
|
107
|
-
priority: {
|
|
108
|
-
description: 'Set priority',
|
|
109
|
-
short: 'p',
|
|
110
|
-
default: 'normal',
|
|
111
|
-
choices: ['low', 'normal', 'high'],
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
}),
|
|
115
|
-
list: pikkuCLICommand({
|
|
116
|
-
func: listTodos,
|
|
117
|
-
description: 'List all todos',
|
|
118
|
-
render: todosRenderer,
|
|
119
|
-
options: {
|
|
120
|
-
completed: {
|
|
121
|
-
description: 'Show completed only',
|
|
122
|
-
short: 'c',
|
|
123
|
-
default: false,
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
}),
|
|
127
|
-
},
|
|
128
|
-
})
|
|
129
|
-
// Usage: todos add "Buy milk" -p high
|
|
130
|
-
// Usage: todos list -c
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Nested Subcommands
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
wireCLI({
|
|
137
|
-
program: 'app',
|
|
138
|
-
options: {
|
|
139
|
-
verbose: { description: 'Verbose output', short: 'v', default: false },
|
|
140
|
-
},
|
|
141
|
-
commands: {
|
|
142
|
-
greet: pikkuCLICommand({
|
|
143
|
-
parameters: '<name>',
|
|
144
|
-
func: greetUser,
|
|
145
|
-
render: greetRenderer,
|
|
146
|
-
}),
|
|
147
|
-
|
|
148
|
-
user: {
|
|
149
|
-
description: 'User management',
|
|
150
|
-
subcommands: {
|
|
151
|
-
create: pikkuCLICommand({
|
|
152
|
-
parameters: '<username> <email>',
|
|
153
|
-
func: createUser,
|
|
154
|
-
render: userRenderer,
|
|
155
|
-
options: {
|
|
156
|
-
admin: { description: 'Admin role', short: 'a', default: false },
|
|
157
|
-
},
|
|
158
|
-
}),
|
|
159
|
-
list: pikkuCLICommand({
|
|
160
|
-
func: listUsers,
|
|
161
|
-
render: usersRenderer,
|
|
162
|
-
options: {
|
|
163
|
-
limit: { description: 'Max results', short: 'l' },
|
|
164
|
-
},
|
|
165
|
-
}),
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
})
|
|
170
|
-
// Usage: app greet Alice
|
|
171
|
-
// Usage: app user create bob bob@example.com -a
|
|
172
|
-
// Usage: app user list -l 10
|
|
173
|
-
// Usage: app -v user list
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Custom Renderers
|
|
177
|
-
|
|
178
|
-
A renderer receives `(services, data)` where `data` is the func's output. Set `render` on `wireCLI` as the program-wide default; set `render` on a `pikkuCLICommand` to override it for that command.
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
const todoRenderer = pikkuCLIRender<{ todo: Todo }>((_services, { todo }) => {
|
|
182
|
-
console.log(`✓ Created: ${todo.text} (priority: ${todo.priority})`)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
wireCLI({
|
|
186
|
-
program: 'todos',
|
|
187
|
-
render: jsonRenderer, // default for all commands
|
|
188
|
-
commands: {
|
|
189
|
-
add: pikkuCLICommand({ func: createTodo, render: todoRenderer }), // overrides jsonRenderer
|
|
190
|
-
},
|
|
191
|
-
})
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
The func's input is the positional `parameters` plus `options`, merged (e.g. `parameters: '<username> <email>'` + an `admin` option → func input `{ username, email, admin }`).
|
|
195
|
-
|
|
196
|
-
## Complete Example
|
|
197
|
-
|
|
198
|
-
For a full functions + renderers + nested-subcommand wiring walkthrough, see `references/complete-example.md`.
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Complete CLI Example
|
|
2
|
-
|
|
3
|
-
End-to-end: functions + renderers + nested-subcommand wiring. Note how each func's input is the positional `parameters` plus `options`, merged (e.g. `parameters: '<username> <email>'` + option `admin` → func input `{ username, email, admin }`).
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
// functions/admin.functions.ts
|
|
7
|
-
export const createUser = pikkuFunc({
|
|
8
|
-
title: 'Create User',
|
|
9
|
-
func: async ({ db }, { username, email, admin }) => {
|
|
10
|
-
const user = await db.createUser({
|
|
11
|
-
username,
|
|
12
|
-
email,
|
|
13
|
-
role: admin ? 'admin' : 'user',
|
|
14
|
-
})
|
|
15
|
-
return { user }
|
|
16
|
-
},
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
export const listUsers = pikkuSessionlessFunc({
|
|
20
|
-
title: 'List Users',
|
|
21
|
-
func: async ({ db }, { limit }) => {
|
|
22
|
-
return { users: await db.listUsers(limit || 50) }
|
|
23
|
-
},
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
export const deleteUser = pikkuFunc({
|
|
27
|
-
title: 'Delete User',
|
|
28
|
-
func: async ({ db }, { username }) => {
|
|
29
|
-
await db.deleteUser(username)
|
|
30
|
-
return { deleted: username }
|
|
31
|
-
},
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
// wirings/cli.wiring.ts
|
|
35
|
-
const userRenderer = pikkuCLIRender<{ user: User }>((_services, { user }) => {
|
|
36
|
-
console.log(`Created user: ${user.username} (${user.email}) [${user.role}]`)
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
const usersRenderer = pikkuCLIRender<{ users: User[] }>(
|
|
40
|
-
(_services, { users }) => {
|
|
41
|
-
console.log(`Users (${users.length}):`)
|
|
42
|
-
users.forEach((u) =>
|
|
43
|
-
console.log(` ${u.username} <${u.email}> [${u.role}]`)
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
wireCLI({
|
|
49
|
-
program: 'admin',
|
|
50
|
-
commands: {
|
|
51
|
-
user: {
|
|
52
|
-
description: 'User management',
|
|
53
|
-
subcommands: {
|
|
54
|
-
create: pikkuCLICommand({
|
|
55
|
-
parameters: '<username> <email>',
|
|
56
|
-
func: createUser,
|
|
57
|
-
render: userRenderer,
|
|
58
|
-
options: {
|
|
59
|
-
admin: {
|
|
60
|
-
description: 'Create as admin',
|
|
61
|
-
short: 'a',
|
|
62
|
-
default: false,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
}),
|
|
66
|
-
list: pikkuCLICommand({
|
|
67
|
-
func: listUsers,
|
|
68
|
-
render: usersRenderer,
|
|
69
|
-
options: {
|
|
70
|
-
limit: { description: 'Max results', short: 'l' },
|
|
71
|
-
},
|
|
72
|
-
}),
|
|
73
|
-
delete: pikkuCLICommand({
|
|
74
|
-
parameters: '<username>',
|
|
75
|
-
func: deleteUser,
|
|
76
|
-
description: 'Delete a user',
|
|
77
|
-
}),
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
```
|