@pikku/cli 0.12.91 → 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/console-app/assets/{index-CpkvmAGb.js → index-DDpIMCpy.js} +149 -149
- package/console-app/index.html +1 -1
- 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 +21 -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 +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +35 -40
- 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 +2 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +2 -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 +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.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 +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 +1 -1
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +6 -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 +9 -0
- package/dist/src/functions/commands/pikku-command-bootstrap.js +1 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +17 -2
- package/dist/src/functions/commands/scenario-browser.js +16 -8
- 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.d.ts +6 -0
- package/dist/src/functions/commands/scenario.js +14 -9
- 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/schemas.js +13 -1
- 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 +13 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.js +15 -2
- 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/workflows/all.workflow.js +2 -7
- package/dist/src/utils/file-writer.js +14 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -0
- package/dist/src/utils/pikku-cli-config.js +34 -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/serialize-schemas.d.ts +3 -1
- package/dist/src/utils/serialize-schemas.js +39 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- 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 -382
- 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,556 +0,0 @@
|
|
|
1
|
-
# Concept Mapping: Generic Backend → Pikku
|
|
2
|
-
|
|
3
|
-
Authoritative mapping table plus side-by-side code examples showing how common backend patterns translate to Pikku.
|
|
4
|
-
|
|
5
|
-
## Quick Reference Table
|
|
6
|
-
|
|
7
|
-
| Generic Backend Concept | Pikku Equivalent | Skill |
|
|
8
|
-
| --------------------------------------- | --------------------------------------------------------------- | ----------------- |
|
|
9
|
-
| **Controller / Route Handler** | `pikkuFunc` / `pikkuSessionlessFunc` | `pikku-concepts` |
|
|
10
|
-
| **Route definition** (`GET /users/:id`) | `wireHTTP({ route, method, func })` | `pikku-http` |
|
|
11
|
-
| **Middleware** (Express/Koa-style) | `pikkuMiddleware` | `pikku-security` |
|
|
12
|
-
| **Auth Guard / Auth Middleware** | `authBearer()` / `authCookie()` / `authApiKey()` | `pikku-security` |
|
|
13
|
-
| **Authorization / Permissions** | `pikkuPermission` / `pikkuAuth` | `pikku-security` |
|
|
14
|
-
| **DTO / Request Validation** | Standard Schema (Zod, Valibot, ArkType) | `pikku-concepts` |
|
|
15
|
-
| **Dependency Injection** | `pikkuServices` (singleton) + `pikkuWireServices` (per-request) | `pikku-services` |
|
|
16
|
-
| **WebSocket handlers** | `wireChannel` | `pikku-websocket` |
|
|
17
|
-
| **Job Queue workers** | `wireQueueWorker` | `pikku-queue` |
|
|
18
|
-
| **Cron / Scheduled tasks** | `wireScheduler` | `pikku-cron` |
|
|
19
|
-
| **Module / Feature grouping** | Tags + wiring files | `pikku-concepts` |
|
|
20
|
-
| **Error handling** | Throw typed errors (`NotFoundError`, `ForbiddenError`) | `pikku-concepts` |
|
|
21
|
-
| **Type-safe API client** | `npx pikku all` generates clients | `pikku-concepts` |
|
|
22
|
-
| **Secrets / Config** | `wireSecret`, `wireVariable`, `services.variables` | `pikku-config` |
|
|
23
|
-
|
|
24
|
-
## Route Handler / Controller → pikkuFunc
|
|
25
|
-
|
|
26
|
-
**Traditional (generic):**
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
// A controller method tied to HTTP
|
|
30
|
-
class TodoController {
|
|
31
|
-
async create(req: Request, res: Response) {
|
|
32
|
-
const { title, priority } = req.body
|
|
33
|
-
const todo = await this.todoService.create(title, priority)
|
|
34
|
-
res.json({ todo })
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Route: router.post('/todos', controller.create)
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Pikku:**
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
// Function knows nothing about HTTP.
|
|
44
|
-
// input/output are Zod schemas; the data + return types are inferred from them.
|
|
45
|
-
const createTodo = pikkuSessionlessFunc({
|
|
46
|
-
input: CreateTodoInput,
|
|
47
|
-
output: TodoOutput,
|
|
48
|
-
func: async ({ todoStore, logger }, { title, priority }) => {
|
|
49
|
-
const todo = todoStore.createTodo(title, priority)
|
|
50
|
-
logger.info(`Created todo: ${todo.id}`)
|
|
51
|
-
return { todo }
|
|
52
|
-
},
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
// Wiring (separate file) - grouped with defineHTTPRoutes
|
|
56
|
-
export const todoRoutes = defineHTTPRoutes({
|
|
57
|
-
basePath: '/todos',
|
|
58
|
-
tags: ['todos'],
|
|
59
|
-
auth: false,
|
|
60
|
-
routes: {
|
|
61
|
-
create: { method: 'post', route: '', func: createTodo },
|
|
62
|
-
list: { method: 'get', route: '', func: listTodos },
|
|
63
|
-
},
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// Compose into top-level API
|
|
67
|
-
wireHTTPRoutes({
|
|
68
|
-
basePath: '/api',
|
|
69
|
-
routes: { todos: todoRoutes },
|
|
70
|
-
})
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
**Key difference:** The function receives `{ title, priority }` as typed data - it doesn't know if it came from HTTP body, WebSocket message, or CLI args. Routes are grouped with `defineHTTPRoutes` (like a controller) and composed with `wireHTTPRoutes`.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Route Parameters → Merged into Data
|
|
78
|
-
|
|
79
|
-
**Traditional:**
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
// Must extract from req.params, req.query, req.body separately
|
|
83
|
-
async getUser(req: Request, res: Response) {
|
|
84
|
-
const id = req.params.id // from URL
|
|
85
|
-
const fields = req.query.fields // from query string
|
|
86
|
-
const updates = req.body // from body
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Pikku:**
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
// All sources merged into a single typed `data` object.
|
|
94
|
-
// input/output are Zod schemas; the data + return types are inferred from them.
|
|
95
|
-
const getUser = pikkuSessionlessFunc({
|
|
96
|
-
input: z.object({ id: z.string(), fields: z.string().optional() }),
|
|
97
|
-
output: UserOutput,
|
|
98
|
-
func: async (services, { id, fields }) => {
|
|
99
|
-
// id comes from route param, fields from query - function doesn't care
|
|
100
|
-
return { user: await services.db.getUser(id, fields) }
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
wireHTTP({ method: 'get', route: '/users/:id', func: getUser, auth: false })
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Pikku merges route params + query string + body + headers into a single typed input.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Middleware → pikkuMiddleware
|
|
112
|
-
|
|
113
|
-
**Traditional:**
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
// Express-style middleware
|
|
117
|
-
function logRequest(req: Request, res: Response, next: NextFunction) {
|
|
118
|
-
console.log(`${req.method} ${req.url}`)
|
|
119
|
-
next()
|
|
120
|
-
console.log(`Response: ${res.statusCode}`)
|
|
121
|
-
}
|
|
122
|
-
app.use(logRequest)
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Pikku:**
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
const logRequest = pikkuMiddleware(async ({ logger }, wire, next) => {
|
|
129
|
-
logger.info('Request started')
|
|
130
|
-
await next()
|
|
131
|
-
logger.info('Request completed')
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
// Apply globally
|
|
135
|
-
addHTTPMiddleware('*', [logRequest])
|
|
136
|
-
|
|
137
|
-
// Apply by route pattern
|
|
138
|
-
addHTTPMiddleware('/api/*', [logRequest])
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
**Key difference:** Pikku middleware receives services (injected), not raw req/res.
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Auth Guard → Built-in Auth Middleware
|
|
146
|
-
|
|
147
|
-
**Traditional:**
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// Custom auth middleware
|
|
151
|
-
function authMiddleware(req, res, next) {
|
|
152
|
-
const token = req.headers.authorization?.replace('Bearer ', '')
|
|
153
|
-
if (!token) return res.status(401).json({ error: 'Unauthorized' })
|
|
154
|
-
try {
|
|
155
|
-
req.user = jwt.verify(token)
|
|
156
|
-
next()
|
|
157
|
-
} catch {
|
|
158
|
-
res.status(401).json({ error: 'Invalid token' })
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**Pikku:**
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { authBearer } from '@pikku/core/middleware'
|
|
167
|
-
|
|
168
|
-
// One line - handles token extraction, JWT verification, session population
|
|
169
|
-
addHTTPMiddleware('*', [authBearer({})])
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Other built-in options: `authCookie({ cookieName })`, `authApiKey({ header })`.
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## Authorization / Role Checks → pikkuPermission
|
|
177
|
-
|
|
178
|
-
**Traditional:**
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
// Guard or middleware that checks roles
|
|
182
|
-
function requireRole(role: string) {
|
|
183
|
-
return (req, res, next) => {
|
|
184
|
-
if (req.user.role !== role)
|
|
185
|
-
return res.status(403).json({ error: 'Forbidden' })
|
|
186
|
-
next()
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
router.delete('/users/:id', requireRole('admin'), deleteUser)
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
**Pikku:**
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
const isOwner = pikkuPermission(async ({ db }, { userId }, wire) => {
|
|
196
|
-
const { session } = wire
|
|
197
|
-
return session?.userId === userId
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
// Declare on the function definition (the only place permissions live).
|
|
201
|
-
// A capability like "may delete users" is a scope, not a permission.
|
|
202
|
-
export const deleteUser = pikkuFunc({
|
|
203
|
-
func: async (services, data) => {
|
|
204
|
-
/* ... */
|
|
205
|
-
},
|
|
206
|
-
scopes: ['admin:users:delete'],
|
|
207
|
-
permissions: { owner: [isOwner] },
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
// App-wide baseline every function must also pass (AND gate, narrow-only)
|
|
211
|
-
addGlobalPermission([signedInUser])
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Permission groups:** `{ groupA: [perm1, perm2], groupB: [perm3] }` means `(perm1 AND perm2) OR perm3`.
|
|
215
|
-
|
|
216
|
-
> Route-pattern (`addHTTPPermission`) and wire-level `permissions` were removed in #972 — permissions live on the function, plus the optional global gate.
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## DTO / Request Validation → Standard Schema
|
|
221
|
-
|
|
222
|
-
**Traditional (class-validator):**
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
class CreateTodoDTO {
|
|
226
|
-
@IsString()
|
|
227
|
-
@IsNotEmpty()
|
|
228
|
-
@MaxLength(200)
|
|
229
|
-
title: string
|
|
230
|
-
|
|
231
|
-
@IsOptional()
|
|
232
|
-
@IsIn(['low', 'medium', 'high'])
|
|
233
|
-
priority?: string
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**Pikku (Zod):**
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
const CreateTodoInputSchema = z.object({
|
|
241
|
-
title: z.string().min(1).max(200),
|
|
242
|
-
priority: z.enum(['low', 'medium', 'high']).optional(),
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
// Schema declared on function - auto-validated before function runs
|
|
246
|
-
const createTodo = pikkuSessionlessFunc({
|
|
247
|
-
input: CreateTodoInputSchema,
|
|
248
|
-
output: TodoOutputSchema,
|
|
249
|
-
func: async (services, data) => { ... },
|
|
250
|
-
})
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
Also supports Valibot, ArkType, or any Standard Schema-compatible library.
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
## Dependency Injection → Service Factories
|
|
258
|
-
|
|
259
|
-
**Traditional (class-based DI):**
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
@Injectable()
|
|
263
|
-
class TodoService {
|
|
264
|
-
constructor(
|
|
265
|
-
@Inject('DATABASE') private db: Database,
|
|
266
|
-
private logger: Logger
|
|
267
|
-
) {}
|
|
268
|
-
|
|
269
|
-
async create(title: string) {
|
|
270
|
-
this.logger.info('Creating todo')
|
|
271
|
-
return this.db.insert('todos', { title })
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
**Pikku:**
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
// Define services once at startup
|
|
280
|
-
const createSingletonServices = pikkuServices(async (config) => ({
|
|
281
|
-
logger: new ConsoleLogger(),
|
|
282
|
-
db: new KyselyService(config.database),
|
|
283
|
-
todoStore: new TodoStore(),
|
|
284
|
-
}))
|
|
285
|
-
|
|
286
|
-
// Functions destructure what they need
|
|
287
|
-
const createTodo = pikkuSessionlessFunc(
|
|
288
|
-
async ({ logger, todoStore }, { title }) => {
|
|
289
|
-
logger.info('Creating todo')
|
|
290
|
-
return { todo: todoStore.createTodo(title) }
|
|
291
|
-
}
|
|
292
|
-
)
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
**Key difference:** No container, no decorators, no class hierarchy. Just a factory function returning an object.
|
|
296
|
-
|
|
297
|
-
Per-request services (like scoped loggers) use `pikkuWireServices`:
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
const createWireServices = pikkuWireServices(
|
|
301
|
-
async (singletonServices, wire) => ({
|
|
302
|
-
scopedLogger: new ScopedLogger(wire.session?.initial?.userId),
|
|
303
|
-
})
|
|
304
|
-
)
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## WebSocket Handlers → wireChannel
|
|
310
|
-
|
|
311
|
-
**Traditional:**
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
wss.on('connection', (ws) => {
|
|
315
|
-
ws.on('message', (raw) => {
|
|
316
|
-
const { type, payload } = JSON.parse(raw)
|
|
317
|
-
switch (type) {
|
|
318
|
-
case 'subscribe':
|
|
319
|
-
handleSubscribe(ws, payload)
|
|
320
|
-
break
|
|
321
|
-
case 'create':
|
|
322
|
-
handleCreate(ws, payload)
|
|
323
|
-
break
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
ws.on('close', () => handleDisconnect(ws))
|
|
327
|
-
})
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**Pikku:**
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
wireChannel({
|
|
334
|
-
name: 'todos-live',
|
|
335
|
-
route: '/',
|
|
336
|
-
onConnect, // pikkuVoidFunc
|
|
337
|
-
onDisconnect, // pikkuVoidFunc
|
|
338
|
-
onMessageWiring: {
|
|
339
|
-
action: {
|
|
340
|
-
// First level of message routing
|
|
341
|
-
subscribe: { func: subscribe },
|
|
342
|
-
create: { func: createTodo },
|
|
343
|
-
auth: { func: login, auth: false },
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
})
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
Functions send data back via `wire.channel.send(data)`. Structured message routing replaces manual switch/case parsing.
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
## Job Queue Workers → wireQueueWorker
|
|
354
|
-
|
|
355
|
-
**Traditional (Bull/BullMQ):**
|
|
356
|
-
|
|
357
|
-
```typescript
|
|
358
|
-
const queue = new Queue('reminders')
|
|
359
|
-
|
|
360
|
-
// Producer
|
|
361
|
-
await queue.add('send-reminder', { todoId: '123', userId: 'user1' })
|
|
362
|
-
|
|
363
|
-
// Consumer
|
|
364
|
-
const worker = new Worker('reminders', async (job) => {
|
|
365
|
-
const { todoId, userId } = job.data
|
|
366
|
-
await sendReminder(todoId, userId)
|
|
367
|
-
})
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
**Pikku:**
|
|
371
|
-
|
|
372
|
-
```typescript
|
|
373
|
-
// Same pikkuFunc shape - knows nothing about queues
|
|
374
|
-
const processReminder = pikkuSessionlessFunc(
|
|
375
|
-
async ({ todoStore, logger }, { todoId, userId }) => {
|
|
376
|
-
const todo = todoStore.getTodo(todoId)
|
|
377
|
-
if (todo && !todo.completed) {
|
|
378
|
-
logger.info(`Sending reminder for: ${todo.title}`)
|
|
379
|
-
}
|
|
380
|
-
return { processed: true }
|
|
381
|
-
}
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
// Wire it to a queue
|
|
385
|
-
wireQueueWorker({ name: 'todo-reminders', func: processReminder })
|
|
386
|
-
|
|
387
|
-
// Enqueue from other functions via queue service
|
|
388
|
-
await services.queueService.addJob('todo-reminders', {
|
|
389
|
-
todoId: '123',
|
|
390
|
-
userId: 'user1',
|
|
391
|
-
})
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
## Cron / Scheduled Tasks → wireScheduler
|
|
397
|
-
|
|
398
|
-
**Traditional:**
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
import cron from 'node-cron'
|
|
402
|
-
cron.schedule('0 9 * * *', async () => {
|
|
403
|
-
const stats = await todoService.getStats()
|
|
404
|
-
console.log(`Daily: ${stats.completed}/${stats.total}`)
|
|
405
|
-
})
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
**Pikku:**
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
const dailySummary = pikkuVoidFunc(async ({ logger, todoStore }) => {
|
|
412
|
-
const stats = todoStore.getStats('user1')
|
|
413
|
-
logger.info(`Daily: ${stats.completed}/${stats.total}`)
|
|
414
|
-
})
|
|
415
|
-
|
|
416
|
-
wireScheduler({
|
|
417
|
-
name: 'dailySummary',
|
|
418
|
-
schedule: '0 9 * * *',
|
|
419
|
-
func: dailySummary,
|
|
420
|
-
})
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
---
|
|
424
|
-
|
|
425
|
-
## Module / Feature Grouping → Tags + File Organization
|
|
426
|
-
|
|
427
|
-
**Traditional (NestJS):**
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
@Module({
|
|
431
|
-
imports: [DatabaseModule],
|
|
432
|
-
controllers: [TodoController],
|
|
433
|
-
providers: [TodoService],
|
|
434
|
-
exports: [TodoService],
|
|
435
|
-
})
|
|
436
|
-
export class TodoModule {}
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
**Pikku:**
|
|
440
|
-
|
|
441
|
-
```text
|
|
442
|
-
// No module system. Organize by convention:
|
|
443
|
-
src/
|
|
444
|
-
├── functions/
|
|
445
|
-
│ └── todos.functions.ts # All todo business logic
|
|
446
|
-
├── wirings/
|
|
447
|
-
│ └── todos.http.ts # All todo HTTP routes
|
|
448
|
-
└── schemas.ts # Shared schemas
|
|
449
|
-
|
|
450
|
-
// Use tags for cross-cutting concerns:
|
|
451
|
-
wireHTTP({ route: '/todos', func: listTodos, tags: ['todos', 'public'] })
|
|
452
|
-
addMiddleware('todos', [loggingMiddleware]) // Applies to all 'todos'-tagged functions
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
---
|
|
456
|
-
|
|
457
|
-
## Error Handling → Typed Errors
|
|
458
|
-
|
|
459
|
-
**Traditional:**
|
|
460
|
-
|
|
461
|
-
```typescript
|
|
462
|
-
if (!todo) {
|
|
463
|
-
res.status(404).json({ error: 'Todo not found' })
|
|
464
|
-
return
|
|
465
|
-
}
|
|
466
|
-
if (!canEdit(user, todo)) {
|
|
467
|
-
res.status(403).json({ error: 'Forbidden' })
|
|
468
|
-
return
|
|
469
|
-
}
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
**Pikku:**
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
import { NotFoundError, ForbiddenError } from '@pikku/core/errors'
|
|
476
|
-
|
|
477
|
-
const updateTodo = pikkuFunc(async (services, { id, title }, wire) => {
|
|
478
|
-
const todo = services.todoStore.getTodo(id)
|
|
479
|
-
if (!todo) throw new NotFoundError('Todo not found')
|
|
480
|
-
|
|
481
|
-
const { session } = wire
|
|
482
|
-
if (todo.userId !== session.userId) throw new ForbiddenError()
|
|
483
|
-
|
|
484
|
-
return { todo: services.todoStore.update(id, { title }) }
|
|
485
|
-
})
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
Pikku catches these errors and maps them to appropriate HTTP status codes automatically.
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
## Session Management
|
|
493
|
-
|
|
494
|
-
**Traditional:**
|
|
495
|
-
|
|
496
|
-
```typescript
|
|
497
|
-
// Express session
|
|
498
|
-
app.use(session({ store: new RedisStore({ client: redis }), secret: 'key' }))
|
|
499
|
-
|
|
500
|
-
// In handler
|
|
501
|
-
req.session.userId = user.id // Set
|
|
502
|
-
const userId = req.session.userId // Get
|
|
503
|
-
req.session.destroy() // Clear
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
**Pikku:**
|
|
507
|
-
|
|
508
|
-
```typescript
|
|
509
|
-
// Session is on the wire context, managed by auth middleware
|
|
510
|
-
const login = pikkuSessionlessFunc(
|
|
511
|
-
async ({ jwt }, { username, password }, wire) => {
|
|
512
|
-
const user = authenticate(username, password)
|
|
513
|
-
const token = await jwt.sign({ userId: user.id })
|
|
514
|
-
await wire.setSession({ userId: user.id, user }) // Set
|
|
515
|
-
return { token, user }
|
|
516
|
-
}
|
|
517
|
-
)
|
|
518
|
-
|
|
519
|
-
const getMe = pikkuFunc(async (services, data, wire) => {
|
|
520
|
-
const { session } = wire // Get
|
|
521
|
-
return { user: session.user }
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
const logout = pikkuFunc(async (services, data, wire) => {
|
|
525
|
-
await wire.clearSession() // Clear
|
|
526
|
-
return { success: true }
|
|
527
|
-
})
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
---
|
|
531
|
-
|
|
532
|
-
## API Client Generation
|
|
533
|
-
|
|
534
|
-
**Traditional:**
|
|
535
|
-
|
|
536
|
-
```typescript
|
|
537
|
-
// Manually written or generated via OpenAPI
|
|
538
|
-
const response = await fetch('/api/todos', {
|
|
539
|
-
method: 'POST',
|
|
540
|
-
headers: { 'Content-Type': 'application/json' },
|
|
541
|
-
body: JSON.stringify({ title: 'New todo' }),
|
|
542
|
-
})
|
|
543
|
-
const data: unknown = await response.json()
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
**Pikku (auto-generated, fully typed):**
|
|
547
|
-
|
|
548
|
-
```typescript
|
|
549
|
-
import { createPikkuFetchClient } from './.pikku/pikku-fetch.gen.js'
|
|
550
|
-
|
|
551
|
-
const client = createPikkuFetchClient({ baseUrl: 'http://localhost:4002' })
|
|
552
|
-
const result = await client.post('/todos', { title: 'New todo' })
|
|
553
|
-
// result is fully typed as TodoOutput - no manual type casting
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
Generated by running `npx pikku all`. Both HTTP and WebSocket clients available.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Available Pikku Packages
|
|
2
|
-
|
|
3
|
-
## Runtime Adapters
|
|
4
|
-
|
|
5
|
-
| Package | Use Case |
|
|
6
|
-
| ----------------------------- | ------------------------------------- |
|
|
7
|
-
| `@pikku/express-server` | Express standalone server |
|
|
8
|
-
| `@pikku/express-middleware` | Express as middleware in existing app |
|
|
9
|
-
| `@pikku/fastify-server` | Fastify standalone |
|
|
10
|
-
| `@pikku/fastify-plugin` | Fastify plugin |
|
|
11
|
-
| `@pikku/next` | Next.js API routes |
|
|
12
|
-
| `@pikku/aws-lambda` | AWS Lambda handlers |
|
|
13
|
-
| `@pikku/cloudflare` | Cloudflare Workers |
|
|
14
|
-
| `@pikku/uws-server` | uWebSockets.js (high perf) |
|
|
15
|
-
| `@pikku/modelcontextprotocol` | MCP server |
|
|
16
|
-
|
|
17
|
-
## Service Packages
|
|
18
|
-
|
|
19
|
-
| Package | Provides |
|
|
20
|
-
| ------------------------ | ---------------------------------------------------- |
|
|
21
|
-
| `@pikku/jose` | JWT (sign/verify) via jose library |
|
|
22
|
-
| `@pikku/schema-ajv` | Schema validation via AJV |
|
|
23
|
-
| `@pikku/schema-cfworker` | Schema validation for Cloudflare |
|
|
24
|
-
| `@pikku/pino` | Structured logging via Pino |
|
|
25
|
-
| `@pikku/kysely` | Type-safe SQL via Kysely (PostgreSQL, SQLite, MySQL) |
|
|
26
|
-
| `@pikku/redis` | Redis client |
|
|
27
|
-
| `@pikku/queue-bullmq` | Job queues via BullMQ |
|
|
28
|
-
| `@pikku/queue-pg-boss` | Job queues via PgBoss |
|
|
29
|
-
| `@pikku/aws-services` | AWS SDK (SQS, DynamoDB, etc.) |
|