@pikku/cli 0.12.26 → 0.12.28

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 (91) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/index-Ca6xJwNm.js +229 -0
  3. package/console-app/assets/{index-C52h1B_L.css → index-DwUzVI5k.css} +1 -1
  4. package/console-app/index.html +2 -2
  5. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  7. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  8. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  9. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  10. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  11. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  12. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  13. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  14. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  16. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  17. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  18. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  19. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  20. package/dist/.pikku/function/pikku-functions-meta.gen.json +192 -170
  21. package/dist/.pikku/function/pikku-functions.gen.js +3 -1
  22. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  23. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  24. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  25. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  26. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  27. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  28. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  29. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  30. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  31. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  32. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  33. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  34. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  35. package/dist/.pikku/pikku-types.gen.js +1 -1
  36. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  37. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  38. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  39. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.json +4 -0
  40. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  42. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  43. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +11 -10
  44. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  45. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  46. package/dist/.pikku/schemas/register.gen.js +13 -13
  47. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  48. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  49. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  50. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  51. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  52. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  53. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  54. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  55. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  56. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  57. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  58. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +8 -2
  59. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  60. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  61. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  62. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  63. package/dist/bin/pikku-bin.mjs +2 -2
  64. package/dist/src/fabric/functions/validate-core.js +6 -6
  65. package/dist/src/fabric/functions/validate.function.js +23 -7
  66. package/dist/src/functions/commands/tests-coverage.js +4 -2
  67. package/dist/src/functions/db/annotation-parser.d.ts +7 -7
  68. package/dist/src/functions/db/annotation-parser.js +61 -11
  69. package/dist/src/functions/db/db-codegen.d.ts +4 -0
  70. package/dist/src/functions/db/db-codegen.js +117 -15
  71. package/dist/src/functions/db/local-db.d.ts +6 -0
  72. package/dist/src/functions/db/local-db.js +134 -34
  73. package/dist/src/functions/db/postgres/postgres-introspector.d.ts +8 -2
  74. package/dist/src/functions/db/postgres/postgres-introspector.js +26 -14
  75. package/dist/src/functions/validate/workspace-validate.js +4 -1
  76. package/dist/src/functions/wirings/auth/pikku-command-auth.d.ts +1 -0
  77. package/dist/src/functions/wirings/auth/pikku-command-auth.js +22 -0
  78. package/dist/src/functions/wirings/auth/serialize-auth-gen.d.ts +1 -0
  79. package/dist/src/functions/wirings/auth/serialize-auth-gen.js +115 -0
  80. package/dist/src/functions/workflows/all.workflow.js +1 -0
  81. package/dist/src/scaffold/rpc-remote.gen.js +1 -1
  82. package/dist/src/utils/pikku-cli-config.js +3 -0
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +7 -4
  85. package/skills/pikku-auth-js/SKILL.md +137 -117
  86. package/skills/pikku-middleware/SKILL.md +283 -0
  87. package/skills/pikku-permissions/SKILL.md +165 -0
  88. package/skills/pikku-security/SKILL.md +38 -177
  89. package/skills/pikku-services/SKILL.md +44 -7
  90. package/skills/pikku-tag-middleware/SKILL.md +13 -0
  91. package/console-app/assets/index-Ba9K10XZ.js +0 -232
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: pikku-permissions
3
+ description: 'Use when adding authorization checks to Pikku functions or routes — pikkuPermission, pikkuAuth, per-function permissions, pattern-based permissions, or understanding OR/AND permission logic.
4
+ TRIGGER when: user wants to restrict who can call a function, check resource ownership, add role-based access, or understand where permission checks belong.
5
+ DO NOT TRIGGER when: user asks about middleware or request interception (use pikku-middleware), authentication strategies (use pikku-security), or session management.'
6
+ installGroups: [core]
7
+ ---
8
+
9
+ # Pikku Permissions
10
+
11
+ ## The Rule
12
+
13
+ **ALWAYS put authorization checks in the `permissions` field of `pikkuFunc` or `pikkuSessionlessFunc` — NEVER inside the `func` body.**
14
+
15
+ This includes: org access checks, repo access checks, role checks, resource ownership, and any other authorization logic. The `permissions` field runs before `func`, is visible to the inspector, and is the only place Pikku enforces authorization.
16
+
17
+ ```typescript
18
+ // CORRECT
19
+ export const deleteBook = pikkuFunc({
20
+ func: async ({ db }, { bookId }) => {
21
+ await db.deleteBook(bookId)
22
+ },
23
+ permissions: {
24
+ owner: isBookOwner, // ← authorization here
25
+ },
26
+ })
27
+
28
+ // WRONG — permission check inside func body
29
+ export const deleteBook = pikkuFunc({
30
+ func: async ({ db }, { bookId }, { session }) => {
31
+ if (!session) throw new UnauthorizedError() // ← never do this
32
+ await db.deleteBook(bookId)
33
+ },
34
+ })
35
+ ```
36
+
37
+ ## Agent Operating Procedure
38
+
39
+ 1. Discover before editing. Run `pikku info permissions --verbose` and `pikku info functions --verbose` to understand what permissions are already defined and applied.
40
+ 2. Define permission checkers in a `src/permissions.ts` or domain-specific `src/lib/*-permissions.ts` file.
41
+ 3. Apply them via the `permissions` field on the function, or via `addHTTPPermission` / `addPermission` for pattern/tag-based application.
42
+ 4. Validate: run `pikku tsc` to confirm permission checker signatures are correct.
43
+
44
+ ## Permission Factories
45
+
46
+ ### `pikkuAuth(fn)` — Session-Only Checks
47
+
48
+ Use for checks that only need the session — no request data required.
49
+
50
+ ```typescript
51
+ import { pikkuAuth } from '#pikku'
52
+
53
+ export const isAuthenticated = pikkuAuth(
54
+ async (_services, session) => !!session
55
+ )
56
+
57
+ export const isAdmin = pikkuAuth(
58
+ async (_services, session) => session?.role === 'admin'
59
+ )
60
+ ```
61
+
62
+ ### `pikkuPermission(fn)` — Data-Aware Checks
63
+
64
+ Use when authorization depends on the actual request data (e.g., resource ownership).
65
+
66
+ ```typescript
67
+ import { pikkuPermission } from '#pikku'
68
+
69
+ export const isBookOwner = pikkuPermission(
70
+ async ({ db }, { bookId }, { session }) => {
71
+ const book = await db.getBook(bookId)
72
+ return book?.authorId === session?.userId
73
+ }
74
+ )
75
+
76
+ export const hasBookAccess = pikkuPermission(
77
+ async ({ db }, { bookId }, { session }) => {
78
+ return await db.hasAccess(session?.userId, bookId)
79
+ }
80
+ )
81
+ ```
82
+
83
+ ## OR / AND Logic
84
+
85
+ ```typescript
86
+ permissions: {
87
+ admin: isAdmin, // OR: admins can access
88
+ owner: isBookOwner, // OR: owners can access
89
+ reviewer: [isAuthenticated, hasBookAccess], // AND: both must pass
90
+ }
91
+ // Logic: admin OR owner OR (isAuthenticated AND hasBookAccess)
92
+ ```
93
+
94
+ Groups are OR'd. Entries within a group array are AND'd.
95
+
96
+ ## Where to Apply Permissions
97
+
98
+ ### Per-Function (preferred)
99
+
100
+ ```typescript
101
+ export const deleteBook = pikkuFunc({
102
+ func: async ({ db }, { bookId }) => {
103
+ await db.deleteBook(bookId)
104
+ },
105
+ permissions: {
106
+ admin: isAdmin,
107
+ owner: isBookOwner,
108
+ },
109
+ })
110
+ ```
111
+
112
+ ### Pattern-Based (`addHTTPPermission`)
113
+
114
+ ```typescript
115
+ import { addHTTPPermission } from '@pikku/core/http'
116
+
117
+ addHTTPPermission('/admin/*', { admin: isAdmin })
118
+ ```
119
+
120
+ ### Tag-Based (`addPermission`)
121
+
122
+ ```typescript
123
+ import { addPermission } from '.pikku/pikku-types.gen.js'
124
+
125
+ addPermission('internal', { machine: isMachineAgent })
126
+ ```
127
+
128
+ ## Complete Example
129
+
130
+ ```typescript
131
+ // src/permissions.ts
132
+ import { pikkuAuth, pikkuPermission } from '#pikku'
133
+
134
+ export const isAuthenticated = pikkuAuth(
135
+ async (_services, session) => !!session
136
+ )
137
+
138
+ export const isAdmin = pikkuAuth(
139
+ async (_services, session) => session?.role === 'admin'
140
+ )
141
+
142
+ export const isOrgMember = pikkuPermission(
143
+ async ({ db }, { orgId }, { session }) => {
144
+ return await db.isMember(session?.userId, orgId)
145
+ }
146
+ )
147
+
148
+ // src/functions/org.function.ts
149
+ export const deleteOrg = pikkuFunc({
150
+ func: async ({ db }, { orgId }) => {
151
+ await db.deleteOrg(orgId)
152
+ },
153
+ permissions: {
154
+ admin: isAdmin,
155
+ owner: [isAuthenticated, isOrgMember],
156
+ },
157
+ })
158
+ ```
159
+
160
+ ## After Changes
161
+
162
+ ```bash
163
+ pikku tsc # verify permission checker types are correct
164
+ pikku all # regenerate if wirings changed
165
+ ```
@@ -1,43 +1,26 @@
1
1
  ---
