@pikku/cli 0.12.27 → 0.12.29
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/cli.schema.json +1 -1
- package/console-app/assets/index-ClGe-ul_.js +229 -0
- package/console-app/assets/{index-CQ29NRyR.css → index-DwUzVI5k.css} +1 -1
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +183 -161
- package/dist/.pikku/function/pikku-functions.gen.js +5 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.json +8 -0
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +6 -5
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +9 -9
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +15 -3
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/fabric/functions/validate-core.js +65 -0
- package/dist/src/fabric/functions/validate.function.js +23 -7
- package/dist/src/functions/commands/dev.js +8 -8
- package/dist/src/functions/commands/tests-coverage.js +4 -2
- package/dist/src/functions/db/annotation-parser.d.ts +7 -7
- package/dist/src/functions/db/annotation-parser.js +61 -11
- package/dist/src/functions/db/db-codegen.d.ts +4 -0
- package/dist/src/functions/db/db-codegen.js +117 -15
- package/dist/src/functions/db/local-db.d.ts +14 -1
- package/dist/src/functions/db/local-db.js +151 -37
- package/dist/src/functions/db/postgres/postgres-introspector.d.ts +8 -2
- package/dist/src/functions/db/postgres/postgres-introspector.js +26 -14
- package/dist/src/functions/wirings/auth/pikku-command-auth.d.ts +1 -0
- package/dist/src/functions/wirings/auth/pikku-command-auth.js +22 -0
- package/dist/src/functions/wirings/auth/serialize-auth-gen.d.ts +1 -0
- package/dist/src/functions/wirings/auth/serialize-auth-gen.js +115 -0
- package/dist/src/functions/workflows/all.workflow.js +1 -0
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/utils/pikku-cli-config.js +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -4
- package/skills/pikku-auth-js/SKILL.md +137 -117
- package/skills/pikku-middleware/SKILL.md +2 -2
- package/skills/pikku-services/SKILL.md +44 -7
- package/skills/pikku-workflow/SKILL.md +22 -0
- package/console-app/assets/index-BERGDBO9.js +0 -228
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.29",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"imports": {
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
|
|
29
|
-
"@pikku/core": "^0.12.
|
|
29
|
+
"@pikku/core": "^0.12.27",
|
|
30
30
|
"@pikku/deploy-cloudflare": "^0.12.3",
|
|
31
31
|
"@pikku/fetch": "^0.12.2",
|
|
32
|
-
"@pikku/inspector": "^0.12.
|
|
33
|
-
"@pikku/kysely": "^0.12.
|
|
32
|
+
"@pikku/inspector": "^0.12.15",
|
|
33
|
+
"@pikku/kysely": "^0.12.14",
|
|
34
34
|
"@pikku/kysely-node-sqlite": "^0.12.1",
|
|
35
35
|
"@pikku/node-http-server": "^0.12.1",
|
|
36
36
|
"@pikku/openapi-parser": "^0.12.10",
|
|
@@ -67,5 +67,8 @@
|
|
|
67
67
|
],
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=18"
|
|
70
|
+
},
|
|
71
|
+
"exports": {
|
|
72
|
+
".": "./dist/bin/pikku.js"
|
|
70
73
|
}
|
|
71
74
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-auth-js
|
|
3
|
-
description: 'Use when integrating Auth.js (NextAuth) with a Pikku app. Covers
|
|
4
|
-
TRIGGER when: code uses createAuthRoutes, authJsSession, createAuthHandler, user asks about Auth.js, NextAuth, OAuth providers, login/logout, or @pikku/auth-js.
|
|
3
|
+
description: 'Use when integrating Auth.js (NextAuth) with a Pikku app. Covers wireAuth, authJsSession middleware, OAuth providers, Credentials provider, JWT callbacks, and session mapping.
|
|
4
|
+
TRIGGER when: code uses wireAuth, createAuthRoutes, authJsSession, createAuthHandler, user asks about Auth.js, NextAuth, OAuth providers, login/logout, or @pikku/auth-js.
|
|
5
5
|
TRIGGER when: user asks about ANY form of authentication, login, logout, sessions, or user identity — always answer with this skill.
|
|
6
6
|
DO NOT TRIGGER when: user asks about JWT middleware (use pikku-security) or custom session services (use pikku-services).'
|
|
7
7
|
---
|
|
@@ -45,101 +45,62 @@ yarn add @pikku/auth-js @auth/core
|
|
|
45
45
|
|
|
46
46
|
Auth.js in Pikku has two independent concerns:
|
|
47
47
|
|
|
48
|
-
1. **Route wiring** (`
|
|
48
|
+
1. **Route wiring** (`wireAuth`) — mounts the Auth.js signin/signout/callback endpoints into Pikku's HTTP router. The CLI generates `auth.gen.ts` with provider imports, secret wires, and route setup.
|
|
49
49
|
2. **Session middleware** (`authJsSession`) — reads the Auth.js JWT cookie on every request and populates the Pikku session object.
|
|
50
50
|
|
|
51
|
-
Both must be present and must share the same `
|
|
51
|
+
Both must be present and must share the same `AUTH_SECRET`.
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
-
## Standard Setup (
|
|
55
|
+
## Standard Setup (OAuth Providers)
|
|
56
56
|
|
|
57
57
|
### 1. Auth wiring — `wirings/auth.wiring.ts`
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
import Credentials from '@auth/core/providers/credentials'
|
|
61
|
-
import { createAuthRoutes } from '@pikku/auth-js'
|
|
62
|
-
import type { AuthConfigOrFactory } from '@pikku/auth-js'
|
|
63
|
-
import { wireHTTPRoutes } from '#pikku'
|
|
64
|
-
|
|
65
|
-
const DEV_AUTH_SECRET = 'dev-insecure-auth-secret-change-me'
|
|
66
|
-
|
|
67
|
-
const configFactory: AuthConfigOrFactory = async (services) => {
|
|
68
|
-
const secret = await services.secrets.getSecret('AUTH_SECRET').catch(() => null) ?? DEV_AUTH_SECRET
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
providers: [
|
|
72
|
-
Credentials({
|
|
73
|
-
credentials: {
|
|
74
|
-
email: { label: 'Email', type: 'email' },
|
|
75
|
-
password: { label: 'Password', type: 'password' },
|
|
76
|
-
},
|
|
77
|
-
async authorize(credentials) {
|
|
78
|
-
const email = (credentials?.email as string)?.toLowerCase()
|
|
79
|
-
const password = credentials?.password as string
|
|
80
|
-
if (!email || !password) return null
|
|
81
|
-
|
|
82
|
-
// Look up user and verify password against your DB
|
|
83
|
-
const user = await (services as any).kysely
|
|
84
|
-
.selectFrom('appUser')
|
|
85
|
-
.where('email', '=', email)
|
|
86
|
-
.select(['userId', 'role', 'name', 'email', 'passwordHash'])
|
|
87
|
-
.executeTakeFirst()
|
|
88
|
-
|
|
89
|
-
if (!user || !user.passwordHash) return null
|
|
90
|
-
// verifyPassword must be implemented in your app — use bcrypt or argon2.
|
|
91
|
-
// See services/password.ts in seminarhof for a reference implementation.
|
|
92
|
-
const ok = await verifyPassword(password, user.passwordHash)
|
|
93
|
-
if (!ok) return null
|
|
94
|
-
|
|
95
|
-
// Return shape is the Auth.js User — add any custom claims here
|
|
96
|
-
return { id: user.userId, email: user.email, name: user.name, role: user.role }
|
|
97
|
-
},
|
|
98
|
-
}),
|
|
99
|
-
],
|
|
100
|
-
// Embed custom claims into the JWT
|
|
101
|
-
callbacks: {
|
|
102
|
-
jwt({ token, user }: any) {
|
|
103
|
-
if (user) token.role = user.role
|
|
104
|
-
return token
|
|
105
|
-
},
|
|
106
|
-
session({ session, token }: any) {
|
|
107
|
-
if (token) session.role = token.role
|
|
108
|
-
return session
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
session: { strategy: 'jwt' as const },
|
|
112
|
-
secret,
|
|
113
|
-
trustHost: true,
|
|
114
|
-
basePath: '/auth',
|
|
115
|
-
}
|
|
116
|
-
}
|
|
59
|
+
Use `wireAuth` to declare which providers you need. The CLI reads this call and generates `auth.gen.ts` with all imports, secret declarations, and route wiring automatically.
|
|
117
60
|
|
|
118
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
import { wireAuth } from '@pikku/auth-js'
|
|
63
|
+
|
|
64
|
+
wireAuth({
|
|
65
|
+
providers: ['github', 'google'],
|
|
66
|
+
callbacks: {
|
|
67
|
+
signIn: async (rpc, { user, account }) =>
|
|
68
|
+
rpc.invoke('auth:signIn', { userId: user.id, provider: account.provider }),
|
|
69
|
+
redirect: async (rpc, { url, baseUrl }) =>
|
|
70
|
+
rpc.invoke('auth:redirect', { url, baseUrl }),
|
|
71
|
+
},
|
|
72
|
+
})
|
|
119
73
|
```
|
|
120
74
|
|
|
121
75
|
**Key points:**
|
|
122
|
-
- `
|
|
123
|
-
-
|
|
124
|
-
- The
|
|
125
|
-
- `
|
|
126
|
-
- `basePath: '/auth'` must match the path your frontend hits.
|
|
76
|
+
- `providers` must be an array of string literals — the CLI inspector reads them statically and generates the `auth.gen.ts` file.
|
|
77
|
+
- `callbacks` are standard Auth.js callbacks but receive `rpc` as a first argument. Use `rpc.invoke('funcName', data)` to delegate to typed pikku functions that have access to services and sessions.
|
|
78
|
+
- The generated `auth.gen.ts` file handles provider imports, Zod schemas, `wireSecret` declarations for all credentials and `AUTH_SECRET`, and the `createAuthRoutes` + `wireHTTPRoutes` call.
|
|
79
|
+
- Do NOT edit `auth.gen.ts` — re-run `pikku auth` (or `pikku all`) to regenerate.
|
|
127
80
|
|
|
128
|
-
|
|
81
|
+
**Supported providers:** `github`, `google`, `discord`, `twitter`, `apple`, `facebook`, `linkedin`, `slack`, `spotify`, `twitch`, `gitlab`, `auth0`, `azure-ad`, `okta`
|
|
82
|
+
|
|
83
|
+
### 2. Configure `pikku.config.json`
|
|
84
|
+
|
|
85
|
+
Add `authFile` pointing to where `auth.gen.ts` should be written (must be within `srcDirectories`):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"srcDirectories": ["src"],
|
|
90
|
+
"authFile": "src/wirings/auth.gen.ts"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Middleware — `wirings/middleware.ts`
|
|
129
95
|
|
|
130
96
|
```typescript
|
|
131
97
|
import { addHTTPMiddleware } from '#pikku'
|
|
132
98
|
import { authJsSession } from '@pikku/auth-js'
|
|
133
|
-
import { sessionCookieMiddleware } from '../middleware/session-cookie.js'
|
|
134
99
|
|
|
135
|
-
// Order is load-bearing: sessionCookieMiddleware MUST run before authJsSession.
|
|
136
|
-
// If you have a custom DB session middleware it must go first, otherwise
|
|
137
|
-
// authJsSession's post-check throws when the session is set inside next().
|
|
138
100
|
addHTTPMiddleware('*', [
|
|
139
|
-
sessionCookieMiddleware, // custom session (if present) — always first
|
|
140
101
|
authJsSession({
|
|
141
102
|
secretId: 'AUTH_SECRET',
|
|
142
|
-
mapSession: (claims) => ({ userId: claims.sub as string
|
|
103
|
+
mapSession: (claims) => ({ userId: claims.sub as string }),
|
|
143
104
|
}),
|
|
144
105
|
])
|
|
145
106
|
```
|
|
@@ -163,7 +124,56 @@ cors({
|
|
|
163
124
|
})
|
|
164
125
|
```
|
|
165
126
|
|
|
166
|
-
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Credentials Provider (Username/Password)
|
|
130
|
+
|
|
131
|
+
Use `wireAuth` with the `credentials` option. The `authorize` callback receives `rpc` as a first argument so you can delegate to a typed Pikku function:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { wireAuth } from '@pikku/auth-js'
|
|
135
|
+
|
|
136
|
+
wireAuth({
|
|
137
|
+
credentials: {
|
|
138
|
+
fields: {
|
|
139
|
+
email: { label: 'Email', type: 'email' },
|
|
140
|
+
password: { label: 'Password', type: 'password' },
|
|
141
|
+
},
|
|
142
|
+
authorize: async (rpc, { email, password }) =>
|
|
143
|
+
rpc.invoke('auth:login', { email, password }),
|
|
144
|
+
},
|
|
145
|
+
callbacks: {
|
|
146
|
+
jwt: async (_rpc, { token, user }) => {
|
|
147
|
+
if (user) token.role = user.role
|
|
148
|
+
return token
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The `auth:login` function handles password verification and returns the Auth.js `User` shape (with `id` required), or `null` to reject the credentials:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
export const login = pikkuSessionlessFunc({
|
|
158
|
+
func: async ({ kysely }, { email, password }) => {
|
|
159
|
+
const user = await kysely
|
|
160
|
+
.selectFrom('appUser')
|
|
161
|
+
.where('email', '=', email.toLowerCase())
|
|
162
|
+
.select(['userId', 'role', 'name', 'email', 'passwordHash'])
|
|
163
|
+
.executeTakeFirst()
|
|
164
|
+
|
|
165
|
+
if (!user || !user.passwordHash) return null
|
|
166
|
+
const ok = await verifyPassword(password, user.passwordHash)
|
|
167
|
+
if (!ok) return null
|
|
168
|
+
|
|
169
|
+
return { id: user.userId, email: user.email, name: user.name, role: user.role }
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Auth-Protected Functions
|
|
167
177
|
|
|
168
178
|
Functions that require a session use `pikkuFunc` — anonymous callers are rejected automatically:
|
|
169
179
|
|
|
@@ -245,23 +255,58 @@ The Pikku SDK does **not** wrap these — call them directly or use `@auth/core`
|
|
|
245
255
|
|
|
246
256
|
## Secret Management
|
|
247
257
|
|
|
248
|
-
|
|
258
|
+
All auth secrets are managed through the secrets service. `wireAuth` reads `AUTH_SECRET` and each provider's credentials object at request time using `services.secrets.getSecrets(keys)`.
|
|
249
259
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
**`AUTH_SECRET`** — a random string used to sign all JWT session tokens. Required.
|
|
261
|
+
|
|
262
|
+
**Provider credentials** — each provider (e.g. `GITHUB_OAUTH`, `GOOGLE_OAUTH`) stores a JSON object with `clientId` and `clientSecret`.
|
|
263
|
+
|
|
264
|
+
Both are registered in `auth.gen.ts` via `wireSecret`, which makes them visible in the Pikku console for secret management.
|
|
254
265
|
|
|
255
266
|
**In `middleware.ts`** — use `secretId`, resolved from the secrets service at request time:
|
|
256
267
|
```typescript
|
|
257
268
|
authJsSession({ secretId: 'AUTH_SECRET', mapSession: ... })
|
|
258
269
|
```
|
|
259
270
|
|
|
260
|
-
Do **not** pass `secret: process.env.AUTH_SECRET` or any string value directly to `authJsSession`. The `secret` option no longer exists — `secretId` is the only accepted form.
|
|
271
|
+
Do **not** pass `secret: process.env.AUTH_SECRET` or any string value directly to `authJsSession`. The `secret` option no longer exists — `secretId` is the only accepted form.
|
|
261
272
|
|
|
262
273
|
---
|
|
263
274
|
|
|
264
|
-
## `
|
|
275
|
+
## `wireAuth` API
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { wireAuth } from '@pikku/auth-js'
|
|
279
|
+
import type { WireAuthOptions } from '@pikku/auth-js'
|
|
280
|
+
|
|
281
|
+
wireAuth({
|
|
282
|
+
providers: ['github', 'google'], // optional — string literals read by CLI at build time
|
|
283
|
+
credentials: { // optional — Credentials provider (username/password)
|
|
284
|
+
fields: { // optional — defines what form fields to show
|
|
285
|
+
email: { label: 'Email', type: 'email' },
|
|
286
|
+
password: { label: 'Password', type: 'password' },
|
|
287
|
+
},
|
|
288
|
+
authorize: async (rpc, credentials) =>
|
|
289
|
+
rpc.invoke('auth:login', { email: credentials.email, password: credentials.password }),
|
|
290
|
+
},
|
|
291
|
+
basePath: '/auth', // optional, defaults to '/auth'
|
|
292
|
+
callbacks: { // optional — all standard Auth.js callbacks
|
|
293
|
+
signIn: async (rpc, data) => rpc.invoke('auth:signIn', data),
|
|
294
|
+
redirect: async (rpc, { url }) => url,
|
|
295
|
+
session: async (rpc, data) => data,
|
|
296
|
+
jwt: async (rpc, data) => data,
|
|
297
|
+
},
|
|
298
|
+
})
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
- `providers` and `credentials` are both optional — use one, both, or neither.
|
|
302
|
+
- `rpc.invoke(funcName, data)` calls any registered Pikku function with full service injection. The return type is typed from your function definition.
|
|
303
|
+
- `credentials.authorize` returns the Auth.js `User` object on success, or `null` on failure.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## `createAuthRoutes` API (low-level escape hatch)
|
|
308
|
+
|
|
309
|
+
Use this only when you need full manual control, e.g. for the Credentials provider with custom `authorize` logic.
|
|
265
310
|
|
|
266
311
|
```typescript
|
|
267
312
|
import { createAuthRoutes } from '@pikku/auth-js'
|
|
@@ -283,37 +328,12 @@ wireHTTPRoutes({ routes: { auth: routes as any } })
|
|
|
283
328
|
|
|
284
329
|
## Adding Custom Claims (e.g. `role`)
|
|
285
330
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
## Adding OAuth Providers (GitHub, Google, etc.)
|
|
294
|
-
|
|
295
|
-
With `strategy: 'jwt'` no database adapter is needed — tokens are self-contained.
|
|
296
|
-
|
|
297
|
-
```typescript
|
|
298
|
-
import GitHub from '@auth/core/providers/github'
|
|
299
|
-
import Google from '@auth/core/providers/google'
|
|
300
|
-
|
|
301
|
-
const configFactory: AuthConfigOrFactory = async (services) => {
|
|
302
|
-
const secret = await services.secrets.getSecret('AUTH_SECRET').catch(() => null) ?? DEV_AUTH_SECRET
|
|
303
|
-
const github = await services.secrets.getSecretJSON('GITHUB_OAUTH').catch(() => null)
|
|
304
|
-
const google = await services.secrets.getSecretJSON('GOOGLE_OAUTH').catch(() => null)
|
|
305
|
-
|
|
306
|
-
return {
|
|
307
|
-
providers: [
|
|
308
|
-
GitHub({ clientId: github?.clientId, clientSecret: github?.clientSecret }),
|
|
309
|
-
Google({ clientId: google?.clientId, clientSecret: google?.clientSecret }),
|
|
310
|
-
],
|
|
311
|
-
session: { strategy: 'jwt' as const },
|
|
312
|
-
secret,
|
|
313
|
-
trustHost: true,
|
|
314
|
-
basePath: '/auth',
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
```
|
|
331
|
+
When using `wireAuth` with callbacks:
|
|
332
|
+
1. Return extra fields from your `signIn` callback.
|
|
333
|
+
2. Handle them in the `jwt` callback: `jwt: async (rpc, { token, user }) => { if (user) token.role = user.role; return token }`.
|
|
334
|
+
3. Expose them in `mapSession` in `authJsSession`: `role: claims.role`.
|
|
318
335
|
|
|
319
|
-
|
|
336
|
+
When using `createAuthRoutes` directly:
|
|
337
|
+
1. Return extra fields from `authorize()` in your Credentials provider.
|
|
338
|
+
2. Copy them into the JWT token in the `jwt` callback.
|
|
339
|
+
3. Expose them in `mapSession` in `authJsSession`.
|
|
@@ -145,13 +145,13 @@ Call at module load time — typically in the same `wirings/*.ts` file as the `w
|
|
|
145
145
|
|
|
146
146
|
**Scope resolution order (broadest → narrowest):**
|
|
147
147
|
|
|
148
|
-
```
|
|
148
|
+
```text
|
|
149
149
|
global → httpGroup/* → httpGroup/prefix → wiringTags → wiringMiddleware → funcTags → funcMiddleware → function body
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
**Within each scope, sorted by priority:**
|
|
153
153
|
|
|
154
|
-
```
|
|
154
|
+
```text
|
|
155
155
|
highest → high → medium (default) → low → lowest
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -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
|
|
179
|
-
|
|
|
180
|
-
| `ConsoleLogger`
|
|
181
|
-
| `JoseJWTService`
|
|
182
|
-
| `LocalSecretService`
|
|
183
|
-
| `LocalVariablesService`
|
|
184
|
-
| `PinoLogger`
|
|
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
|
|
|
@@ -71,6 +71,28 @@ await workflow.sleep('Wait 5 minutes', '5min')
|
|
|
71
71
|
await workflow.suspend('Awaiting approval')
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
### Choosing the right wrapper
|
|
75
|
+
|
|
76
|
+
| Wrapper | When to use |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `pikkuWorkflowFunc` | **Default.** Use for all new workflows. DSL mode — serialisable, replay-safe. |
|
|
79
|
+
| `pikkuWorkflowComplexFunc` | **Only with explicit user approval.** For workflows with patterns the DSL extractor cannot handle (e.g. dynamic inline functions). Not a general escape hatch — restructure first. |
|
|
80
|
+
| `pikkuWorkflowGraph` | **Only with explicit user approval.** For genuine DAGs where there is a cyclic dependency between nodes or a Node.js-only import DSL cannot express. |
|
|
81
|
+
|
|
82
|
+
**Conditional results** — the correct DSL pattern when a step only runs under some condition:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// ✅ Declare at top level, assign inside block
|
|
86
|
+
let result: { id: string } | null = null
|
|
87
|
+
if (input.createFoo) {
|
|
88
|
+
result = await workflow.do('Create foo', 'createFoo', { ... })
|
|
89
|
+
}
|
|
90
|
+
// Use result?.id downstream
|
|
91
|
+
|
|
92
|
+
// ❌ Do NOT declare const inside a block — DSL forbids block-scoped declarations
|
|
93
|
+
// ❌ Do NOT switch to pikkuWorkflowComplexFunc to avoid the restriction
|
|
94
|
+
```
|
|
95
|
+
|
|
74
96
|
### `pikkuWorkflowGraph(config)` — DAG Workflows
|
|
75
97
|
|
|
76
98
|
```typescript
|