create-questpie 2.0.4 → 2.1.0
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/dist/index.mjs +362 -119
- package/package.json +2 -3
- package/templates/elysia/AGENTS.md +56 -0
- package/templates/elysia/CLAUDE.md +39 -0
- package/templates/elysia/Dockerfile +24 -0
- package/templates/elysia/README.md +148 -0
- package/templates/elysia/docker/init-extensions.sql +11 -0
- package/templates/elysia/docker-compose.yml +21 -0
- package/templates/elysia/env.example +16 -0
- package/templates/elysia/gitignore +6 -0
- package/templates/elysia/package.json +47 -0
- package/templates/elysia/questpie.config.ts +12 -0
- package/templates/elysia/src/index.ts +21 -0
- package/templates/elysia/src/lib/auth-client.ts +32 -0
- package/templates/elysia/src/lib/client.ts +13 -0
- package/templates/elysia/src/lib/env.ts +24 -0
- package/templates/elysia/src/lib/query-client.ts +18 -0
- package/templates/elysia/src/lib/query.ts +18 -0
- package/templates/elysia/src/questpie/server/.generated/context.gen.ts +200 -0
- package/templates/elysia/src/questpie/server/.generated/entities.gen.ts +84 -0
- package/templates/elysia/src/questpie/server/.generated/factories.ts +65 -0
- package/templates/elysia/src/questpie/server/.generated/index.ts +131 -0
- package/templates/elysia/src/questpie/server/.generated/names.gen.ts +25 -0
- package/templates/elysia/src/questpie/server/app.ts +10 -0
- package/templates/elysia/src/questpie/server/collections/index.ts +1 -0
- package/templates/elysia/src/questpie/server/collections/posts.collection.ts +10 -0
- package/templates/elysia/src/questpie/server/config/auth.ts +8 -0
- package/templates/elysia/src/questpie/server/config/openapi.ts +10 -0
- package/templates/elysia/src/questpie/server/globals/index.ts +1 -0
- package/templates/elysia/src/questpie/server/globals/site-settings.global.ts +10 -0
- package/templates/elysia/src/questpie/server/modules.ts +8 -0
- package/templates/elysia/src/questpie/server/questpie.config.ts +21 -0
- package/templates/elysia/tsconfig.json +28 -0
- package/templates/hono/AGENTS.md +56 -0
- package/templates/hono/CLAUDE.md +39 -0
- package/templates/hono/Dockerfile +24 -0
- package/templates/hono/README.md +148 -0
- package/templates/hono/docker/init-extensions.sql +11 -0
- package/templates/hono/docker-compose.yml +21 -0
- package/templates/hono/env.example +16 -0
- package/templates/hono/gitignore +6 -0
- package/templates/hono/package.json +47 -0
- package/templates/hono/questpie.config.ts +12 -0
- package/templates/hono/src/index.ts +30 -0
- package/templates/hono/src/lib/auth-client.ts +32 -0
- package/templates/hono/src/lib/client.ts +13 -0
- package/templates/hono/src/lib/env.ts +24 -0
- package/templates/hono/src/lib/query-client.ts +18 -0
- package/templates/hono/src/lib/query.ts +18 -0
- package/templates/hono/src/questpie/server/.generated/context.gen.ts +200 -0
- package/templates/hono/src/questpie/server/.generated/entities.gen.ts +84 -0
- package/templates/hono/src/questpie/server/.generated/factories.ts +65 -0
- package/templates/hono/src/questpie/server/.generated/index.ts +131 -0
- package/templates/hono/src/questpie/server/.generated/names.gen.ts +25 -0
- package/templates/hono/src/questpie/server/app.ts +10 -0
- package/templates/hono/src/questpie/server/collections/index.ts +1 -0
- package/templates/hono/src/questpie/server/collections/posts.collection.ts +10 -0
- package/templates/hono/src/questpie/server/config/auth.ts +8 -0
- package/templates/hono/src/questpie/server/config/openapi.ts +10 -0
- package/templates/hono/src/questpie/server/globals/index.ts +1 -0
- package/templates/hono/src/questpie/server/globals/site-settings.global.ts +10 -0
- package/templates/hono/src/questpie/server/modules.ts +8 -0
- package/templates/hono/src/questpie/server/questpie.config.ts +21 -0
- package/templates/hono/tsconfig.json +28 -0
- package/templates/next/AGENTS.md +55 -0
- package/templates/next/CLAUDE.md +39 -0
- package/templates/next/Dockerfile +25 -0
- package/templates/next/README.md +148 -0
- package/templates/next/components.json +22 -0
- package/templates/next/docker/init-extensions.sql +11 -0
- package/templates/next/docker-compose.yml +21 -0
- package/templates/next/env.example +16 -0
- package/templates/next/gitignore +10 -0
- package/templates/next/next-env.d.ts +5 -0
- package/templates/next/next.config.ts +20 -0
- package/templates/next/package.json +54 -0
- package/templates/next/postcss.config.mjs +8 -0
- package/templates/next/public/.gitkeep +0 -0
- package/templates/next/questpie.config.ts +12 -0
- package/templates/next/src/app/admin/[[...all]]/page.tsx +34 -0
- package/templates/next/src/app/admin/admin.css +4 -0
- package/templates/next/src/app/admin/layout.tsx +63 -0
- package/templates/next/src/app/api/[...all]/route.ts +24 -0
- package/templates/next/src/app/layout.tsx +24 -0
- package/templates/next/src/app/not-found.tsx +18 -0
- package/templates/next/src/app/page.tsx +74 -0
- package/templates/next/src/app/providers.tsx +11 -0
- package/templates/next/src/lib/auth-client.ts +12 -0
- package/templates/next/src/lib/client.ts +13 -0
- package/templates/next/src/lib/env.ts +24 -0
- package/templates/next/src/lib/query-client.ts +18 -0
- package/templates/next/src/lib/query.ts +18 -0
- package/templates/next/src/questpie/admin/.generated/client.ts +13 -0
- package/templates/next/src/questpie/admin/admin.ts +9 -0
- package/templates/next/src/questpie/admin/modules.ts +3 -0
- package/templates/next/src/questpie/server/.generated/context.gen.ts +204 -0
- package/templates/next/src/questpie/server/.generated/entities.gen.ts +100 -0
- package/templates/next/src/questpie/server/.generated/factories.ts +204 -0
- package/templates/next/src/questpie/server/.generated/index.ts +139 -0
- package/templates/next/src/questpie/server/.generated/names.gen.ts +31 -0
- package/templates/next/src/questpie/server/app.ts +10 -0
- package/templates/next/src/questpie/server/collections/index.ts +1 -0
- package/templates/next/src/questpie/server/collections/posts.collection.ts +58 -0
- package/templates/next/src/questpie/server/config/admin.ts +80 -0
- package/templates/next/src/questpie/server/config/auth.ts +8 -0
- package/templates/next/src/questpie/server/config/openapi.ts +10 -0
- package/templates/next/src/questpie/server/globals/index.ts +1 -0
- package/templates/next/src/questpie/server/globals/site-settings.global.ts +19 -0
- package/templates/next/src/questpie/server/modules.ts +9 -0
- package/templates/next/src/questpie/server/questpie.config.ts +21 -0
- package/templates/next/src/styles.css +125 -0
- package/templates/next/tsconfig.json +37 -0
- package/templates/tanstack-start/AGENTS.md +35 -607
- package/templates/tanstack-start/CLAUDE.md +26 -134
- package/templates/tanstack-start/README.md +13 -1
- package/templates/tanstack-start/docker/init-extensions.sql +11 -0
- package/templates/tanstack-start/docker-compose.yml +1 -0
- package/templates/tanstack-start/src/lib/auth-client.ts +1 -1
- package/templates/tanstack-start/src/lib/client.ts +1 -1
- package/templates/tanstack-start/src/lib/query.ts +18 -0
- package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/questpie.config.ts +1 -1
- package/templates/tanstack-start/src/routes/__root.tsx +31 -1
- package/templates/tanstack-start/src/routes/api/$.ts +1 -1
- package/templates/tanstack-start/src/routes/index.tsx +97 -0
- package/skills/questpie/AGENTS.md +0 -2871
- package/skills/questpie/SKILL.md +0 -293
- package/skills/questpie/coverage.json +0 -213
- package/skills/questpie/references/auth.md +0 -236
- package/skills/questpie/references/business-logic.md +0 -620
- package/skills/questpie/references/codegen-plugin-api.md +0 -382
- package/skills/questpie/references/crud-api.md +0 -580
- package/skills/questpie/references/data-modeling.md +0 -509
- package/skills/questpie/references/extend.md +0 -584
- package/skills/questpie/references/field-types.md +0 -398
- package/skills/questpie/references/infrastructure-adapters.md +0 -720
- package/skills/questpie/references/mcp.md +0 -147
- package/skills/questpie/references/multi-tenancy.md +0 -363
- package/skills/questpie/references/production.md +0 -640
- package/skills/questpie/references/query-operators.md +0 -125
- package/skills/questpie/references/quickstart.md +0 -562
- package/skills/questpie/references/rules.md +0 -454
- package/skills/questpie/references/sandbox.md +0 -110
- package/skills/questpie/references/tanstack-query.md +0 -543
- package/skills/questpie/references/type-inference.md +0 -167
- package/skills/questpie/references/workflows.md +0 -155
- package/skills/questpie-admin/AGENTS.md +0 -1515
- package/skills/questpie-admin/SKILL.md +0 -443
- package/skills/questpie-admin/references/blocks.md +0 -331
- package/skills/questpie-admin/references/custom-ui.md +0 -305
- package/skills/questpie-admin/references/views.md +0 -449
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# Authentication Reference
|
|
2
|
-
|
|
3
|
-
Detailed authentication configuration for QUESTPIE using Better Auth.
|
|
4
|
-
|
|
5
|
-
## File Convention
|
|
6
|
-
|
|
7
|
-
Auth is configured via `config/auth.ts` using the `authConfig()` factory:
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
// src/questpie/server/config/auth.ts
|
|
11
|
-
import { authConfig } from "questpie/app";
|
|
12
|
-
export default authConfig({
|
|
13
|
-
emailAndPassword: {
|
|
14
|
-
enabled: true,
|
|
15
|
-
requireEmailVerification: false,
|
|
16
|
-
},
|
|
17
|
-
baseURL: process.env.APP_URL || "http://localhost:3000",
|
|
18
|
-
basePath: "/api/auth",
|
|
19
|
-
secret: process.env.BETTER_AUTH_SECRET || "change-me",
|
|
20
|
-
});
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Codegen discovers this file automatically. No manual registration needed.
|
|
24
|
-
|
|
25
|
-
## Configuration Options
|
|
26
|
-
|
|
27
|
-
| Option | Type | Default | Description |
|
|
28
|
-
| ------------------------------------------- | --------- | ------------- | ----------------------------------------------------------- |
|
|
29
|
-
| `emailAndPassword.enabled` | `boolean` | `false` | Enable email/password authentication |
|
|
30
|
-
| `emailAndPassword.requireEmailVerification` | `boolean` | `false` | Require email verification before login |
|
|
31
|
-
| `baseURL` | `string` | — | Application public URL (used for OAuth callbacks) |
|
|
32
|
-
| `basePath` | `string` | `"/api/auth"` | Auth API route prefix |
|
|
33
|
-
| `secret` | `string` | — | Session signing secret. **Must be 32+ chars in production** |
|
|
34
|
-
|
|
35
|
-
## Session Access
|
|
36
|
-
|
|
37
|
-
### In Routes
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { route } from "questpie/services";
|
|
41
|
-
import z from "zod";
|
|
42
|
-
|
|
43
|
-
export default route()
|
|
44
|
-
.post()
|
|
45
|
-
.schema(z.object({ postId: z.string() }))
|
|
46
|
-
.handler(async ({ input, session, collections }) => {
|
|
47
|
-
if (!session) {
|
|
48
|
-
throw new Error("Not authenticated");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const user = session.user;
|
|
52
|
-
// user.id - unique user ID
|
|
53
|
-
// user.email - user email address
|
|
54
|
-
// user.name - user display name
|
|
55
|
-
|
|
56
|
-
const post = await collections.posts.create({
|
|
57
|
-
title: "My Post",
|
|
58
|
-
author: user.id,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return post;
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### In Hooks
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
.hooks({
|
|
69
|
-
beforeChange: async ({ data, operation, session }) => {
|
|
70
|
-
if (operation === "create") {
|
|
71
|
-
if (!session) throw new Error("Must be logged in");
|
|
72
|
-
data.createdBy = session.user.id;
|
|
73
|
-
}
|
|
74
|
-
return data;
|
|
75
|
-
},
|
|
76
|
-
})
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### In Access Rules
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
.access({
|
|
83
|
-
// Public read
|
|
84
|
-
read: true,
|
|
85
|
-
|
|
86
|
-
// Authenticated users can create
|
|
87
|
-
create: ({ session }) => !!session,
|
|
88
|
-
|
|
89
|
-
// Only admins can update/delete
|
|
90
|
-
update: ({ session }) => (session?.user as any)?.role === "admin",
|
|
91
|
-
delete: ({ session }) => (session?.user as any)?.role === "admin",
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## User Collection
|
|
96
|
-
|
|
97
|
-
The `adminModule` includes the starter auth model and provides the canonical Better Auth `user` collection. It stores:
|
|
98
|
-
|
|
99
|
-
- `id` -- unique identifier
|
|
100
|
-
- `email` -- email address
|
|
101
|
-
- `name` -- display name
|
|
102
|
-
- `image` -- avatar URL
|
|
103
|
-
- `emailVerified` -- verification status
|
|
104
|
-
- `role` -- admin access role (`admin` or `user`)
|
|
105
|
-
- `avatar`, `banned`, `banReason`, `banExpires` -- admin-managed profile and access fields
|
|
106
|
-
|
|
107
|
-
This collection is automatically created when you add the admin module to your config.
|
|
108
|
-
|
|
109
|
-
Critical: the built-in admin setup route and admin `AuthGuard` depend on `user.role`. Setup checks whether any user has `role = "admin"`, and the admin UI expects `session.user.role === "admin"`. Do not replace `collection("user")` from scratch in an app that uses `adminModule`; merge `starterModule.collections.user` and extend it if custom user fields or admin layout are needed.
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
import { starterModule } from "questpie/app";
|
|
113
|
-
import { collection } from "#questpie/factories";
|
|
114
|
-
|
|
115
|
-
export default collection("user")
|
|
116
|
-
.merge(starterModule.collections.user)
|
|
117
|
-
.fields(({ f }) => ({
|
|
118
|
-
internalNotes: f.textarea(),
|
|
119
|
-
}));
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
`.fields()` is cumulative -- it adds to the merged starter fields and overrides them by key, never wipes them, so this recipe keeps the full starter user model.
|
|
123
|
-
|
|
124
|
-
### Anonymous Users (Better Auth plugin)
|
|
125
|
-
|
|
126
|
-
Better Auth plugins that extend the user model follow the same recipe. For the anonymous plugin, register it in `auth.ts` (merged after the built-in plugins) and extend the starter user with the `isAnonymous` field the plugin expects:
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
// auth.ts
|
|
130
|
-
import { anonymous } from "better-auth/plugins";
|
|
131
|
-
import type { AuthConfig } from "questpie/app";
|
|
132
|
-
|
|
133
|
-
export default {
|
|
134
|
-
plugins: [anonymous()],
|
|
135
|
-
} satisfies AuthConfig;
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
// collections/user.ts
|
|
140
|
-
import { starterModule } from "questpie/app";
|
|
141
|
-
import { collection } from "#questpie/factories";
|
|
142
|
-
|
|
143
|
-
export default collection("user")
|
|
144
|
-
.merge(starterModule.collections.user)
|
|
145
|
-
.fields(({ f }) => ({
|
|
146
|
-
isAnonymous: f.boolean().default(false),
|
|
147
|
-
}));
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Run `questpie generate` and apply migrations to add the column. Anonymous sign-in (`authClient.signIn.anonymous()` on the client) creates throwaway users that Better Auth can later link to real accounts.
|
|
151
|
-
|
|
152
|
-
## Reaching the App from Better Auth Callbacks
|
|
153
|
-
|
|
154
|
-
The `/auth/*` catch-all is a plain **raw route**, and raw routes execute their handler inside `runWithContext()` (the request's AsyncLocalStorage scope). That means every Better Auth callback — `onLinkAccount`, `databaseHooks`, `sendMagicLink`, plugin hooks — already runs inside the request scope, and `getContext<App>()` returns the live app, session, db, and locale.
|
|
155
|
-
|
|
156
|
-
**Never build a module-level app singleton or a hand-rolled context bridge for auth callbacks.** The `App` import stays type-only, so there is no circular import:
|
|
157
|
-
|
|
158
|
-
```ts
|
|
159
|
-
// config/auth.ts
|
|
160
|
-
import { anonymous } from "better-auth/plugins";
|
|
161
|
-
import { getContext } from "questpie";
|
|
162
|
-
import { authConfig } from "questpie/app";
|
|
163
|
-
import type { App } from "#questpie"; // type-only — no runtime cycle
|
|
164
|
-
|
|
165
|
-
export default authConfig({
|
|
166
|
-
plugins: [
|
|
167
|
-
anonymous({
|
|
168
|
-
// Fires when an anonymous user signs in with a real account —
|
|
169
|
-
// re-point the guest's rows onto the new user before the plugin
|
|
170
|
-
// deletes the anonymous user.
|
|
171
|
-
onLinkAccount: async ({ anonymousUser, newUser }) => {
|
|
172
|
-
const { app } = getContext<App>();
|
|
173
|
-
// Bare { accessMode: "system" } elevates ONLY the mode —
|
|
174
|
-
// session, db, and locale inherit from the request scope (ALS).
|
|
175
|
-
await app.collections.memberships.updateMany(
|
|
176
|
-
{
|
|
177
|
-
where: { user: anonymousUser.user.id },
|
|
178
|
-
data: { user: newUser.user.id },
|
|
179
|
-
},
|
|
180
|
-
{ accessMode: "system" },
|
|
181
|
-
);
|
|
182
|
-
},
|
|
183
|
-
}),
|
|
184
|
-
],
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Partial Context Overrides
|
|
189
|
-
|
|
190
|
-
CRUD context normalization merges what you pass with the ambient request scope — priority: explicit param → ALS scope → defaults (`accessMode: "system"`, `locale: "en"`). Passing only `{ accessMode: "system" }` elevates the mode while the request's session/db/locale ride along. The inverse also holds: `{ accessMode: "user" }` inside system-scoped code re-enables access rules against the inherited session without re-threading it:
|
|
191
|
-
|
|
192
|
-
```ts
|
|
193
|
-
// Inside any handler — session comes from the request ALS scope
|
|
194
|
-
await app.collections.posts.find({}, { accessMode: "user" }); // rules enforced for the current user
|
|
195
|
-
await app.collections.posts.find({}, { accessMode: "system" }); // rules bypassed, same session/locale
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Client-Side Auth (authClient)
|
|
199
|
-
|
|
200
|
-
For session state and sign-in/out on the frontend, create a typed Better Auth client. In admin-equipped apps use the typed wrapper (session includes your merged user fields):
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
// src/lib/auth-client.ts
|
|
204
|
-
import { createAdminAuthClient } from "@questpie/admin/client";
|
|
205
|
-
import type { AppConfig } from "#questpie";
|
|
206
|
-
import { env } from "#questpie/env.client.vite"; // generated from env.client.ts
|
|
207
|
-
|
|
208
|
-
export const authClient = createAdminAuthClient<AppConfig>({
|
|
209
|
-
baseURL: typeof window !== "undefined" ? window.location.origin : env.APP_URL,
|
|
210
|
-
basePath: "/api/auth",
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
```tsx
|
|
215
|
-
const { data: session, isPending } = authClient.useSession();
|
|
216
|
-
await authClient.signIn.email({ email, password });
|
|
217
|
-
await authClient.signIn.anonymous(); // with the anonymous plugin
|
|
218
|
-
await authClient.signOut();
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Apps without `@questpie/admin` use Better Auth's own `createAuthClient` from `better-auth/react` pointed at `${APP_URL}/api/auth` — same call surface, without the app-inferred session typing.
|
|
222
|
-
|
|
223
|
-
## Environment Variables
|
|
224
|
-
|
|
225
|
-
| Variable | Required | Description |
|
|
226
|
-
| -------------------- | ---------- | --------------------------------------------------------- |
|
|
227
|
-
| `APP_URL` | Yes | Public URL -- used for OAuth callback URLs |
|
|
228
|
-
| `BETTER_AUTH_SECRET` | Yes (prod) | Session signing secret. Use a random 32+ character string |
|
|
229
|
-
|
|
230
|
-
## Production Security Checklist
|
|
231
|
-
|
|
232
|
-
1. Set `BETTER_AUTH_SECRET` to a strong random value (32+ chars)
|
|
233
|
-
2. Set `APP_URL` to your production domain (HTTPS)
|
|
234
|
-
3. Enable `requireEmailVerification` if using email/password
|
|
235
|
-
4. Use HTTPS for all auth endpoints
|
|
236
|
-
5. Configure proper CORS if API and frontend are on different domains
|