2
2
  name: pikku-security
3
- description: 'Use when adding authentication, authorization, permissions, middleware, or security to a Pikku app. Covers pikkuAuth, pikkuPermission, pikkuMiddleware, built-in auth strategies (bearer, cookie, API key), and permission scoping.
4
- TRIGGER when: code uses pikkuAuth/pikkuPermission/pikkuMiddleware, user asks about auth, login, session, permissions, RBAC, middleware, or API keys.
5
- DO NOT TRIGGER when: user asks about JWT service setup (use pikku-services) or secrets/env vars (use pikku-config).'
3
+ description: 'Use when adding authentication or session management to a Pikku app pikkuAuth, session lifecycle (setSession/clearSession), built-in auth strategies (authBearer, authCookie, authAPIKey), or JWT setup.
4
+ TRIGGER when: user asks about login, logout, session, bearer tokens, cookie auth, API keys, or JWT.
5
+ DO NOT TRIGGER when: user asks about middleware (use pikku-middleware), permissions/authorization checks (use pikku-permissions), or secrets/env vars (use pikku-config).'
6
6
  installGroups: [core]
7
7
  ---
8
8
 
9
- # Pikku Security (Auth, Permissions, Middleware)
9
+ # Pikku Security (Authentication & Sessions)
10
10
 
