@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.
Files changed (222) hide show
  1. package/LICENSE +106 -0
  2. package/console-app/assets/{index-CpkvmAGb.js → index-DDpIMCpy.js} +149 -149
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  7. package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
  8. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  9. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  11. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  12. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +15 -0
  13. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  14. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  15. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +21 -0
  17. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  18. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  19. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  20. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  21. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  22. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  23. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  24. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  25. package/dist/.pikku/function/pikku-functions-meta.gen.json +35 -40
  26. package/dist/.pikku/function/pikku-functions.gen.js +1 -3
  27. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  28. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  29. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  30. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  31. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +2 -1
  32. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +2 -1
  33. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  34. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  35. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  36. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  37. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  38. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  39. package/dist/.pikku/pikku-types.gen.js +1 -1
  40. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  42. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  43. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  44. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  45. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  46. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +1 -1
  47. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  48. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  49. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  50. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  51. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
  52. package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
  53. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  54. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  55. package/dist/.pikku/schemas/register.gen.js +5 -3
  56. package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
  57. package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
  58. package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
  59. package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
  60. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  61. package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
  62. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  63. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  64. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  65. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  66. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  67. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  68. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  69. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  70. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  71. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  72. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  73. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  74. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  75. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +2 -8
  76. package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +1 -1
  77. package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +1 -1
  78. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  79. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  80. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  81. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  82. package/dist/bin/pikku-bin.mjs +2 -2
  83. package/dist/src/cli.wiring.js +6 -0
  84. package/dist/src/deploy/analyzer/analyzer.js +22 -5
  85. package/dist/src/deploy/build-pipeline.js +5 -1
  86. package/dist/src/fabric/fabric-commands.d.ts +37 -9
  87. package/dist/src/fabric/fabric-commands.js +12 -0
  88. package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
  89. package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
  90. package/dist/src/fabric/functions/secrets-list.function.js +12 -10
  91. package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
  92. package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
  93. package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
  94. package/dist/src/fabric/functions/secrets-set.function.js +18 -7
  95. package/dist/src/fabric/lib/http.d.ts +7 -1
  96. package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
  97. package/dist/src/fabric/lib/sealed-box.js +72 -0
  98. package/dist/src/functions/commands/dev.js +9 -0
  99. package/dist/src/functions/commands/pikku-command-bootstrap.js +1 -0
  100. package/dist/src/functions/commands/scenario-browser.d.ts +17 -2
  101. package/dist/src/functions/commands/scenario-browser.js +16 -8
  102. package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
  103. package/dist/src/functions/commands/scenario-environment.js +61 -0
  104. package/dist/src/functions/commands/scenario.d.ts +6 -0
  105. package/dist/src/functions/commands/scenario.js +14 -9
  106. package/dist/src/functions/commands/skills.js +27 -61
  107. package/dist/src/functions/db/db-codegen.d.ts +6 -0
  108. package/dist/src/functions/db/db-codegen.js +9 -0
  109. package/dist/src/functions/db/db-migrator.js +14 -0
  110. package/dist/src/functions/db/local-db.d.ts +8 -0
  111. package/dist/src/functions/db/local-db.js +24 -2
  112. package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
  113. package/dist/src/functions/db/migration-identifiers.js +262 -0
  114. package/dist/src/functions/db/migration-provenance.d.ts +35 -0
  115. package/dist/src/functions/db/migration-provenance.js +80 -0
  116. package/dist/src/functions/db/schema-sql.d.ts +43 -0
  117. package/dist/src/functions/db/schema-sql.js +135 -0
  118. package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
  119. package/dist/src/functions/wirings/functions/schemas.js +13 -1
  120. package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
  121. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
  122. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
  123. package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +13 -0
  124. package/dist/src/functions/wirings/scenarios/scenario-partition.js +15 -2
  125. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
  126. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
  127. package/dist/src/functions/workflows/all.workflow.js +2 -7
  128. package/dist/src/utils/file-writer.js +14 -2
  129. package/dist/src/utils/pikku-cli-config.d.ts +14 -0
  130. package/dist/src/utils/pikku-cli-config.js +34 -0
  131. package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
  132. package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
  133. package/dist/src/utils/serialize-schemas.d.ts +3 -1
  134. package/dist/src/utils/serialize-schemas.js +39 -4
  135. package/dist/tsconfig.tsbuildinfo +1 -1
  136. package/package.json +9 -9
  137. package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
  138. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
  139. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
  140. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
  141. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
  142. package/skills/pikku-addon/SKILL.md +0 -243
  143. package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
  144. package/skills/pikku-ai-agent/SKILL.md +0 -231
  145. package/skills/pikku-ai-vercel/SKILL.md +0 -82
  146. package/skills/pikku-ai-voice/SKILL.md +0 -88
  147. package/skills/pikku-audit/SKILL.md +0 -175
  148. package/skills/pikku-aws/SKILL.md +0 -111
  149. package/skills/pikku-backblaze/SKILL.md +0 -71
  150. package/skills/pikku-better-auth/SKILL.md +0 -298
  151. package/skills/pikku-cli/SKILL.md +0 -198
  152. package/skills/pikku-cli/references/complete-example.md +0 -82
  153. package/skills/pikku-concepts/SKILL.md +0 -250
  154. package/skills/pikku-concepts/references/concept-mapping.md +0 -556
  155. package/skills/pikku-concepts/references/packages.md +0 -29
  156. package/skills/pikku-config/SKILL.md +0 -212
  157. package/skills/pikku-cron/SKILL.md +0 -214
  158. package/skills/pikku-deploy-azure/SKILL.md +0 -71
  159. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
  160. package/skills/pikku-deploy-express/SKILL.md +0 -86
  161. package/skills/pikku-deploy-fastify/SKILL.md +0 -73
  162. package/skills/pikku-deploy-lambda/SKILL.md +0 -110
  163. package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
  164. package/skills/pikku-deploy-uws/SKILL.md +0 -88
  165. package/skills/pikku-deps/SKILL.md +0 -98
  166. package/skills/pikku-emails/SKILL.md +0 -163
  167. package/skills/pikku-fabric/SKILL.md +0 -318
  168. package/skills/pikku-fabric-debug/SKILL.md +0 -112
  169. package/skills/pikku-feature/SKILL.md +0 -258
  170. package/skills/pikku-gateway-slack/SKILL.md +0 -115
  171. package/skills/pikku-http/SKILL.md +0 -220
  172. package/skills/pikku-http/references/http-options.md +0 -55
  173. package/skills/pikku-i18n/SKILL.md +0 -137
  174. package/skills/pikku-info/SKILL.md +0 -100
  175. package/skills/pikku-jose/SKILL.md +0 -105
  176. package/skills/pikku-kysely/SKILL.md +0 -219
  177. package/skills/pikku-machine-auth/SKILL.md +0 -183
  178. package/skills/pikku-mcp/SKILL.md +0 -241
  179. package/skills/pikku-middleware/SKILL.md +0 -231
  180. package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
  181. package/skills/pikku-mongodb/SKILL.md +0 -105
  182. package/skills/pikku-n8n-import/SKILL.md +0 -109
  183. package/skills/pikku-n8n-import/SPEC.md +0 -84
  184. package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
  185. package/skills/pikku-n8n-import/references/code-translation.md +0 -121
  186. package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
  187. package/skills/pikku-paraglide/SKILL.md +0 -117
  188. package/skills/pikku-permissions/SKILL.md +0 -192
  189. package/skills/pikku-pino/SKILL.md +0 -79
  190. package/skills/pikku-product-second-opinion/README.md +0 -43
  191. package/skills/pikku-product-second-opinion/SKILL.md +0 -158
  192. package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
  193. package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
  194. package/skills/pikku-queue/SKILL.md +0 -240
  195. package/skills/pikku-react/SKILL.md +0 -212
  196. package/skills/pikku-react-query/SKILL.md +0 -242
  197. package/skills/pikku-realtime/SKILL.md +0 -236
  198. package/skills/pikku-realtime/references/other-routes.md +0 -23
  199. package/skills/pikku-redis/SKILL.md +0 -90
  200. package/skills/pikku-rpc/SKILL.md +0 -171
  201. package/skills/pikku-rtl/SKILL.md +0 -219
  202. package/skills/pikku-scenario/SKILL.md +0 -382
  203. package/skills/pikku-schedule/SKILL.md +0 -57
  204. package/skills/pikku-schema-ajv/SKILL.md +0 -62
  205. package/skills/pikku-schema-cfworker/SKILL.md +0 -63
  206. package/skills/pikku-security/SKILL.md +0 -108
  207. package/skills/pikku-services/SKILL.md +0 -248
  208. package/skills/pikku-services/references/audit-wire-service.md +0 -34
  209. package/skills/pikku-software-archaeology/README.md +0 -70
  210. package/skills/pikku-software-archaeology/SKILL.md +0 -186
  211. package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
  212. package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
  213. package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
  214. package/skills/pikku-tag-middleware/SKILL.md +0 -13
  215. package/skills/pikku-template-clone/SKILL.md +0 -40
  216. package/skills/pikku-trigger/SKILL.md +0 -181
  217. package/skills/pikku-versioning/SKILL.md +0 -173
  218. package/skills/pikku-websocket/SKILL.md +0 -243
  219. package/skills/pikku-workflow/SKILL.md +0 -172
  220. package/skills/pikku-workflow/references/workflow-reference.md +0 -63
  221. package/skills/pikku-workflows-client/SKILL.md +0 -150
  222. 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.) |