create-questpie 2.0.3 → 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 +544 -87
- 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 -600
- package/templates/tanstack-start/CLAUDE.md +26 -127
- package/templates/tanstack-start/README.md +20 -7
- package/templates/tanstack-start/docker/init-extensions.sql +11 -0
- package/templates/tanstack-start/docker-compose.yml +1 -0
- package/templates/tanstack-start/package.json +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/admin/modules.ts +3 -1
- package/templates/tanstack-start/src/questpie/server/.generated/factories.ts +10 -9
- package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/config/auth.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
- package/templates/tanstack-start/src/questpie/server/modules.ts +4 -5
- package/templates/tanstack-start/src/questpie/server/questpie.config.ts +3 -2
- package/templates/tanstack-start/src/routes/__root.tsx +31 -1
- package/templates/tanstack-start/src/routes/api/$.ts +2 -3
- package/templates/tanstack-start/src/routes/index.tsx +97 -0
- package/templates/tanstack-start/vite.config.ts +2 -2
- package/skills/questpie/AGENTS.md +0 -2670
- package/skills/questpie/SKILL.md +0 -260
- package/skills/questpie/references/auth.md +0 -121
- package/skills/questpie/references/business-logic.md +0 -550
- package/skills/questpie/references/codegen-plugin-api.md +0 -382
- package/skills/questpie/references/crud-api.md +0 -378
- package/skills/questpie/references/data-modeling.md +0 -493
- package/skills/questpie/references/extend.md +0 -557
- package/skills/questpie/references/field-types.md +0 -386
- package/skills/questpie/references/infrastructure-adapters.md +0 -545
- package/skills/questpie/references/multi-tenancy.md +0 -364
- package/skills/questpie/references/production.md +0 -475
- package/skills/questpie/references/query-operators.md +0 -125
- package/skills/questpie/references/quickstart.md +0 -564
- package/skills/questpie/references/rules.md +0 -389
- package/skills/questpie/references/tanstack-query.md +0 -520
- package/skills/questpie-admin/AGENTS.md +0 -1508
- package/skills/questpie-admin/SKILL.md +0 -436
- 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,557 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: questpie-core/extend
|
|
3
|
-
description: QUESTPIE extensibility — codegen plugins CodegenPlugin CategoryDeclaration CallbackParamDefinition, building modules, custom field types field() factory toColumn toZodSchema getOperators getMetadata, custom adapters createFetchHandler Elysia Hono Next.js TanStack Start, type registries FieldTypeRegistry ComponentTypeRegistry ViewKindRegistry declare module augmentation, package distribution tsdown npm publishing changesets
|
|
4
|
-
- questpie-core
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
This skill covers extending QUESTPIE: building codegen plugins, reusable modules, custom field types, framework adapters, type registries, and package distribution.
|
|
10
|
-
|
|
11
|
-
## Building a Codegen Plugin
|
|
12
|
-
|
|
13
|
-
A plugin tells codegen what to discover and what types to generate. Plugins contribute to one or more codegen **targets** (e.g., `"server"`, `"admin-client"`).
|
|
14
|
-
|
|
15
|
-
### Plugin Structure
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import type { CodegenPlugin } from "questpie";
|
|
19
|
-
|
|
20
|
-
export function myPlugin(): CodegenPlugin {
|
|
21
|
-
return {
|
|
22
|
-
name: "my-plugin",
|
|
23
|
-
|
|
24
|
-
targets: {
|
|
25
|
-
// Contribute to the server target
|
|
26
|
-
server: {
|
|
27
|
-
root: ".",
|
|
28
|
-
outputFile: "index.ts",
|
|
29
|
-
|
|
30
|
-
// Directory-pattern categories to discover
|
|
31
|
-
categories: {
|
|
32
|
-
widgets: {
|
|
33
|
-
dirs: ["widgets"],
|
|
34
|
-
prefix: "widget",
|
|
35
|
-
emit: "record",
|
|
36
|
-
registryKey: "widgets",
|
|
37
|
-
includeInAppState: true,
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
// Single-file / glob discover patterns
|
|
42
|
-
discover: {
|
|
43
|
-
widgetConfig: { pattern: "widget-config.ts", cardinality: "single" },
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
// Extension methods for collection()/global() factories
|
|
47
|
-
registries: {
|
|
48
|
-
collectionExtensions: {
|
|
49
|
-
widget: {
|
|
50
|
-
stateKey: "~widget",
|
|
51
|
-
configType: "WidgetConfig",
|
|
52
|
-
imports: [{ name: "WidgetConfig", from: "my-plugin-package" }],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
singletonFactories: {
|
|
56
|
-
widgetConfig: {
|
|
57
|
-
configType: "WidgetConfig",
|
|
58
|
-
imports: [{ name: "WidgetConfig", from: "my-plugin-package" }],
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
// Callback param definitions for extension methods
|
|
64
|
-
callbackParams: {
|
|
65
|
-
w: {
|
|
66
|
-
factory: "createWidgetNameProxy",
|
|
67
|
-
from: "my-plugin-package",
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Register in Config
|
|
77
|
-
|
|
78
|
-
```ts title="questpie.config.ts"
|
|
79
|
-
import { runtimeConfig } from "questpie";
|
|
80
|
-
import { myPlugin } from "my-plugin-package";
|
|
81
|
-
|
|
82
|
-
export default runtimeConfig({
|
|
83
|
-
plugins: [myPlugin()],
|
|
84
|
-
db: { url: process.env.DATABASE_URL! },
|
|
85
|
-
app: { url: process.env.APP_URL! },
|
|
86
|
-
});
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Use direct `runtimeConfig({ plugins })` registration only for standalone codegen plugins or custom setups that do not ship a module. Reusable packages should usually attach the plugin to a static module and let codegen extract it from `modules.ts`.
|
|
90
|
-
|
|
91
|
-
### Configurable Codegen-Aware Modules
|
|
92
|
-
|
|
93
|
-
When a package ships a module and a `CodegenPlugin`, keep module identity static and put runtime options in a plugin-discovered config file. Codegen imports `modules.ts` before runtime app creation, so it must be able to see the same module/plugin tree regardless of environment or runtime options.
|
|
94
|
-
|
|
95
|
-
#### DO THIS
|
|
96
|
-
|
|
97
|
-
```ts title="modules.ts"
|
|
98
|
-
import { observabilityModule } from "@questpie/observability/server";
|
|
99
|
-
|
|
100
|
-
export default [observabilityModule] as const;
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
```ts title="config/observability.ts"
|
|
104
|
-
import { observabilityConfig } from "@questpie/observability/server";
|
|
105
|
-
|
|
106
|
-
export default observabilityConfig({
|
|
107
|
-
serviceName: "barbershop",
|
|
108
|
-
enabled: process.env.NODE_ENV === "production",
|
|
109
|
-
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```ts title="@questpie/observability/server.ts"
|
|
114
|
-
export const observabilityModule = module({
|
|
115
|
-
name: "questpie-observability",
|
|
116
|
-
plugin: observabilityPlugin(),
|
|
117
|
-
services: {
|
|
118
|
-
observability: service({
|
|
119
|
-
namespace: null,
|
|
120
|
-
lifecycle: "singleton",
|
|
121
|
-
create: ({ app, logger }) =>
|
|
122
|
-
createObservabilityService(app.state.config?.observability, logger),
|
|
123
|
-
}),
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
The plugin contributes `config/observability.ts` as a discover pattern and a typed singleton factory such as `observabilityConfig()`. The service reads the resolved config at runtime from `app.state.config.observability`.
|
|
129
|
-
|
|
130
|
-
#### DON'T DO THIS
|
|
131
|
-
|
|
132
|
-
Do not make runtime options the main API for modules that contribute codegen plugins:
|
|
133
|
-
|
|
134
|
-
```ts title="modules.ts"
|
|
135
|
-
export default [
|
|
136
|
-
observabilityModule({
|
|
137
|
-
serviceName: "barbershop",
|
|
138
|
-
enabled: process.env.NODE_ENV === "production",
|
|
139
|
-
}),
|
|
140
|
-
] as const;
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Do not conditionally include codegen-aware modules or plugins:
|
|
144
|
-
|
|
145
|
-
```ts title="modules.ts"
|
|
146
|
-
export default [
|
|
147
|
-
process.env.OTEL_ENABLED ? observabilityModule : undefined,
|
|
148
|
-
].filter(Boolean);
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
Factory modules are acceptable only for simple runtime-only modules whose plugin identity and generated contributions do not change. If the package contributes discover patterns, generated factories, module categories, views, components, fields, or collection/global extensions, use **static module + `config/*.ts` singleton factory**.
|
|
152
|
-
|
|
153
|
-
### Plugin Lifecycle
|
|
154
|
-
|
|
155
|
-
1. **Discovery** -- codegen scans for files matching category patterns and discover patterns
|
|
156
|
-
2. **Import** -- files are imported and exports are read
|
|
157
|
-
3. **Transform** -- `transform(ctx)` callbacks can modify the codegen context
|
|
158
|
-
4. **Generation** -- types and runtime code are emitted
|
|
159
|
-
5. **Validation** -- cross-target validators check projection consistency
|
|
160
|
-
|
|
161
|
-
### Real-World Example: Admin Plugin
|
|
162
|
-
|
|
163
|
-
The admin module contributes a codegen plugin to both `"server"` and `"admin-client"` targets -- declaring categories (`blocks`, `views`, `components`, field types), discovering `config/admin.ts`, adding collection/global/field extensions, and defining callback context params such as `v`, `f`, `c`, and `a`.
|
|
164
|
-
|
|
165
|
-
## Building a Module
|
|
166
|
-
|
|
167
|
-
A module is a reusable package that contributes entities to any QUESTPIE project.
|
|
168
|
-
|
|
169
|
-
```ts
|
|
170
|
-
import { module, collection, job } from "questpie";
|
|
171
|
-
import { z } from "zod";
|
|
172
|
-
|
|
173
|
-
const notificationsCollection = collection("notifications")
|
|
174
|
-
.fields(({ f }) => ({
|
|
175
|
-
title: f.text().required(),
|
|
176
|
-
body: f.textarea(),
|
|
177
|
-
read: f.boolean().default(false),
|
|
178
|
-
userId: f.relation("user").required(),
|
|
179
|
-
}))
|
|
180
|
-
.admin(({ c }) => ({
|
|
181
|
-
label: { en: "Notifications" },
|
|
182
|
-
icon: c.icon("ph:bell"),
|
|
183
|
-
}));
|
|
184
|
-
|
|
185
|
-
const sendPushNotification = job({
|
|
186
|
-
name: "sendPushNotification",
|
|
187
|
-
schema: z.object({
|
|
188
|
-
userId: z.string(),
|
|
189
|
-
title: z.string(),
|
|
190
|
-
body: z.string(),
|
|
191
|
-
}),
|
|
192
|
-
handler: async ({ payload }) => {
|
|
193
|
-
// Send push notification logic
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
export const notificationsModule = module({
|
|
198
|
-
name: "notifications",
|
|
199
|
-
collections: { notifications: notificationsCollection },
|
|
200
|
-
jobs: { sendPushNotification },
|
|
201
|
-
sidebar: {
|
|
202
|
-
items: [
|
|
203
|
-
{
|
|
204
|
-
sectionId: "operations",
|
|
205
|
-
type: "collection",
|
|
206
|
-
collection: "notifications",
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
},
|
|
210
|
-
messages: {
|
|
211
|
-
en: {
|
|
212
|
-
"notifications.title": "Notifications",
|
|
213
|
-
"notifications.markRead": "Mark as read",
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Module Options
|
|
220
|
-
|
|
221
|
-
| Property | Type | Description |
|
|
222
|
-
| ------------- | ------------- | ------------------------ |
|
|
223
|
-
| `name` | `string` | Module identifier |
|
|
224
|
-
| `modules` | `Module[]` | Module dependencies |
|
|
225
|
-
| `collections` | `Record` | Collection contributions |
|
|
226
|
-
| `globals` | `Record` | Global contributions |
|
|
227
|
-
| `jobs` | `Record` | Job contributions |
|
|
228
|
-
| `functions` | `Record` | Function contributions |
|
|
229
|
-
| `services` | `Record` | Service contributions |
|
|
230
|
-
| `routes` | `Record` | Route contributions |
|
|
231
|
-
| `fields` | `Record` | Custom field types |
|
|
232
|
-
| `sidebar` | `object` | Sidebar items |
|
|
233
|
-
| `dashboard` | `object` | Dashboard widgets |
|
|
234
|
-
| `migrations` | `Migration[]` | Database migrations |
|
|
235
|
-
| `seeds` | `Seed[]` | Seed data |
|
|
236
|
-
| `messages` | `Record` | i18n translations |
|
|
237
|
-
|
|
238
|
-
### Using a Module
|
|
239
|
-
|
|
240
|
-
```ts title="modules.ts"
|
|
241
|
-
import { adminModule } from "@questpie/admin/server";
|
|
242
|
-
import { notificationsModule } from "my-notifications-package";
|
|
243
|
-
|
|
244
|
-
export default [adminModule, notificationsModule] as const;
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Custom Field Types
|
|
248
|
-
|
|
249
|
-
Custom fields are registered through modules and become available on the `f` builder after codegen.
|
|
250
|
-
|
|
251
|
-
### Registration
|
|
252
|
-
|
|
253
|
-
```ts
|
|
254
|
-
const myModule = module({
|
|
255
|
-
name: "custom-fields",
|
|
256
|
-
fields: {
|
|
257
|
-
color: colorField,
|
|
258
|
-
currency: currencyField,
|
|
259
|
-
},
|
|
260
|
-
});
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
Once registered and codegen runs:
|
|
264
|
-
|
|
265
|
-
```ts
|
|
266
|
-
.fields(({ f }) => ({
|
|
267
|
-
brandColor: f.color().default("#000000"),
|
|
268
|
-
price: f.currency({ currency: "USD" }),
|
|
269
|
-
}))
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### Field Definition
|
|
273
|
-
|
|
274
|
-
A custom field defines:
|
|
275
|
-
|
|
276
|
-
- **Storage type** -- how the value is stored in the database (via `toColumn`)
|
|
277
|
-
- **Validation** -- Zod schema for the value (via `toZodSchema`)
|
|
278
|
-
- **Operators** -- query operators (via `getOperators`)
|
|
279
|
-
- **Metadata** -- introspection metadata (via `getMetadata`)
|
|
280
|
-
|
|
281
|
-
The `Field` class is an immutable builder:
|
|
282
|
-
|
|
283
|
-
```ts
|
|
284
|
-
import { Field } from "questpie";
|
|
285
|
-
|
|
286
|
-
// Each method returns a new Field with updated type state
|
|
287
|
-
f.text(255).required().label({ en: "Name" }).admin({ placeholder: "..." });
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Admin Renderer
|
|
291
|
-
|
|
292
|
-
Register a React component to render the field in the admin panel:
|
|
293
|
-
|
|
294
|
-
```tsx
|
|
295
|
-
function ColorFieldRenderer({ value, onChange }) {
|
|
296
|
-
return (
|
|
297
|
-
<input
|
|
298
|
-
type="color"
|
|
299
|
-
value={value || "#000000"}
|
|
300
|
-
onChange={(e) => onChange(e.target.value)}
|
|
301
|
-
/>
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
Place it in `questpie/admin/fields/color.tsx` -- codegen discovers it automatically.
|
|
307
|
-
|
|
308
|
-
## Custom Adapters
|
|
309
|
-
|
|
310
|
-
QUESTPIE ships with adapters for Hono, Elysia, and Next.js. For other frameworks, use `createFetchHandler` directly.
|
|
311
|
-
|
|
312
|
-
### Generic Fetch Handler
|
|
313
|
-
|
|
314
|
-
```ts
|
|
315
|
-
import { createFetchHandler } from "questpie";
|
|
316
|
-
import { app } from "#questpie";
|
|
317
|
-
|
|
318
|
-
const handler = createFetchHandler(app, { basePath: "/api" });
|
|
319
|
-
// Use with any framework supporting standard Request/Response
|
|
320
|
-
const response = await handler(request);
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Framework Adapters
|
|
324
|
-
|
|
325
|
-
**Elysia:**
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
import { Elysia } from "elysia";
|
|
329
|
-
import { questpieElysia } from "@questpie/elysia/server";
|
|
330
|
-
import { app } from "#questpie";
|
|
331
|
-
|
|
332
|
-
const server = new Elysia()
|
|
333
|
-
.use(questpieElysia(app, { basePath: "/api" }))
|
|
334
|
-
.listen(3000);
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
**Hono:**
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
import { Hono } from "hono";
|
|
341
|
-
import { questpieHono } from "@questpie/hono/server";
|
|
342
|
-
import { app } from "#questpie";
|
|
343
|
-
|
|
344
|
-
const server = new Hono().route("/api", questpieHono(app));
|
|
345
|
-
export default server;
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
**Next.js (App Router):**
|
|
349
|
-
|
|
350
|
-
```ts title="app/api/[...slug]/route.ts"
|
|
351
|
-
import { questpieNextRouteHandlers } from "@questpie/next";
|
|
352
|
-
import { app } from "#questpie";
|
|
353
|
-
|
|
354
|
-
export const { GET, POST, PATCH, DELETE } = questpieNextRouteHandlers(app, {
|
|
355
|
-
basePath: "/api",
|
|
356
|
-
});
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
**TanStack Start (no adapter needed):**
|
|
360
|
-
|
|
361
|
-
```ts title="src/routes/api/$.ts"
|
|
362
|
-
import { createAPIFileRoute } from "@tanstack/react-start/api";
|
|
363
|
-
import { createFetchHandler } from "questpie";
|
|
364
|
-
import { app } from "#questpie";
|
|
365
|
-
|
|
366
|
-
const handler = createFetchHandler(app, { basePath: "/api" });
|
|
367
|
-
export const Route = createAPIFileRoute("/api/$")({
|
|
368
|
-
GET: ({ request }) => handler(request),
|
|
369
|
-
POST: ({ request }) => handler(request),
|
|
370
|
-
PATCH: ({ request }) => handler(request),
|
|
371
|
-
DELETE: ({ request }) => handler(request),
|
|
372
|
-
});
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## Type Registries
|
|
376
|
-
|
|
377
|
-
Three augmentation interfaces allow plugins to extend discriminant types:
|
|
378
|
-
|
|
379
|
-
| Interface | Package | Purpose | Fallback |
|
|
380
|
-
| ----------------------- | ------------------------ | ------------------------------------------------ | ------------- |
|
|
381
|
-
| `FieldTypeRegistry` | `questpie` | Field type names (`"text"`, `"number"`, etc.) | `string` |
|
|
382
|
-
| `ComponentTypeRegistry` | `@questpie/admin/server` | Component type names (`"icon"`, `"badge"`, etc.) | `string` |
|
|
383
|
-
| `ViewKindRegistry` | `@questpie/admin/server` | View kind names (`"list"`, `"edit"`) | literal union |
|
|
384
|
-
|
|
385
|
-
### How Registries Work
|
|
386
|
-
|
|
387
|
-
```text
|
|
388
|
-
Server: f.text().required()
|
|
389
|
-
-> Generated: { type: "text", options: {...} }
|
|
390
|
-
-> Admin Client: fieldRegistry.get("text")
|
|
391
|
-
-> React: <TextFieldRenderer value={...} onChange={...} />
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
### Extending Registries
|
|
395
|
-
|
|
396
|
-
Place files in admin directory -- codegen discovers them automatically:
|
|
397
|
-
|
|
398
|
-
```text
|
|
399
|
-
questpie/admin/
|
|
400
|
-
fields/
|
|
401
|
-
color.tsx # Custom color field renderer
|
|
402
|
-
currency.tsx # Custom currency field renderer
|
|
403
|
-
views/
|
|
404
|
-
kanban.tsx # Custom kanban list view
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### Module Augmentation Pattern
|
|
408
|
-
|
|
409
|
-
Codegen generates `declare module` augmentations:
|
|
410
|
-
|
|
411
|
-
```ts
|
|
412
|
-
declare global {
|
|
413
|
-
namespace Questpie {
|
|
414
|
-
interface FieldTypeRegistry {
|
|
415
|
-
color: {};
|
|
416
|
-
currency: {};
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
The companion type alias uses the `[keyof Registry] extends [never] ? string : keyof Registry` pattern to fall back to `string` when the registry is empty.
|
|
423
|
-
|
|
424
|
-
## Package Distribution
|
|
425
|
-
|
|
426
|
-
### Package Structure
|
|
427
|
-
|
|
428
|
-
```text
|
|
429
|
-
packages/my-package/
|
|
430
|
-
src/
|
|
431
|
-
exports/ # Public API entry points
|
|
432
|
-
index.ts # Main entry (.)
|
|
433
|
-
client.ts # Client entry (./client)
|
|
434
|
-
server.ts # Server entry (./server)
|
|
435
|
-
dist/ # Build output (gitignored)
|
|
436
|
-
tsdown.config.ts
|
|
437
|
-
package.json
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### Dual Exports Strategy
|
|
441
|
-
|
|
442
|
-
```json title="package.json"
|
|
443
|
-
{
|
|
444
|
-
"type": "module",
|
|
445
|
-
"exports": {
|
|
446
|
-
".": {
|
|
447
|
-
"types": "./dist/index.d.mts",
|
|
448
|
-
"default": "./src/exports/index.ts"
|
|
449
|
-
}
|
|
450
|
-
},
|
|
451
|
-
"publishConfig": {
|
|
452
|
-
"exports": {
|
|
453
|
-
".": {
|
|
454
|
-
"types": "./dist/index.d.mts",
|
|
455
|
-
"default": "./dist/index.mjs"
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
},
|
|
459
|
-
"files": ["dist"]
|
|
460
|
-
}
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
During development: `exports.default` points to `.ts` source (no build step needed). When published: `publishConfig.exports` overrides with compiled `.mjs` + `.d.mts`.
|
|
464
|
-
|
|
465
|
-
### Build with tsdown
|
|
466
|
-
|
|
467
|
-
```ts title="tsdown.config.ts"
|
|
468
|
-
import { defineConfig } from "tsdown";
|
|
469
|
-
|
|
470
|
-
export default defineConfig({
|
|
471
|
-
entry: ["src/exports/*.ts"],
|
|
472
|
-
outDir: "dist",
|
|
473
|
-
format: ["esm"],
|
|
474
|
-
clean: true,
|
|
475
|
-
dts: { sourcemap: false },
|
|
476
|
-
unbundle: true,
|
|
477
|
-
});
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
### Publishing a Module
|
|
481
|
-
|
|
482
|
-
```json title="package.json"
|
|
483
|
-
{
|
|
484
|
-
"name": "questpie-notifications",
|
|
485
|
-
"main": "dist/index.js",
|
|
486
|
-
"types": "dist/index.d.ts",
|
|
487
|
-
"peerDependencies": {
|
|
488
|
-
"questpie": "^2.0.0"
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### Versioning with Changesets
|
|
494
|
-
|
|
495
|
-
Core packages use lock-step versioning. Run `bun changeset` to create, `bun run version` to apply, `bun run release` to publish.
|
|
496
|
-
|
|
497
|
-
## Common Mistakes
|
|
498
|
-
|
|
499
|
-
### HIGH: Adding `& Record<string, unknown>` to Registry augmentation
|
|
500
|
-
|
|
501
|
-
This erases named keys via index signature intersection. The resulting type becomes `string` instead of a union of literal keys.
|
|
502
|
-
|
|
503
|
-
```ts
|
|
504
|
-
// WRONG -- erases literal types
|
|
505
|
-
declare global {
|
|
506
|
-
namespace Questpie {
|
|
507
|
-
interface FieldTypeRegistry extends Record<string, unknown> {
|
|
508
|
-
color: {};
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// CORRECT -- only named keys
|
|
514
|
-
declare global {
|
|
515
|
-
namespace Questpie {
|
|
516
|
-
interface FieldTypeRegistry {
|
|
517
|
-
color: {};
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
### HIGH: Stale `.js`/`.d.ts` artifacts in src/
|
|
524
|
-
|
|
525
|
-
tsdown prefers `.js` over `.ts` when both exist. Delete stale artifacts before building:
|
|
526
|
-
|
|
527
|
-
```bash
|
|
528
|
-
# Remove tsc incremental artifacts that may shadow .ts files
|
|
529
|
-
find src -name '*.d.ts' -o -name '*.js' | xargs rm -f
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
### MEDIUM: Not including `"skills"` in package.json files array
|
|
533
|
-
|
|
534
|
-
Skills must ship with the npm package. Add the directory to `files`:
|
|
535
|
-
|
|
536
|
-
```json
|
|
537
|
-
{
|
|
538
|
-
"files": ["dist", "skills"]
|
|
539
|
-
}
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### MEDIUM: Complex conditional mapped types collapsing to `{}` in tsdown `.d.ts` emit
|
|
543
|
-
|
|
544
|
-
Ensure source types have literal generic parameters. If a type like `FilterViewsByKind<TKind>` collapses to `{}` in declaration output, provide explicit `as ViewDefinition<"name", "kind", Config>` casts.
|
|
545
|
-
|
|
546
|
-
### MEDIUM: Missing `extractFromModules` for new categories
|
|
547
|
-
|
|
548
|
-
If a plugin declares a new category but does not set `extractFromModules: true`, module-contributed entities of that category will not appear in the generated `App*` type.
|
|
549
|
-
|
|
550
|
-
## References
|
|
551
|
-
|
|
552
|
-
| Need to... | Read |
|
|
553
|
-
| -------------------------------- | ---------------------------------- |
|
|
554
|
-
| See full CodegenPlugin API | `references/codegen-plugin-api.md` |
|
|
555
|
-
| Define collections and fields | `questpie-core/data-modeling` |
|
|
556
|
-
| Set up access, hooks, validation | `questpie-core/rules` |
|
|
557
|
-
| Add functions, jobs, routes | `questpie-core/business-logic` |
|