11
11
  ## Agent Operating Procedure
12
12
 
13
- Use this skill as an execution checklist, not reference material.
13
+ 1. Discover before editing. Run `pikku info middleware --verbose` and `pikku info functions --verbose` to understand existing auth setup.
14
+ 2. Auth strategies live in wirings files — do not put `addHTTPMiddleware` calls inside function bodies.
15
+ 3. Validate with `pikku tsc` after changes; run `pikku all` if wirings changed.
14
16
 
15
- 1. Discover before editing. Prefer OpenCode tools such as `pikku-meta` when available; otherwise run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
16
- 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.
17
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
18
- 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.
19
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
17
+ For **middleware** (including tag middleware and service-to-service bearer auth) see `pikku-middleware`.
18
+ For **permissions** (pikkuPermission, pikkuAuth, per-function authorization) see `pikku-permissions`.
20
19
 
21
- Pikku provides a layered security model: authentication middleware (who are you?), auth checks (are you logged in?), and permissions (can you do this?). All work across every transport (HTTP, WebSocket, CLI, queue, etc.).
22
-
23
- ## Before You Start
24
-
25
- ```bash
26
- pikku info middleware --verbose # See existing middleware and where it's applied
27
- pikku info permissions --verbose # See existing permissions
28
- pikku info functions --verbose # See which functions have auth/permissions
29
- ```
30
-
31
- See `pikku-concepts` for the core mental model.
32
-
33
- ## API Reference
34
-
35
- ### Session Management
36
-
37
- Functions access session via the wire object:
20
+ ## Session Management
38
21
 
