@pikku/skills 0.12.22 → 0.12.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/dist/skills.gen.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-a11y/SKILL.md +59 -0
- package/skills/pikku-addon/SKILL.md +2 -2
- package/skills/pikku-agent/SKILL.md +67 -316
- package/skills/pikku-agent/references/agents.md +299 -0
- package/skills/{pikku-ai-vercel/SKILL.md → pikku-agent/references/runner-vercel.md} +2 -24
- package/skills/{pikku-ai-voice/SKILL.md → pikku-agent/references/voice.md} +1 -22
- package/skills/pikku-architect/SKILL.md +265 -0
- package/skills/pikku-auth/SKILL.md +89 -0
- package/skills/{pikku-better-auth/SKILL.md → pikku-auth/references/better-auth.md} +126 -34
- package/skills/{pikku-jose/SKILL.md → pikku-auth/references/jose.md} +1 -23
- package/skills/{pikku-machine-auth/SKILL.md → pikku-auth/references/machine-auth.md} +0 -23
- package/skills/pikku-auth/references/permissions.md +261 -0
- package/skills/{pikku-security/SKILL.md → pikku-auth/references/sessions.md} +0 -20
- package/skills/pikku-build/SKILL.md +88 -0
- package/skills/{pikku-build-app/SKILL.md → pikku-build/references/app.md} +76 -24
- package/skills/{pikku-feature/SKILL.md → pikku-build/references/feature.md} +1 -8
- package/skills/{pikku-build-app → pikku-build}/references/multi-app.md +56 -1
- package/skills/{pikku-build-platform/SKILL.md → pikku-build/references/platform.md} +22 -37
- package/skills/{pikku-template-clone/SKILL.md → pikku-build/references/post-clone.md} +0 -6
- package/skills/{pikku-build-quick/SKILL.md → pikku-build/references/quick.md} +4 -20
- package/skills/{pikku-build-app → pikku-build}/references/ship.md +9 -3
- package/skills/pikku-concepts/SKILL.md +72 -7
- package/skills/pikku-concepts/references/concept-mapping.md +8 -8
- package/skills/pikku-deploy/SKILL.md +158 -0
- package/skills/{pikku-deploy-azure/SKILL.md → pikku-deploy/references/azure.md} +18 -50
- package/skills/pikku-deploy/references/cloudflare.md +104 -0
- package/skills/pikku-deploy/references/express.md +92 -0
- package/skills/{pikku-deploy-fastify/SKILL.md → pikku-deploy/references/fastify.md} +8 -32
- package/skills/{pikku-deploy-lambda/SKILL.md → pikku-deploy/references/lambda.md} +6 -27
- package/skills/{pikku-deploy-nextjs/SKILL.md → pikku-deploy/references/nextjs.md} +9 -33
- package/skills/pikku-deploy/references/uws.md +72 -0
- package/skills/pikku-deploy/references/ws.md +75 -0
- package/skills/pikku-emails/SKILL.md +3 -2
- package/skills/pikku-fabric/SKILL.md +47 -20
- package/skills/{pikku-fabric-debug/SKILL.md → pikku-fabric/references/debugging.md} +0 -6
- package/skills/pikku-i18n/SKILL.md +62 -207
- package/skills/{pikku-paraglide/SKILL.md → pikku-i18n/references/enum-labels.md} +0 -6
- package/skills/pikku-i18n/references/messages.md +218 -0
- package/skills/{pikku-rtl/SKILL.md → pikku-i18n/references/rtl.md} +3 -9
- package/skills/pikku-knowledge/SKILL.md +15 -0
- package/skills/pikku-kysely/SKILL.md +13 -13
- package/skills/pikku-list-query/SKILL.md +163 -0
- package/skills/pikku-meta/SKILL.md +58 -130
- package/skills/{pikku-deps/SKILL.md → pikku-meta/references/audit.md} +1 -17
- package/skills/pikku-meta/references/meta.md +114 -0
- package/skills/{pikku-versioning/SKILL.md → pikku-meta/references/versioning.md} +0 -26
- package/skills/pikku-middleware/SKILL.md +5 -5
- package/skills/pikku-n8n-import/SKILL.md +0 -1
- package/skills/pikku-permissions/SKILL.md +75 -229
- package/skills/pikku-react/SKILL.md +50 -298
- package/skills/pikku-react/references/client.md +313 -0
- package/skills/{pikku-react-query/SKILL.md → pikku-react/references/react-query.md} +2 -22
- package/skills/{pikku-workflows-client/SKILL.md → pikku-react/references/workflows.md} +1 -22
- package/skills/pikku-realtime/SKILL.md +110 -251
- package/skills/pikku-scenario/SKILL.md +60 -45
- package/skills/pikku-scenario/references/persona-run.md +148 -0
- package/skills/pikku-seo/SKILL.md +133 -0
- package/skills/pikku-service-backends/SKILL.md +154 -0
- package/skills/pikku-service-backends/references/aws.md +106 -0
- package/skills/pikku-service-backends/references/backblaze.md +57 -0
- package/skills/pikku-service-backends/references/mongodb.md +90 -0
- package/skills/pikku-service-backends/references/redis.md +75 -0
- package/skills/pikku-service-backends/references/schema.md +63 -0
- package/skills/pikku-services/SKILL.md +68 -291
- package/skills/{pikku-audit/SKILL.md → pikku-services/references/audit.md} +0 -22
- package/skills/{pikku-config/SKILL.md → pikku-services/references/config.md} +1 -25
- package/skills/{pikku-pino/SKILL.md → pikku-services/references/pino.md} +0 -20
- package/skills/pikku-services/references/services.md +272 -0
- package/skills/pikku-software-archaeology/README.md +5 -1
- package/skills/pikku-software-archaeology/SKILL.md +16 -2
- package/skills/{pikku-product-second-opinion/example/sample-report.md → pikku-software-archaeology/example/second-opinion-sample-report.md} +1 -1
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +1 -1
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
- package/skills/{pikku-product-second-opinion/SKILL.md → pikku-software-archaeology/references/second-opinion.md} +4 -9
- package/skills/pikku-webhook/SKILL.md +224 -0
- package/skills/pikku-wiring/SKILL.md +180 -0
- package/skills/{pikku-websocket/SKILL.md → pikku-wiring/references/channel.md} +2 -35
- package/skills/{pikku-cli/SKILL.md → pikku-wiring/references/cli.md} +1 -33
- package/skills/{pikku-gateway-slack/SKILL.md → pikku-wiring/references/gateway-slack.md} +0 -23
- package/skills/{pikku-http/SKILL.md → pikku-wiring/references/http.md} +3 -39
- package/skills/{pikku-mcp/SKILL.md → pikku-wiring/references/mcp.md} +0 -33
- package/skills/{pikku-queue/SKILL.md → pikku-wiring/references/queue.md} +1 -33
- package/skills/pikku-wiring/references/realtime.md +265 -0
- package/skills/{pikku-rpc/SKILL.md → pikku-wiring/references/rpc.md} +0 -32
- package/skills/{pikku-schedule/SKILL.md → pikku-wiring/references/scheduler.md} +1 -35
- package/skills/{pikku-trigger/SKILL.md → pikku-wiring/references/trigger.md} +0 -43
- package/skills/pikku-workflow/SKILL.md +39 -2
- package/skills/pikku-aws/SKILL.md +0 -161
- package/skills/pikku-backblaze/SKILL.md +0 -104
- package/skills/pikku-deploy-cloudflare/SKILL.md +0 -123
- package/skills/pikku-deploy-express/SKILL.md +0 -122
- package/skills/pikku-deploy-uws/SKILL.md +0 -144
- package/skills/pikku-mongodb/SKILL.md +0 -113
- package/skills/pikku-product-second-opinion/README.md +0 -43
- package/skills/pikku-redis/SKILL.md +0 -99
- package/skills/pikku-schema-ajv/SKILL.md +0 -83
- package/skills/pikku-schema-cfworker/SKILL.md +0 -82
- package/skills/pikku-ws/SKILL.md +0 -87
- /package/skills/{pikku-build-app → pikku-build}/references/theming.md +0 -0
- /package/skills/{pikku-product-second-opinion/references/report-template.md → pikku-software-archaeology/references/second-opinion-report-template.md} +0 -0
- /package/skills/{pikku-cli/references/complete-example.md → pikku-wiring/references/cli-complete-example.md} +0 -0
- /package/skills/{pikku-http → pikku-wiring}/references/http-options.md +0 -0
- /package/skills/{pikku-realtime/references/other-routes.md → pikku-wiring/references/realtime-other-routes.md} +0 -0
|
@@ -74,6 +74,71 @@ which is what decides whether a thrown error becomes a 409 or a 500.
|
|
|
74
74
|
`pikku doc` needs `@pikku/cli` 0.12.115 or newer. On an older pin, fall back to the door's
|
|
75
75
|
skill and `pikku meta --json`, and do not guess at names the doc would have given you.
|
|
76
76
|
|
|
77
|
+
## The CLI commands
|
|
78
|
+
|
|
79
|
+
`pikku doc` is the API surface — the `#pikku/*` exports. It does **not** list
|
|
80
|
+
commands, so this table is where they exist. `pikku <command> --help` has the
|
|
81
|
+
flags; the "Read" column is the skill that teaches the thing, where one does.
|
|
82
|
+
|
|
83
|
+
**Generating**
|
|
84
|
+
|
|
85
|
+
| Command | What it does | Read |
|
|
86
|
+
| ------------------------------------------ | ---------------------------------------------------- | ----------------------------- |
|
|
87
|
+
| `all` | Everything: types, schemas, wirings, clients | this skill |
|
|
88
|
+
| `bootstrap` | Type files only (the setup phase) | this skill |
|
|
89
|
+
| `schemas` | JSON Schemas for function input/output types | this skill |
|
|
90
|
+
| `fetch` / `websocket` / `rpc` / `realtime` | One client each, when you do not want `all` | `pikku-wiring`, `pikku-react` |
|
|
91
|
+
| `react-query` / `tanstack-start` | React Query hooks; the TanStack Start `makeApi` shim | `pikku-react` |
|
|
92
|
+
| `queue-service` | The queue service wrapper | `pikku-wiring` |
|
|
93
|
+
| `openapi` | An OpenAPI spec from the HTTP routes | — |
|
|
94
|
+
| `nextjs` | Next.js backend and HTTP wrappers | `pikku-deploy` |
|
|
95
|
+
| `new` | Scaffold a function or wiring | `pikku-wiring` |
|
|
96
|
+
| `enable` | Turn a Pikku feature on | `pikku-build` |
|
|
97
|
+
| `import` | Import workflows from another system | `pikku-n8n-import` |
|
|
98
|
+
|
|
99
|
+
**Running**
|
|
100
|
+
|
|
101
|
+
| Command | What it does | Read |
|
|
102
|
+
| ---------------------------- | ------------------------------------------------------------------------------ | --------------------------------------- |
|
|
103
|
+
| `dev` | Local dev server, all services wired, watch + HMR | `pikku-build` |
|
|
104
|
+
| `serve` | Bundled bun/node runner — no watch, no codegen | `pikku-deploy` |
|
|
105
|
+
| `watch` | Regenerate on file change, without a server | — |
|
|
106
|
+
| `scenario list\|run` | Scenarios as e2e tests and health checks | `pikku-scenario` |
|
|
107
|
+
| `persona run` | A declared persona as a model-driven virtual user against a stage | `pikku-scenario`, persona-run reference |
|
|
108
|
+
| `persona list\|sync\|secret` | Who is declared; what an environment will provision; minting their credentials | `pikku-scenario`, persona-run reference |
|
|
109
|
+
| `db` | Local development database | `pikku-kysely` |
|
|
110
|
+
|
|
111
|
+
**Inspecting and evolving**
|
|
112
|
+
|
|
113
|
+
| Command | What it does | Read |
|
|
114
|
+
| --------------------- | ----------------------------------------------------------------------- | ---------------------------- |
|
|
115
|
+
| `doc` | The installed API surface | this skill |
|
|
116
|
+
| `meta` / `info` | What the project declares, machine- and human-readable | `pikku-meta` |
|
|
117
|
+
| `validate` | Every check that applies — app structure, an addon's published file set | `pikku-build`, `pikku-addon` |
|
|
118
|
+
| `versions` / `semver` | Contract hashes, breaking-change detection, the release semver | `pikku-meta` |
|
|
119
|
+
| `audit` / `update` | Advisories; which `@pikku/*` can move and what peers that needs | `pikku-meta` |
|
|
120
|
+
| `scopes` / `roles` | Declared authorization scopes; roles from `defineSystemRole` | `pikku-auth` |
|
|
121
|
+
| `knowledge` | The knowledge base — what this app is, in its users' language | `pikku-knowledge` |
|
|
122
|
+
| `emails` | Email template generation | `pikku-emails` |
|
|
123
|
+
|
|
124
|
+
**Shipping, and the CLI itself**
|
|
125
|
+
|
|
126
|
+
| Command | What it does | Read |
|
|
127
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
|
|
128
|
+
| `deploy` | Deploy to cloud infrastructure | `pikku-deploy` |
|
|
129
|
+
| `fabric` | PikkuFabric: login, link, deploy, domains, secrets, logs | `pikku-fabric` |
|
|
130
|
+
| `binary` | Compile an entrypoint to a native binary (`bun build --compile`) | — |
|
|
131
|
+
| `dist` | Copy what `tsc` cannot emit — `.gen.json` meta, hand-authored `.d.ts` — into the build output. Run it after `tsc`, as a package's build script | — |
|
|
132
|
+
| `login` / `logout` / `whoami` | The CLI's session against a pikku server | — |
|
|
133
|
+
| `skills` | Install these skills into an agent (Claude Code, opencode, pi) | — |
|
|
134
|
+
|
|
135
|
+
`-c/--config`, `--log-level`, `--json` and the filter flags are **global
|
|
136
|
+
options**, not commands — they attach to the generating commands above.
|
|
137
|
+
|
|
138
|
+
A dash means no skill covers it beyond this line. `--help` is then the whole of
|
|
139
|
+
it — which is a reason to read `--help` rather than to assume the command does
|
|
140
|
+
what its name suggests.
|
|
141
|
+
|
|
77
142
|
## Core Mental Model
|
|
78
143
|
|
|
79
144
|
```text
|
|
@@ -101,7 +166,7 @@ The function never imports Express, never reads `req.body`, never touches `ws.se
|
|
|
101
166
|
|
|
102
167
|
## Concept Mapping: Generic Backend → Pikku
|
|
103
168
|
|
|
104
|
-
Controllers/routes → `pikkuFunc`; auth/sessions → `pikku-
|
|
169
|
+
Controllers/routes → `pikkuFunc`; auth/sessions and authorization checks → `pikku-auth`, a separate install; request interception → `pikku-middleware`; DI → `pikku-services`; transports (HTTP/WS/queue/cron) → their `wire*` + skill. For the full Generic Backend → Pikku mapping table (with side-by-side code examples), read `references/concept-mapping.md`.
|
|
105
170
|
|
|
106
171
|
## Functions
|
|
107
172
|
|
|
@@ -143,7 +208,7 @@ pikkuFunc({
|
|
|
143
208
|
// "What Language You Write In".
|
|
144
209
|
title?: string, // Human-readable name
|
|
145
210
|
description?: string, // What the function does
|
|
146
|
-
version?: number, // Contract version (see pikku-
|
|
211
|
+
version?: number, // Contract version (see pikku-meta)
|
|
147
212
|
override?: string, // Logical name override, so several exports share a versioned base
|
|
148
213
|
tags?: string[], // For grouping and middleware targeting
|
|
149
214
|
|
|
@@ -153,13 +218,13 @@ pikkuFunc({
|
|
|
153
218
|
errors?: Array<typeof PikkuError>, // Errors this function may throw
|
|
154
219
|
|
|
155
220
|
// Reachability
|
|
156
|
-
expose?: boolean, // Allow external RPC calls (see pikku-
|
|
221
|
+
expose?: boolean, // Allow external RPC calls (see pikku-wiring)
|
|
157
222
|
remote?: boolean, // Allow remote RPC calls
|
|
158
|
-
mcp?: boolean, // Expose as MCP tool (see pikku-
|
|
223
|
+
mcp?: boolean, // Expose as MCP tool (see pikku-wiring)
|
|
159
224
|
readonly?: boolean, // Declares the function performs no writes
|
|
160
225
|
deploy?: 'serverless' | 'server' | 'auto',
|
|
161
226
|
|
|
162
|
-
// Authorization — see pikku-
|
|
227
|
+
// Authorization — see pikku-auth
|
|
163
228
|
auth?: boolean, // Override default auth requirement
|
|
164
229
|
scopes?: ScopeId[], // AND-ed, checked before permissions; session required
|
|
165
230
|
permissions?: PermissionGroup, // OR-ed pool
|
|
@@ -317,7 +382,7 @@ src/
|
|
|
317
382
|
├── services.ts # Service factories (see pikku-services)
|
|
318
383
|
├── lifecycle.ts # Server lifecycle hooks (pikku dev/serve only)
|
|
319
384
|
├── middleware.ts # Middleware definitions (see pikku-middleware)
|
|
320
|
-
├── permissions.ts # Permission definitions (see pikku-
|
|
385
|
+
├── permissions.ts # Permission definitions (see pikku-auth)
|
|
321
386
|
└── .pikku/ # Generated (gitignored)
|
|
322
387
|
├── function/ # #pikku/function
|
|
323
388
|
├── http/ # #pikku/http
|
|
@@ -415,7 +480,7 @@ language, it is telling you about axis three and nothing else.
|
|
|
415
480
|
|
|
416
481
|
## Environment Variables
|
|
417
482
|
|
|
418
|
-
Never use `process.env` inside Pikku functions. Use the `variables` service (see `pikku-
|
|
483
|
+
Never use `process.env` inside Pikku functions. Use the `variables` service (see `pikku-services`):
|
|
419
484
|
|
|
420
485
|
```typescript
|
|
421
486
|
const apiKey = services.variables.get('API_KEY')
|
|
@@ -7,19 +7,19 @@ Authoritative mapping table plus side-by-side code examples showing how common b
|
|
|
7
7
|
| Generic Backend Concept | Pikku Equivalent | Skill |
|
|
8
8
|
| --------------------------------------- | --------------------------------------------------------------- | ----------------- |
|
|
9
9
|
| **Controller / Route Handler** | `pikkuFunc` / `pikkuSessionlessFunc` | `pikku-concepts` |
|
|
10
|
-
| **Route definition** (`GET /users/:id`) | `wireHTTP({ route, method, func })` | `pikku-
|
|
11
|
-
| **Middleware** (Express/Koa-style) | `pikkuMiddleware` | `pikku-
|
|
12
|
-
| **Auth Guard / Auth Middleware** | `authBearer()` / `authCookie()` / `authApiKey()` | `pikku-
|
|
13
|
-
| **Authorization / Permissions** | `pikkuPermission` / `pikkuAuth` | `pikku-
|
|
10
|
+
| **Route definition** (`GET /users/:id`) | `wireHTTP({ route, method, func })` | `pikku-wiring` |
|
|
11
|
+
| **Middleware** (Express/Koa-style) | `pikkuMiddleware` | `pikku-middleware` |
|
|
12
|
+
| **Auth Guard / Auth Middleware** | `authBearer()` / `authCookie()` / `authApiKey()` | `pikku-auth` |
|
|
13
|
+
| **Authorization / Permissions** | `pikkuPermission` / `pikkuAuth` | `pikku-auth` |
|
|
14
14
|
| **DTO / Request Validation** | Standard Schema (Zod, Valibot, ArkType) | `pikku-concepts` |
|
|
15
15
|
| **Dependency Injection** | `pikkuServices` (singleton) + `pikkuWireServices` (per-request) | `pikku-services` |
|
|
16
|
-
| **WebSocket handlers** | `wireChannel` | `pikku-
|
|
17
|
-
| **Job Queue workers** | `wireQueueWorker` | `pikku-
|
|
18
|
-
| **Cron / Scheduled tasks** | `wireScheduler` | `pikku-
|
|
16
|
+
| **WebSocket handlers** | `wireChannel` | `pikku-wiring` |
|
|
17
|
+
| **Job Queue workers** | `wireQueueWorker` | `pikku-wiring` |
|
|
18
|
+
| **Cron / Scheduled tasks** | `wireScheduler` | `pikku-wiring` |
|
|
19
19
|
| **Module / Feature grouping** | Tags + wiring files | `pikku-concepts` |
|
|
20
20
|
| **Error handling** | Throw typed errors (`NotFoundError`, `ForbiddenError`) | `pikku-concepts` |
|
|
21
21
|
| **Type-safe API client** | `npx pikku all` generates clients | `pikku-concepts` |
|
|
22
|
-
| **Secrets / Config** | `defineSecret`, `defineVariable`, `services.variables` | `pikku-
|
|
22
|
+
| **Secrets / Config** | `defineSecret`, `defineVariable`, `services.variables` | `pikku-services` |
|
|
23
23
|
|
|
24
24
|
## Route Handler / Controller → pikkuFunc
|
|
25
25
|
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pikku-deploy
|
|
3
|
+
description: >-
|
|
4
|
+
Use when deploying a Pikku app to a runtime — Express, Fastify, uWebSockets.js, the `ws` library,
|
|
5
|
+
Next.js, AWS Lambda, Cloudflare Workers or Azure Functions. Covers the bootstrap every runtime
|
|
6
|
+
shares, choosing between them, and the behaviour that differs: which accept
|
|
7
|
+
`RunHTTPWiringOptions`, how each one runs scheduled tasks, and where CORS and health checks live.
|
|
8
|
+
TRIGGER when: writing or debugging `start.ts` / a worker entry / a Lambda handler, code imports
|
|
9
|
+
`@pikku/express`, `@pikku/fastify`, `@pikku/uws`, `@pikku/ws`, `@pikku/next`, `@pikku/lambda`,
|
|
10
|
+
`@pikku/cloudflare` or `@pikku/azure-functions`, or the user asks how to serve, host or deploy a
|
|
11
|
+
Pikku app. DO NOT TRIGGER when: defining functions or wirings with no runtime-specific code.
|
|
12
|
+
installGroups: [core]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Pikku Deployment
|
|
16
|
+
|
|
17
|
+
## Agent Operating Procedure
|
|
18
|
+
|
|
19
|
+
Use this skill as an execution checklist, not reference material.
|
|
20
|
+
|
|
21
|
+
1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
22
|
+
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.
|
|
23
|
+
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
24
|
+
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.
|
|
25
|
+
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
26
|
+
|
|
27
|
+
Signatures and option keys come from `pikku doc` — run `pikku doc --ai` for the
|
|
28
|
+
installed surface. This skill is the part the compiler cannot tell you: which
|
|
29
|
+
runtime to pick, and what each one does differently once you have.
|
|
30
|
+
|
|
31
|
+
## Pick a runtime
|
|
32
|
+
|
|
33
|
+
Two families, and the difference decides how you write the entry file.
|
|
34
|
+
|
|
35
|
+
**Long-running servers** own a process. Services are built once at startup and
|
|
36
|
+
live in module scope for the life of the server.
|
|
37
|
+
|
|
38
|
+
| Runtime | Package | Reach for it when |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| Express | `@pikku/express` | An existing Express app, or you want static assets and upload handling |
|
|
41
|
+
| Fastify | `@pikku/fastify` | An existing Fastify app, or you want its stricter defaults |
|
|
42
|
+
| uWebSockets.js | `@pikku/uws` | Highest throughput, HTTP and WebSocket on one port |
|
|
43
|
+
| ws | `@pikku/ws` | WebSocket only, attached to an `http.Server` you own |
|
|
44
|
+
|
|
45
|
+
**Per-invocation runtimes** are handed a request and torn down. Services are
|
|
46
|
+
cached in module scope across warm invocations, and the deploy codegen writes
|
|
47
|
+
that caching for you.
|
|
48
|
+
|
|
49
|
+
| Runtime | Package | Reach for it when |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| AWS Lambda | `@pikku/lambda` | API Gateway, EventBridge, SQS |
|
|
52
|
+
| Cloudflare Workers | `@pikku/cloudflare` | Edge, Durable Objects for channels |
|
|
53
|
+
| Azure Functions | `@pikku/azure-functions` | Azure hosting — note channels are not implemented |
|
|
54
|
+
| Next.js | `@pikku/next` | Pikku behind Next routes, or RPC from Server Components |
|
|
55
|
+
|
|
56
|
+
Then read the reference for the one you picked: `references/express.md`,
|
|
57
|
+
`references/fastify.md`, `references/uws.md`, `references/ws.md`,
|
|
58
|
+
`references/nextjs.md`, `references/lambda.md`, `references/cloudflare.md`,
|
|
59
|
+
`references/azure.md`.
|
|
60
|
+
|
|
61
|
+
## The bootstrap every runtime shares
|
|
62
|
+
|
|
63
|
+
Importing the generated bootstrap registers your wirings; nothing routes without
|
|
64
|
+
it. `createConfig` and `createSingletonServices` come from your own
|
|
65
|
+
`services.ts`.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import './.pikku/pikku-bootstrap.gen.js'
|
|
69
|
+
import { createConfig, createSingletonServices } from './services.js'
|
|
70
|
+
|
|
71
|
+
const config = await createConfig()
|
|
72
|
+
const singletonServices = await createSingletonServices(config)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
A long-running server takes it from there. A per-invocation runtime wraps the
|
|
76
|
+
same two calls in a memoised factory, because the module may be reused across
|
|
77
|
+
invocations — every `@pikku/*` serverless package ships those factories, and
|
|
78
|
+
hand-written handlers are for the cases the deploy codegen does not cover.
|
|
79
|
+
|
|
80
|
+
## What differs, and where it bites
|
|
81
|
+
|
|
82
|
+
### `RunHTTPWiringOptions` is not accepted everywhere
|
|
83
|
+
|
|
84
|
+
`maxBodySize`, `respondWith404`, `coerceDataFromSchema` and `bubbleErrors` reach
|
|
85
|
+
the request only on the runtimes that thread them through.
|
|
86
|
+
|
|
87
|
+
| Runtime | Accepts options | Where an oversized body is actually stopped |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| Express | `init(httpOptions)` | The `express.json` parser limit, fed by `maxBodySize` |
|
|
90
|
+
| Fastify | `init(httpOptions)` | Fastify's own `bodyLimit`, set from `maxBodySize` |
|
|
91
|
+
| uWS | HTTP handler only | The handler counts bytes itself and answers `413` |
|
|
92
|
+
| ws | Yes, on the handler | `maxPayload` on the `WebSocketServer` |
|
|
93
|
+
| Next.js | Only via your own `PikkuNextJS` handler | Next's own limits |
|
|
94
|
+
| Lambda | **No** | API Gateway's payload limit |
|
|
95
|
+
| Cloudflare | Partially — `runFetch(request, hibernation, options)` | The platform's limit |
|
|
96
|
+
| Azure | **No** | Azure's request limits |
|
|
97
|
+
|
|
98
|
+
On Fastify, leaving `maxBodySize` unset keeps Fastify's stricter 1MB default
|
|
99
|
+
rather than loosening it to Pikku's 10MB fallback. On uWS the chunks are dropped
|
|
100
|
+
rather than concatenated, so an oversized request never accumulates in memory.
|
|
101
|
+
|
|
102
|
+
### Scheduled tasks run differently on all three serverless runtimes
|
|
103
|
+
|
|
104
|
+
Same `wireScheduler` declaration, three behaviours. This is the one most likely
|
|
105
|
+
to produce a silent production bug.
|
|
106
|
+
|
|
107
|
+
- **Cloudflare** matches `controller.cron` and **returns after the first match**.
|
|
108
|
+
Two tasks sharing a cron expression means only one ever runs.
|
|
109
|
+
- **Lambda** runs **every** task in the bundle, ignores the event, and logs
|
|
110
|
+
rather than rethrows a failure — one bad task cannot stop the others.
|
|
111
|
+
- **Azure** runs **every** task in the bundle, ignores both the timer argument
|
|
112
|
+
and each task's own cron, and does **not** catch per-task failures — the first
|
|
113
|
+
throw aborts the rest.
|
|
114
|
+
|
|
115
|
+
Where a runtime runs everything in the bundle, the deployment unit is what
|
|
116
|
+
decides which tasks fire, not the schedule you wrote. Reach for
|
|
117
|
+
`runScheduledTask({ name })` when one deployment genuinely bundles several tasks
|
|
118
|
+
that must fire separately.
|
|
119
|
+
|
|
120
|
+
### CORS and health checks are not uniform
|
|
121
|
+
|
|
122
|
+
- **Express** registers the health check in the **constructor**, so it answers
|
|
123
|
+
before any middleware and cannot be wrapped in auth. `enableCors` must be
|
|
124
|
+
called before `init()`.
|
|
125
|
+
- **Fastify** registers it in `init()`, so nothing answers before that runs. Its
|
|
126
|
+
`enableCors` exists but **throws `Method not implemented.`** — register
|
|
127
|
+
`@fastify/cors` yourself.
|
|
128
|
+
- **uWS** registers it in `init()` and has **no** `enableCors`, no static assets
|
|
129
|
+
and no `content` support at all.
|
|
130
|
+
- Serverless runtimes have neither; the platform in front of them owns both.
|
|
131
|
+
On Lambda, only `runFetchV2` echoes the request `Origin`, so v1 preflights
|
|
132
|
+
fail in the browser unless API Gateway or CloudFront adds the header.
|
|
133
|
+
|
|
134
|
+
### Channels need a shared store off a single process
|
|
135
|
+
|
|
136
|
+
A long-running server can hold channel state in memory. Every per-invocation
|
|
137
|
+
runtime cannot: `$connect` and `$default` are separate invocations, so
|
|
138
|
+
`channelStore` must be a real shared store (`PgChannelStore` and friends).
|
|
139
|
+
Cloudflare instead keeps state in a Durable Object, and **Azure has no channel
|
|
140
|
+
support** — `createAzureWebSocketHandler` is a stub that answers `501`.
|
|
141
|
+
|
|
142
|
+
## What NOT to do
|
|
143
|
+
|
|
144
|
+
- Do not hand-roll Cloudflare's `setupServices`. It calls
|
|
145
|
+
`setSingletonServices()`, and the core runners resolve through that global
|
|
146
|
+
slot rather than the value you were returned — a setup that only returns
|
|
147
|
+
services leaves every request throwing "Singleton services not initialized" as
|
|
148
|
+
a CF `1101`.
|
|
149
|
+
- Do not discard what a Lambda WebSocket handler returns.
|
|
150
|
+
`connectWebsocket` returns a complete `APIGatewayProxyResult`; answering a
|
|
151
|
+
hardcoded `200` instead accepts every connection, including the ones your
|
|
152
|
+
channel's auth rejected.
|
|
153
|
+
- Do not bind a `WebSocketServer` to the HTTP server on `ws` or uWS.
|
|
154
|
+
`noServer: true` is required, not stylistic — the handler performs the upgrade
|
|
155
|
+
itself so middleware and auth run against the upgrade request first.
|
|
156
|
+
- Do not assume a runtime rethrows. Express, Azure and Lambda's `runFetch` each
|
|
157
|
+
swallow or flatten errors differently; the reference for your runtime says
|
|
158
|
+
which.
|
|
@@ -1,57 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
name: pikku-deploy-azure
|
|
3
|
-
description: >-
|
|
4
|
-
Use when deploying a Pikku app to Azure Functions. Covers createAzureHandler for HTTP, storage
|
|
5
|
-
queue and timer triggers, plus AzInvocationLogger and PikkuAZTimerRequest. TRIGGER when: user
|
|
6
|
-
asks about Azure Functions, Azure deployment, or @pikku/azure-functions. DO NOT TRIGGER when:
|
|
7
|
-
user asks about AWS Lambda (use pikku-deploy-lambda) or Cloudflare Workers (use
|
|
8
|
-
pikku-deploy-cloudflare).
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Pikku Azure Functions Deployment
|
|
12
|
-
|
|
13
|
-
## Agent Operating Procedure
|
|
14
|
-
|
|
15
|
-
Use this skill as an execution checklist, not reference material.
|
|
16
|
-
|
|
17
|
-
1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
18
|
-
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.
|
|
19
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
20
|
-
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.
|
|
21
|
-
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
22
|
-
|
|
23
|
-
`@pikku/azure-functions` provides Azure Functions runtime adapters for Pikku.
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
1
|
+
# Azure Functions
|
|
26
2
|
|
|
27
3
|
```bash
|
|
28
4
|
yarn add @pikku/azure-functions @azure/functions
|
|
29
5
|
```
|
|
30
6
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- `createAzureWorkerHandler(factories)` — `createAzureHandler(factories, ['fetch'])`.
|
|
38
|
-
- `createAzureWebSocketHandler(factories)` — **a stub**: its `negotiate` always
|
|
39
|
-
answers `501 WebSocket via Azure Web PubSub not yet implemented`. Channels do
|
|
40
|
-
not work on Azure yet; do not plan a deployment around it.
|
|
41
|
-
- `AzInvocationLogger` — the logger. Note the name: there is no
|
|
42
|
-
`PikkuAzFunctionsLogger`.
|
|
43
|
-
- `PikkuAZTimerRequest` — `new PikkuAZTimerRequest(context, data)`, a
|
|
44
|
-
`PikkuRequest` carrying the data. The context argument is accepted and
|
|
45
|
-
ignored.
|
|
46
|
-
- `AzureQueueService`, `AzureDeploymentService`.
|
|
7
|
+
`createAzureHandler(factories, handlerTypes)` is the entry point, returning
|
|
8
|
+
`{ http?, queue?, timer? }` for the handler types you ask for.
|
|
9
|
+
`createAzureWorkerHandler(factories)` is `createAzureHandler(factories,
|
|
10
|
+
['fetch'])`. `factories` is `{ createConfig, createSingletonServices,
|
|
11
|
+
createPlatformServices? }`; services are built from `process.env` and cached in
|
|
12
|
+
module scope across invocations of the same instance.
|
|
47
13
|
|
|
48
|
-
`
|
|
49
|
-
|
|
50
|
-
|
|
14
|
+
**Channels do not work on Azure.** `createAzureWebSocketHandler` is a stub whose
|
|
15
|
+
`negotiate` always answers `501 WebSocket via Azure Web PubSub not yet
|
|
16
|
+
implemented` — do not plan a deployment around it.
|
|
51
17
|
|
|
52
|
-
|
|
18
|
+
Two naming traps: the logger is `AzInvocationLogger`, not
|
|
19
|
+
`PikkuAzFunctionsLogger`; and `PikkuAZTimerRequest(context, data)` accepts the
|
|
20
|
+
context argument and ignores it.
|
|
53
21
|
|
|
54
|
-
|
|
22
|
+
## Registering handlers
|
|
55
23
|
|
|
56
24
|
```typescript
|
|
57
25
|
import { app } from '@azure/functions'
|
|
@@ -86,7 +54,7 @@ app.timer('scheduler', {
|
|
|
86
54
|
Note the key names: `handlerTypes` uses **`scheduled`**, but the handler it
|
|
87
55
|
returns is **`timer`**.
|
|
88
56
|
|
|
89
|
-
|
|
57
|
+
## HTTP
|
|
90
58
|
|
|
91
59
|
The handler buffers the whole body, converts to a standard `Request`, and
|
|
92
60
|
returns the response body as **text** — a streaming or binary response is
|
|
@@ -95,7 +63,7 @@ flattened. It takes no `RunHTTPWiringOptions`, so there is no `maxBodySize` or
|
|
|
95
63
|
is logged to `console.error` and whatever the response already holds is
|
|
96
64
|
returned.
|
|
97
65
|
|
|
98
|
-
|
|
66
|
+
## Queue
|
|
99
67
|
|
|
100
68
|
The queue name comes from the message's own `queueName`, falling back to
|
|
101
69
|
`context.triggerMetadata.queueTrigger` and then `'unknown'` — a name that does
|
|
@@ -112,7 +80,7 @@ base64-encoded (Azure requires it), `delay` is milliseconds mapped to
|
|
|
112
80
|
`AZURE_QUEUE_NAME_<SCREAMING_SNAKE>` when that variable exists, otherwise used
|
|
113
81
|
as-is.
|
|
114
82
|
|
|
115
|
-
|
|
83
|
+
## Timer
|
|
116
84
|
|
|
117
85
|
The timer handler runs **every** scheduled task registered in the bundle,
|
|
118
86
|
ignoring both the `Timer` argument and each task's own cron expression. Unlike
|
|
@@ -120,7 +88,7 @@ the Lambda equivalent it does not catch per-task failures, so the first task
|
|
|
120
88
|
that throws aborts the ones after it — keep one schedule per function app, or
|
|
121
89
|
guard the task bodies yourself.
|
|
122
90
|
|
|
123
|
-
|
|
91
|
+
## Logging
|
|
124
92
|
|
|
125
93
|
`new AzInvocationLogger(context)` forwards to the invocation context's
|
|
126
94
|
`info`/`warn`/`error`/`debug`/`trace`. `setLevel()` is a **no-op**: every level
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Cloudflare Workers
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
yarn add @pikku/cloudflare
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Worker entry
|
|
8
|
+
|
|
9
|
+
`@pikku/cloudflare` ships the handler factories the deploy codegen emits — use
|
|
10
|
+
them rather than hand-rolling an `ExportedHandler`. Each returns a
|
|
11
|
+
`WorkerEntrypoint` class that sets services up on every invocation (cached after
|
|
12
|
+
the first) and adds an RPC-callable `runRpc(name, args)`:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { createCloudflareHandler } from '@pikku/cloudflare'
|
|
16
|
+
import { createConfig, createSingletonServices } from './services.js'
|
|
17
|
+
import './.pikku/pikku-bootstrap.gen.js'
|
|
18
|
+
|
|
19
|
+
export default createCloudflareHandler(
|
|
20
|
+
{ createConfig, createSingletonServices },
|
|
21
|
+
['fetch', 'scheduled']
|
|
22
|
+
)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Factory | For |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `createCloudflareHandler(factories, handlerTypes)` | combined `fetch`/`queue`/`scheduled` |
|
|
28
|
+
| `createCloudflareWorkerHandler(factories)` | HTTP / agent / RPC / workflow-orchestrator units |
|
|
29
|
+
| `createCloudflareCronHandler(factories)` | cron units |
|
|
30
|
+
| `createCloudflareQueueHandler(factories)` | queue-consumer and workflow-step units |
|
|
31
|
+
| `createCloudflareMCPHandler(factories)` | MCP units (same HTTP transport) |
|
|
32
|
+
| `createCloudflareWebSocketHandler(factories)` | channel units, delegating to the DO |
|
|
33
|
+
|
|
34
|
+
`factories` is `{ createConfig, createSingletonServices, createPlatformServices? }`.
|
|
35
|
+
|
|
36
|
+
## Service setup — do not hand-roll this
|
|
37
|
+
|
|
38
|
+
Cloudflare passes env bindings per-request, so services are built from `env`
|
|
39
|
+
rather than at module load. `setupServices(env, factories)` is exported from
|
|
40
|
+
`@pikku/cloudflare` and is what the factories call:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { setupServices } from '@pikku/cloudflare'
|
|
44
|
+
|
|
45
|
+
const services = await setupServices(env, {
|
|
46
|
+
createConfig,
|
|
47
|
+
createSingletonServices,
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Beyond building `LocalVariablesService` / `LocalSecretService` and caching the
|
|
52
|
+
result, it calls `setSingletonServices()` — and the core runners (`fetchData`,
|
|
53
|
+
`runQueueJob`, `runScheduled`) resolve services through that global slot, _not_
|
|
54
|
+
through the value you were returned. A setup function that only returns the
|
|
55
|
+
services leaves every request throwing "Singleton services not initialized" as a
|
|
56
|
+
CF `1101`. It also stashes the env via `setCloudflareEnv`, which
|
|
57
|
+
`getCloudflareEnv()` reads for bindings.
|
|
58
|
+
|
|
59
|
+
## HTTP
|
|
60
|
+
|
|
61
|
+
`runFetch(request, websocketHibernationServer?, options?)`:
|
|
62
|
+
|
|
63
|
+
- A `GET` with `Upgrade: websocket` is routed to the hibernation server. Without
|
|
64
|
+
one passed in it answers **426**, so a channel worker that forgets the second
|
|
65
|
+
argument fails every upgrade while plain HTTP keeps working.
|
|
66
|
+
- `CF-Ray` becomes the traceId when present, so a Cloudflare trace and a Pikku
|
|
67
|
+
trace line up without extra wiring.
|
|
68
|
+
- `options.exposeErrors` defaults to **`false`** — error detail is withheld from
|
|
69
|
+
responses unless you opt in.
|
|
70
|
+
|
|
71
|
+
## Scheduled tasks
|
|
72
|
+
|
|
73
|
+
`runScheduled(controller)` matches registered tasks against `controller.cron`
|
|
74
|
+
and **returns after the first match**. Two tasks sharing one cron expression
|
|
75
|
+
means only one of them ever runs — give each its own expression, or invoke
|
|
76
|
+
`runScheduledTask({ name })` per task yourself.
|
|
77
|
+
|
|
78
|
+
## WebSocket (Durable Objects)
|
|
79
|
+
|
|
80
|
+
The ready-made DO class is exported; re-export it under the binding name and
|
|
81
|
+
point the worker at it:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
export { PikkuWebSocketHibernationServer as WebSocketHibernationServer } from '@pikku/cloudflare'
|
|
85
|
+
export default createCloudflareWebSocketHandler({
|
|
86
|
+
createConfig,
|
|
87
|
+
createSingletonServices,
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Subclass `CloudflareWebSocketHibernationServer` only when you need something
|
|
92
|
+
`getParams()` cannot express — it is abstract with one method returning
|
|
93
|
+
`{ singletonServices, createWireServices? }`. The channel store
|
|
94
|
+
(`CloudflareWebsocketStore` over the DO's own storage), the event hub and the
|
|
95
|
+
channel handler factory are all built by the base class; do not supply them.
|
|
96
|
+
|
|
97
|
+
The router looks up the DO through the **`WEBSOCKET_HIBERNATION_SERVER`**
|
|
98
|
+
binding and answers `503` naming it if the binding is missing, so declare it in
|
|
99
|
+
`wrangler.toml` under exactly that name.
|
|
100
|
+
|
|
101
|
+
A throw during `onConnect` closes the socket with `1008` and answers `403
|
|
102
|
+
Forbidden` with a deliberately generic body — an auth denial and a genuine fault
|
|
103
|
+
look identical to the client. The real reason is on the logger, so read the
|
|
104
|
+
worker logs rather than the status code.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Express
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
yarn add @pikku/express
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Standalone server
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { PikkuExpressServer } from '@pikku/express'
|
|
11
|
+
import './.pikku/pikku-bootstrap.gen.js'
|
|
12
|
+
import { createConfig, createSingletonServices } from './services.js'
|
|
13
|
+
|
|
14
|
+
const config = await createConfig()
|
|
15
|
+
const singletonServices = await createSingletonServices(config)
|
|
16
|
+
|
|
17
|
+
const appServer = new PikkuExpressServer(
|
|
18
|
+
{ ...config, port: 4002, hostname: 'localhost' },
|
|
19
|
+
singletonServices.logger
|
|
20
|
+
)
|
|
21
|
+
appServer.enableExitOnSigInt()
|
|
22
|
+
await appServer.init()
|
|
23
|
+
await appServer.start()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The config extends `CoreConfig` with `port`, `hostname`, an optional
|
|
27
|
+
`healthCheckPath`, an optional `limits` map and an optional `content`
|
|
28
|
+
(`LocalContentConfig`) for static assets and file uploads. `app: Express` is
|
|
29
|
+
exposed for custom middleware, and `getHttpServer()` returns the underlying
|
|
30
|
+
`http.Server` — to attach a WebSocket server, say — but throws before `start()`.
|
|
31
|
+
|
|
32
|
+
`enableStaticAssets()` serves `content.localFileUploadPath` under
|
|
33
|
+
`content.assetUrlPrefix`, and `enableReaper()` adds a `PUT /reaper/*path` upload
|
|
34
|
+
sink for local development, path-traversal checked and bounded by
|
|
35
|
+
`content.sizeLimit` (default `1mb`). Both throw when `content` is unset.
|
|
36
|
+
|
|
37
|
+
## Ordering, and what `init` installs for you
|
|
38
|
+
|
|
39
|
+
The health check is registered in the **constructor**, so it answers before any
|
|
40
|
+
middleware you add and cannot be wrapped in auth. It defaults to
|
|
41
|
+
`/health-check`; override with `healthCheckPath`.
|
|
42
|
+
|
|
43
|
+
Everything else is installed by `init()`: `express.json`, `express.text` (for
|
|
44
|
+
`text/xml`), `express.urlencoded`, `cookie-parser`, then the Pikku middleware.
|
|
45
|
+
Call `enableCors` **before** `init` if you want CORS applied to Pikku's routes.
|
|
46
|
+
|
|
47
|
+
Express buffers the body before Pikku sees it, so the parser limit is the only
|
|
48
|
+
place an oversized request can actually be stopped. `httpOptions.maxBodySize`
|
|
49
|
+
therefore feeds those parser limits, with an explicit `config.limits` entry
|
|
50
|
+
(`json` / `xml` / `urlencoded`) still winning. Everything defaults to `1mb`.
|
|
51
|
+
|
|
52
|
+
`init` passes `logRoutes: true` and `loadSchemas: true` by default; your
|
|
53
|
+
`httpOptions` spread over them, so you can turn either off.
|
|
54
|
+
|
|
55
|
+
`stop()` throws if the server was never started. `enableExitOnSigInt()`
|
|
56
|
+
installs a SIGINT handler that stops the singleton services, then the server,
|
|
57
|
+
then exits 0.
|
|
58
|
+
|
|
59
|
+
## Middleware (existing Express app)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
yarn add @pikku/express-middleware
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import express from 'express'
|
|
67
|
+
import { pikkuExpressMiddleware } from '@pikku/express-middleware'
|
|
68
|
+
import './.pikku/pikku-bootstrap.gen.js'
|
|
69
|
+
|
|
70
|
+
const app = express()
|
|
71
|
+
app.use(express.json())
|
|
72
|
+
app.use(cookieParser())
|
|
73
|
+
app.use(
|
|
74
|
+
pikkuExpressMiddleware({
|
|
75
|
+
logger: singletonServices.logger,
|
|
76
|
+
logRoutes: true,
|
|
77
|
+
loadSchemas: true,
|
|
78
|
+
// plus any RunHTTPWiringOptions: maxBodySize, respondWith404, coerceDataFromSchema
|
|
79
|
+
})
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Options beyond `logger` are all optional: `logRoutes` logs the wiring table once
|
|
84
|
+
at startup, `loadSchemas` compiles every schema up front, and the rest are
|
|
85
|
+
`RunHTTPWiringOptions` passed through per request.
|
|
86
|
+
|
|
87
|
+
On your own app **you** own the parser stack — the middleware reads `req.body`,
|
|
88
|
+
so a body parser and `cookie-parser` must be registered before it, and
|
|
89
|
+
`maxBodySize` alone will not stop an oversized request that your parser already
|
|
90
|
+
accepted. Unmatched requests fall through to `next()` (unless `respondWith404`
|
|
91
|
+
is set), so Pikku's routes coexist with your existing ones; a streaming response
|
|
92
|
+
is the exception and does not call `next()`.
|