39
22
  ```typescript
40
- // In pikkuFunc (authenticated)
23
+ // Read session in pikkuFunc (session guaranteed to exist)
41
24
  const getProfile = pikkuFunc({
42
25
  func: async ({ db }, _data, { session }) => {
43
26
  return await db.getUser(session.userId)
@@ -62,78 +45,19 @@ const logout = pikkuFunc({
62
45
  })
63
46
  ```
64
47
 
65
- ### `pikkuAuth(fn)` Session-Only Checks
66
-
67
- Use for authentication gates that only need the session (no request data).
68
-
69
- ```typescript
70
- import { pikkuAuth } from '#pikku'
71
-
72
- // Receives (services, session)
73
- export const isAuthenticated = pikkuAuth(
74
- async (_services, session) => !!session
75
- )
76
-
77
- export const isAdmin = pikkuAuth(
78
- async (_services, session) => session?.role === 'admin'
79
- )
80
- ```
81
-
82
- ### `pikkuPermission(fn)` — Data-Aware Checks
83
-
84
- Use when authorization depends on the actual request data.
85
-
86
- ```typescript
87
- import { pikkuPermission } from '#pikku'
88
-
89
- // Receives (services, data, wire)
90
- export const isOwner = pikkuPermission(
91
- async ({ db }, { bookId }, { session }) => {
92
- const book = await db.getBook(bookId)
93
- return book?.authorId === session?.userId
94
- }
95
- )
96
-
97
- export const hasBookAccess = pikkuPermission(
98
- async ({ db }, { bookId }, { session }) => {
99
- return await db.hasAccess(session?.userId, bookId)
100
- }
101
- )
102
- ```
103
-
104
- ### Permission Groups (OR/AND Logic)
48
+ ## Built-in Auth Strategies
105
49
 
106
- ```typescript
107
- {
108
- admin: isAdmin, // OR: admins can access
109
- owner: isOwner, // OR: owners can access
110
- reviewer: [isAuthenticated, hasBookAccess], // AND: both must pass
111
- }
112
- // Logic: admin OR owner OR (isAuthenticated AND hasBookAccess)
113
- ```
114
-
115
- ### `pikkuMiddleware(fn)` — Before/After Wrapping
116
-
117
- ```typescript
118
- import { pikkuMiddleware } from '#pikku'
119
-
120
- const logRequest = pikkuMiddleware(async ({ logger }, wire, next) => {
121
- logger.info('Before')
122
- await next()
123
- logger.info('After')
124
- })
125
- ```
126
-
127
- ### Built-in Auth Middleware
50
+ Apply these via `addHTTPMiddleware` in a wirings file:
128
51
 
129
52
  ```typescript
130
53
  import { authBearer, authCookie, authAPIKey } from '@pikku/core/middleware'
54
+ import { addHTTPMiddleware } from '@pikku/core/http'
131
55
 
132
56
  // JWT bearer token — reads Authorization header
133
- addHTTPMiddleware([authBearer()])
57
+ addHTTPMiddleware('*', [authBearer()])
134
58
 
135
59
  // Cookie-based sessions — auto-refreshes JWT
136
- addHTTPMiddleware([
60
+ addHTTPMiddleware('*', [
137
61
  authCookie({
138
62
  name: 'session',
139
63
  expiresIn: { value: 30, unit: 'day' },
@@ -141,48 +65,8 @@ addHTTPMiddleware([
141
65
  }),
142
66
  ])
143
67
 
144
- // API key — from x-api-key header or ?apiKey= query
145
- addHTTPMiddleware([authAPIKey({ source: 'all' })])
146
- ```
147
-
148
- ### Scoping: Where to Apply
149
-
150
- Four levels of scoping, from broadest to narrowest:
151
-
152
- ```typescript
153
- // 1. Global: all HTTP routes
154
- addHTTPMiddleware('*', [authBearer()])
155
-
156
- // 2. Prefix-based: URL pattern
157
- addHTTPMiddleware('/admin/*', [auditLog])
158
- addHTTPPermission('/admin/*', { admin: requireAdmin })
159
-
160
- // 3. Tag-based: any wiring with matching tag
161
- addMiddleware('api', [rateLimiter])
162
- addPermission('api', { auth: requireAuth })
163
-
164
- // 4. Inline: per-wiring
165
- wireHTTP({
166
- route: '/books/:id',
167
- func: getBook,
168
- middleware: [cacheControl],
169
- permissions: { owner: requireOwnership },
170
- })
171
- ```
172
-
173
- ### Per-Function Permissions
174
-
175
- ```typescript
176
- export const deleteBook = pikkuFunc({
177
- func: async ({ db }, { bookId }) => {
178
- await db.deleteBook(bookId)
179
- },
180
- permissions: {
181
- admin: isAdmin,
182
- owner: isOwner,
183
- reviewer: [isAuthenticated, hasBookAccess],
184
- },
185
- })
68
+ // API key — from x-api-key header or ?apiKey= query param
69
+ addHTTPMiddleware('*', [authAPIKey({ source: 'all' })])
186
70
  ```
187
71
 
188
72
  ## Complete Example
@@ -191,53 +75,30 @@ export const deleteBook = pikkuFunc({
191
75
  // permissions.ts
192
76
  import { pikkuAuth, pikkuPermission } from '#pikku'
193
77
 
194
- export const isAuthenticated = pikkuAuth(
195
- async (_services, session) => !!session
196
- )
197
-
198
- export const isAdmin = pikkuAuth(
199
- async (_services, session) => session?.role === 'admin'
200
- )
201
-
202
- export const isBookOwner = pikkuPermission(
203
- async ({ db }, { bookId }, { session }) => {
204
- const book = await db.getBook(bookId)
205
- return book?.authorId === session?.userId
206
- }
207
- )
208
-
209
- // middleware.ts
210
- import { pikkuMiddleware } from '#pikku'
211
-
212
- export const auditLog = pikkuMiddleware(async ({ logger, db }, wire, next) => {
213
- const start = Date.now()
214
- await next()
215
- await db.createAuditLog({
216
- duration: Date.now() - start,
217
- })
218
- })
219
-
220
- // wirings/security.wiring.ts
221
- import { authBearer } from '@pikku/core/middleware'
222
- import { addHTTPMiddleware, addHTTPPermission } from '#pikku'
78
+ export const isAuthenticated = pikkuAuth(async (_services, session) => !!session)
79
+ export const isAdmin = pikkuAuth(async (_services, session) => session?.role === 'admin')
223
80
 
224
- // All routes require bearer auth
225
- addHTTPMiddleware('*', [authBearer()])
81
+ // wirings/auth.wiring.ts
82
+ import { authCookie } from '@pikku/core/middleware'
83
+ import { addHTTPMiddleware } from '@pikku/core/http'
226
84
 
227
- // Admin routes need admin permission + audit logging
228
- addHTTPMiddleware('/admin/*', [auditLog])
229
- addHTTPPermission('/admin/*', { admin: isAdmin })
85
+ addHTTPMiddleware('*', [
86
+ authCookie({ name: 'session', expiresIn: { value: 30, unit: 'day' } }),
87
+ ])
230
88
 
231
- // functions/books.functions.ts
232
- export const deleteBook = pikkuFunc({
233
- title: 'Delete Book',
234
- func: async ({ db }, { bookId }) => {
235
- await db.deleteBook(bookId)
236
- return { deleted: true }
89
+ // functions/auth.functions.ts
90
+ export const login = pikkuFunc({
91
+ auth: false,
92
+ func: async ({ jwt, db }, { email, password }, { setSession }) => {
93
+ const user = await db.verifyCredentials(email, password)
94
+ setSession({ userId: user.id, role: user.role })
95
+ return { token: jwt.sign({ userId: user.id }) }
237
96
  },
238
- permissions: {
239
- admin: isAdmin,
240
- owner: isBookOwner,
97
+ })
98
+
99
+ export const logout = pikkuFunc({
100
+ func: async ({}, _data, { clearSession }) => {
101
+ clearSession()
241
102
  },
242
103
  })
243
104
  ```
@@ -173,15 +173,52 @@ const createSingletonServices = pikkuServices(async (config) => {
173
173
  })
174
174
  ```
175
175
 
176
+ ### Audit Wire Service
177
+
178
+ `createInvocationAudit` creates a per-request `InvocationAuditLog` that buffers audit events in memory and flushes them as a batch when the function-runner calls `closeWireServices` at the end of the request. If `singletonServices.audit` is not configured (local dev without Fabric), it returns a no-op `DisabledInvocationAudit` — no crash, events are silently dropped.
179
+
180
+ Pair with `createAuditedKysely` to auto-capture every Kysely query as an audit event.
181
+
182
+ ```typescript
183
+ // services.ts
184
+ import { createInvocationAudit } from '@pikku/core/services'
185
+ import { createAuditedKysely } from '@pikku/kysely'
186
+
187
+ export const createWireServices = pikkuWireServices(async (singletonServices, wire) => {
188
+ const audit = createInvocationAudit(singletonServices.audit, wire)
189
+ const kysely = singletonServices.kysely
190
+ ? createAuditedKysely(singletonServices.kysely, { audit })
191
+ : undefined
192
+ return { audit, ...(kysely ? { kysely } : {}) }
193
+ })
194
+ ```
195
+
196
+ The `audit` wire service is typed as `AuditLog` (from `@pikku/core`). Functions that emit custom events use it directly:
197
+
198
+ ```typescript
199
+ const deleteUser = pikkuFunc({
200
+ func: async ({ audit }, { userId }) => {
201
+ await audit.audit({ type: 'user.deleted', actor_user_id: userId })
202
+ // ...
203
+ },
204
+ })
205
+ ```
206
+
207
+ `closeWireServices` (called automatically by the function-runner) invokes `audit.close()` → `singletonServices.audit.write(batch)` → platform-specific flush (e.g. CF Queue, libsql INSERT). No manual flushing needed.
208
+
209
+ > **Fabric note:** Fabric provisions the audit queue and consumer worker automatically. The audit table schema is in `db/sqlite/0003-audit.sql` (starter-template). Run `pikku fabric validate` to confirm the migration is in place.
210
+
176
211
  ### Built-in Services
177
212
 
178
- | Service | Package | Purpose |
179
- | ----------------------- | ---------------------- | --------------------------- |
180
- | `ConsoleLogger` | `@pikku/core/services` | Console-based logging |
181
- | `JoseJWTService` | `@pikku/jose` | JWT sign/verify via jose |
182
- | `LocalSecretService` | `@pikku/core/services` | Local development secrets |
183
- | `LocalVariablesService` | `@pikku/core/services` | Local environment variables |
184
- | `PinoLogger` | `@pikku/pino` | Structured logging via Pino |
213
+ | Service | Package | Purpose |
214
+ | -------------------------- | ---------------------- | -------------------------------- |
215
+ | `ConsoleLogger` | `@pikku/core/services` | Console-based logging |
216
+ | `JoseJWTService` | `@pikku/jose` | JWT sign/verify via jose |
217
+ | `LocalSecretService` | `@pikku/core/services` | Local development secrets |
218
+ | `LocalVariablesService` | `@pikku/core/services` | Local environment variables |
219
+ | `PinoLogger` | `@pikku/pino` | Structured logging via Pino |
220
+ | `createInvocationAudit` | `@pikku/core/services` | Per-request audit buffer |
221
+ | `createAuditedKysely` | `@pikku/kysely` | Auto-capture DB queries as audit events |
185
222
 
186
223
  ## Complete Example
187
224
 
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: pikku-tag-middleware
3
+ description: 'Deprecated — use pikku-middleware instead. Tag middleware (addTagMiddleware) is now documented as a section within the pikku-middleware skill, alongside global HTTP middleware, execution order, and the service-to-service bearer auth pattern.'
4
+ ---
5
+
6
+ # Deprecated: use `pikku-middleware`
7
+
8
+ Tag middleware is covered in the **`pikku-middleware`** skill, which also covers:
9
+ - `addHTTPMiddleware` (global / prefix-based)
10
+ - `addTagMiddleware` (tag-scoped)
11
+ - Middleware execution order and priority
12
+ - Service-to-service bearer auth pattern
13
+ - Session-setting middleware pattern