@questpie/elysia 0.0.1

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.
@@ -0,0 +1,16 @@
1
+
2
+ $ tsdown
3
+ ℹ tsdown v0.18.4 powered by rolldown v1.0.0-beta.57
4
+ ℹ config file: /Users/drepkovsky/questpie/repos/questpie-cms/packages/elysia/tsdown.config.ts
5
+ (node:61186) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
6
+ (Use `node --trace-warnings ...` to show where the warning was created)
7
+ ℹ entry: src/server.ts, src/client.ts
8
+ ℹ tsconfig: tsconfig.json
9
+ ℹ Build start
10
+ ℹ Cleaning 4 files
11
+ ℹ dist/server.mjs 1.53 kB │ gzip: 0.73 kB
12
+ ℹ dist/client.mjs 1.20 kB │ gzip: 0.56 kB
13
+ ℹ dist/server.d.mts 2.54 kB │ gzip: 0.96 kB
14
+ ℹ dist/client.d.mts 1.60 kB │ gzip: 0.71 kB
15
+ ℹ 4 files, total: 6.86 kB
16
+ ✔ Build complete in 5676ms
@@ -0,0 +1 @@
1
+ $ tsc --noEmit
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # @questpie/elysia
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - feat: initial release
8
+ - Updated dependencies
9
+ - questpie@0.0.1
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # @questpie/elysia
2
+
3
+ Elysia adapter for QUESTPIE CMS with full end-to-end type safety using Eden Treaty.
4
+
5
+ ## Features
6
+
7
+ - 🔒 **Full Type Safety**: End-to-end type safety using Elysia's Eden Treaty
8
+ - 🚀 **High Performance**: Built on Elysia's blazing-fast framework
9
+ - 🎯 **Auto-complete**: IntelliSense for all CMS routes and methods
10
+ - 📦 **Zero Config**: Works out of the box with minimal setup
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ bun add @questpie/elysia @questpie/cms elysia
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ### Server Setup
21
+
22
+ ```typescript
23
+ import { Elysia } from "elysia";
24
+ import { questpieElysia } from "@questpie/elysia";
25
+ import { cms } from "./cms";
26
+
27
+ const app = new Elysia()
28
+ .use(questpieElysia(cms))
29
+ .listen(3000);
30
+
31
+ console.log(`Server running at http://${app.server?.hostname}:${app.server?.port}`);
32
+
33
+ // Export type for Eden Treaty client
34
+ export type App = typeof app;
35
+ ```
36
+
37
+ ### Client Setup with Unified Client
38
+
39
+ ```typescript
40
+ import { createClientFromEden } from "@questpie/elysia/client";
41
+ import { cms } from "./cms";
42
+ import type { App } from "./server";
43
+
44
+ // IMPORTANT: Use `typeof cms` directly (not a type alias) for proper type inference
45
+ const client = createClientFromEden<App, typeof cms>({
46
+ server: "localhost:3000",
47
+ });
48
+
49
+ // ✨ Use CMS CRUD operations (fully typed!)
50
+ const posts = await client.collections.posts.find({ limit: 10 });
51
+
52
+ // ✨ Use Eden Treaty for custom routes (fully type-safe!)
53
+ const result = await client.api.custom.route.get();
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ ### Custom Options
59
+
60
+ ```typescript
61
+ import { Elysia } from "elysia";
62
+ import { questpieElysia } from "@questpie/elysia";
63
+ import { cms } from "./cms";
64
+
65
+ const app = new Elysia().use(
66
+ questpieElysia(cms, {
67
+ basePath: "/cms-api", // Default: '/cms'
68
+ cors: {
69
+ origin: "https://example.com",
70
+ credentials: true,
71
+ },
72
+ }),
73
+ );
74
+ ```
75
+
76
+ ### Disable CORS
77
+
78
+ ```typescript
79
+ const app = new Elysia().use(
80
+ questpieElysia(cms, {
81
+ cors: false, // Disable CORS middleware
82
+ }),
83
+ );
84
+ ```
85
+
86
+ ## API Routes
87
+
88
+ The adapter automatically creates the following routes:
89
+
90
+ ### Collections
91
+
92
+ - `GET /cms/:collection` - Find all items
93
+ - `POST /cms/:collection` - Create item
94
+ - `GET /cms/:collection/:id` - Find one item
95
+ - `PATCH /cms/:collection/:id` - Update item
96
+ - `DELETE /cms/:collection/:id` - Delete item
97
+ - `POST /cms/:collection/:id/restore` - Restore soft-deleted item
98
+
99
+ ### Globals
100
+
101
+ - `GET /cms/globals/:global` - Get global settings
102
+ - `PATCH /cms/globals/:global` - Update global settings
103
+
104
+ ### Storage
105
+
106
+ - `POST /cms/storage/upload` - Upload file
107
+
108
+ ### Authentication
109
+
110
+ - `ALL /cms/auth/*` - Better Auth routes
111
+
112
+ ## Type-Safe Client Examples
113
+
114
+ ### CRUD Operations
115
+
116
+ ```typescript
117
+ import { createClientFromEden } from "@questpie/elysia/client";
118
+ import { cms } from "./cms";
119
+ import type { App } from "./server";
120
+
121
+ // IMPORTANT: Use `typeof cms` directly for proper type inference
122
+ const client = createClientFromEden<App, typeof cms>({
123
+ server: "localhost:3000",
124
+ });
125
+
126
+ // CMS CRUD operations (fully typed with autocomplete!)
127
+ const posts = await client.collections.posts.find({
128
+ where: { published: true },
129
+ limit: 10,
130
+ orderBy: { createdAt: "desc" },
131
+ });
132
+
133
+ const newPost = await client.collections.posts.create({
134
+ title: "New Post",
135
+ content: "Content here",
136
+ });
137
+
138
+ const updated = await client.collections.posts.update("123", {
139
+ title: "Updated Title",
140
+ });
141
+
142
+ await client.collections.posts.delete("123");
143
+ ```
144
+
145
+ ### With Relations
146
+
147
+ ```typescript
148
+ const post = await client.collections.posts.findOne({
149
+ where: { id: "123" },
150
+ with: {
151
+ author: true,
152
+ comments: true,
153
+ },
154
+ });
155
+ ```
156
+
157
+ ### Custom Routes with Eden Treaty
158
+
159
+ ```typescript
160
+ // Custom business logic routes are fully type-safe!
161
+ const availability = await client.api.barbers[":id"].availability.get({
162
+ params: { id: "barber-123" },
163
+ query: { date: "2025-01-15" },
164
+ });
165
+
166
+ const booking = await client.api.appointments.book.post({
167
+ barberId: "123",
168
+ serviceId: "456",
169
+ scheduledAt: "2025-01-15T10:00:00Z",
170
+ });
171
+ ```
172
+
173
+ ### File Upload
174
+
175
+ ```typescript
176
+ const formData = new FormData();
177
+ formData.append("file", file);
178
+
179
+ const asset = await client.api.storage.upload.post(formData);
180
+ ```
181
+
182
+ ## Generic HTTP Client
183
+
184
+ If you prefer a generic HTTP client (not Eden Treaty), use the shared client from `@questpie/cms`:
185
+
186
+ ```typescript
187
+ import { createQCMSClient } from "@questpie/cms/client";
188
+ import type { cms } from "./server";
189
+
190
+ const client = createQCMSClient<typeof cms>({
191
+ baseURL: "http://localhost:3000",
192
+ basePath: "/cms",
193
+ });
194
+
195
+ // Still type-safe but uses fetch under the hood
196
+ const posts = await client.collections.posts.find({ limit: 10 });
197
+ ```
198
+
199
+ ## Comparison with Hono
200
+
201
+ ### Elysia + Eden Treaty (Recommended)
202
+
203
+ ```typescript
204
+ import { createClientFromEden } from "@questpie/elysia/client";
205
+ import { cms } from "./cms";
206
+ import type { App } from "./server";
207
+
208
+ // Use `typeof cms` directly (not type alias!)
209
+ const client = createClientFromEden<App, typeof cms>({
210
+ server: "localhost:3000",
211
+ });
212
+
213
+ // ✅ Fully type-safe end-to-end
214
+ // ✅ Auto-complete for all routes and collections
215
+ // ✅ Runtime type checking
216
+ // ✅ CMS CRUD + custom routes in one client
217
+ const posts = await client.collections.posts.find();
218
+ const custom = await client.api.custom.route.get();
219
+ ```
220
+
221
+ ### Hono RPC
222
+
223
+ ```typescript
224
+ import { createClientFromHono } from "@questpie/hono/client";
225
+ import type { AppType } from "./server";
226
+ import type { cms } from "./cms";
227
+
228
+ const client = createClientFromHono<AppType, typeof cms>({
229
+ baseURL: "http://localhost:3000",
230
+ });
231
+
232
+ // ⚠️ Limited type safety for custom routes
233
+ // ✅ Good CMS CRUD type safety
234
+ // ✅ Single unified client
235
+ const posts = await client.collections.posts.find();
236
+ const custom = await client.api.custom.route.$get();
237
+ ```
238
+
239
+ ## Why Elysia?
240
+
241
+ - **Better Type Safety**: Elysia with Eden Treaty provides superior end-to-end type safety compared to Hono
242
+ - **Performance**: Elysia is one of the fastest JavaScript web frameworks
243
+ - **Developer Experience**: Better IntelliSense and auto-complete
244
+ - **Modern**: Built with TypeScript from the ground up
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,56 @@
1
+ import Elysia from "elysia";
2
+ import { Questpie } from "questpie";
3
+ import { Treaty } from "@elysiajs/eden";
4
+ import { QuestpieClient } from "questpie/client";
5
+
6
+ //#region src/client.d.ts
7
+
8
+ /**
9
+ * Elysia client configuration
10
+ */
11
+ type ElysiaClientConfig = {
12
+ /**
13
+ * Server URL (domain with optional port, no protocol needed for Eden)
14
+ * @example 'localhost:3000'
15
+ * @example 'api.example.com'
16
+ */
17
+ server: string;
18
+ /**
19
+ * Custom fetch implementation
20
+ * @default globalThis.fetch
21
+ */
22
+ fetch?: typeof fetch;
23
+ /**
24
+ * Base path for CMS routes
25
+ * @default '/cms'
26
+ */
27
+ basePath?: string;
28
+ /**
29
+ * Default headers to include in all requests
30
+ */
31
+ headers?: Record<string, string>;
32
+ };
33
+ /**
34
+ * Create a unified client that combines QUESTPIE CMS CRUD operations
35
+ * with Elysia's native Eden Treaty client for custom routes
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { createClientFromEden } from '@questpie/elysia/client'
40
+ * import type { App } from './server'
41
+ * import type { AppCMS } from './cms'
42
+ *
43
+ * const client = createClientFromEden<App, AppCMS>({
44
+ * server: 'localhost:3000'
45
+ * })
46
+ *
47
+ * // Use CMS CRUD operations
48
+ * const posts = await client.collections.posts.find({ limit: 10 })
49
+ *
50
+ * // Use Eden Treaty for custom routes (fully type-safe!)
51
+ * const result = await client.api.custom.route.get()
52
+ * ```
53
+ */
54
+ declare function createClientFromEden<TApp extends Elysia<any, any, any, any, any, any, any> = any, TCMS extends Questpie<any> = any>(config: ElysiaClientConfig): QuestpieClient<TCMS> & Treaty.Create<TApp>;
55
+ //#endregion
56
+ export { ElysiaClientConfig, createClientFromEden };
@@ -0,0 +1,44 @@
1
+ import { treaty } from "@elysiajs/eden";
2
+ import { createQuestpieClient } from "questpie/client";
3
+
4
+ //#region src/client.ts
5
+ /**
6
+ * Create a unified client that combines QUESTPIE CMS CRUD operations
7
+ * with Elysia's native Eden Treaty client for custom routes
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { createClientFromEden } from '@questpie/elysia/client'
12
+ * import type { App } from './server'
13
+ * import type { AppCMS } from './cms'
14
+ *
15
+ * const client = createClientFromEden<App, AppCMS>({
16
+ * server: 'localhost:3000'
17
+ * })
18
+ *
19
+ * // Use CMS CRUD operations
20
+ * const posts = await client.collections.posts.find({ limit: 10 })
21
+ *
22
+ * // Use Eden Treaty for custom routes (fully type-safe!)
23
+ * const result = await client.api.custom.route.get()
24
+ * ```
25
+ */
26
+ function createClientFromEden(config) {
27
+ const cmsClient = createQuestpieClient({
28
+ baseURL: config.server.startsWith("http") ? config.server : `http://${config.server}`,
29
+ fetch: config.fetch,
30
+ basePath: config.basePath,
31
+ headers: config.headers
32
+ });
33
+ return {
34
+ ...treaty(config.server, {
35
+ fetcher: config.fetch,
36
+ headers: config.headers
37
+ }),
38
+ collections: cmsClient.collections,
39
+ globals: cmsClient.globals
40
+ };
41
+ }
42
+
43
+ //#endregion
44
+ export { createClientFromEden };
@@ -0,0 +1,122 @@
1
+ import { Elysia as Elysia$1 } from "elysia";
2
+ import { Questpie } from "questpie";
3
+
4
+ //#region src/server.d.ts
5
+
6
+ /**
7
+ * Context stored in Elysia decorator
8
+ */
9
+ type QuestpieContext = {
10
+ cms: Questpie<any>;
11
+ cmsContext: Awaited<ReturnType<Questpie<any>["createContext"]>>;
12
+ user: any;
13
+ };
14
+ /**
15
+ * Elysia adapter configuration
16
+ */
17
+ type ElysiaAdapterConfig = {
18
+ /**
19
+ * Base path for CMS routes
20
+ * Use '/cms' for server-only apps or '/api/cms' for fullstack apps.
21
+ * @default '/cms'
22
+ */
23
+ basePath?: string;
24
+ };
25
+ /**
26
+ * Create Elysia app with QUESTPIE CMS integration
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { Elysia } from 'elysia'
31
+ * import { questpieElysia } from '@questpie/elysia'
32
+ * import { cms } from './cms'
33
+ *
34
+ * const app = new Elysia()
35
+ * .use(questpieElysia(cms))
36
+ *
37
+ * export default app
38
+ * export type App = typeof app
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // With custom config
44
+ * const app = new Elysia()
45
+ * .use(questpieElysia(cms, {
46
+ * basePath: '/cms-api',
47
+ * cors: {
48
+ * origin: 'https://example.com',
49
+ * credentials: true
50
+ * }
51
+ * }))
52
+ * ```
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * // Client usage with Eden Treaty
57
+ * import { treaty } from '@elysiajs/eden'
58
+ * import type { App } from './server'
59
+ *
60
+ * const client = treaty<App>('localhost:3000')
61
+ *
62
+ * // Fully type-safe!
63
+ * const posts = await client.cms.posts.get()
64
+ * const post = await client.cms.posts({ id: '123' }).get()
65
+ * const newPost = await client.cms.posts.post({ title: 'Hello' })
66
+ * ```
67
+ */
68
+ declare function questpieElysia(cms: Questpie<any>, config?: ElysiaAdapterConfig): Elysia$1<string, {
69
+ decorator: {};
70
+ store: {};
71
+ derive: {};
72
+ resolve: {};
73
+ }, {
74
+ typebox: {};
75
+ error: {};
76
+ }, {
77
+ schema: {};
78
+ standaloneSchema: {};
79
+ macro: {};
80
+ macroFn: {};
81
+ parser: {};
82
+ response: {};
83
+ }, {
84
+ [x: string]: {
85
+ "*": {
86
+ [x: string]: {
87
+ body: unknown;
88
+ params: {
89
+ "*": string;
90
+ } & {};
91
+ query: unknown;
92
+ headers: unknown;
93
+ response: {
94
+ 200: Response;
95
+ 422: {
96
+ type: "validation";
97
+ on: string;
98
+ summary?: string;
99
+ message?: string;
100
+ found?: unknown;
101
+ property?: string;
102
+ expected?: string;
103
+ };
104
+ };
105
+ };
106
+ };
107
+ };
108
+ }, {
109
+ derive: {};
110
+ resolve: {};
111
+ schema: {};
112
+ standaloneSchema: {};
113
+ response: {};
114
+ }, {
115
+ derive: {};
116
+ resolve: {};
117
+ schema: {};
118
+ standaloneSchema: {};
119
+ response: {};
120
+ }>;
121
+ //#endregion
122
+ export { ElysiaAdapterConfig, QuestpieContext, questpieElysia };
@@ -0,0 +1,66 @@
1
+ import { Elysia as Elysia$1 } from "elysia";
2
+ import { createFetchHandler } from "questpie";
3
+
4
+ //#region src/server.ts
5
+ /**
6
+ * Create Elysia app with QUESTPIE CMS integration
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { Elysia } from 'elysia'
11
+ * import { questpieElysia } from '@questpie/elysia'
12
+ * import { cms } from './cms'
13
+ *
14
+ * const app = new Elysia()
15
+ * .use(questpieElysia(cms))
16
+ *
17
+ * export default app
18
+ * export type App = typeof app
19
+ * ```
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // With custom config
24
+ * const app = new Elysia()
25
+ * .use(questpieElysia(cms, {
26
+ * basePath: '/cms-api',
27
+ * cors: {
28
+ * origin: 'https://example.com',
29
+ * credentials: true
30
+ * }
31
+ * }))
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Client usage with Eden Treaty
37
+ * import { treaty } from '@elysiajs/eden'
38
+ * import type { App } from './server'
39
+ *
40
+ * const client = treaty<App>('localhost:3000')
41
+ *
42
+ * // Fully type-safe!
43
+ * const posts = await client.cms.posts.get()
44
+ * const post = await client.cms.posts({ id: '123' }).get()
45
+ * const newPost = await client.cms.posts.post({ title: 'Hello' })
46
+ * ```
47
+ */
48
+ function questpieElysia(cms, config = {}) {
49
+ const basePath = config.basePath || "/cms";
50
+ const handler = createFetchHandler(cms, {
51
+ basePath,
52
+ accessMode: "user"
53
+ });
54
+ return new Elysia$1({
55
+ prefix: basePath,
56
+ name: "questpie-cms"
57
+ }).all("/*", async ({ request }) => {
58
+ return await handler(request) ?? new Response(JSON.stringify({ error: "Not found" }), {
59
+ status: 404,
60
+ headers: { "Content-Type": "application/json" }
61
+ });
62
+ });
63
+ }
64
+
65
+ //#endregion
66
+ export { questpieElysia };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@questpie/elysia",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsdown",
7
+ "check-types": "tsc --noEmit"
8
+ },
9
+ "dependencies": {
10
+ "@elysiajs/cors": "^1.2.1",
11
+ "@elysiajs/eden": "^1.2.6",
12
+ "questpie": "workspace:*",
13
+ "elysia": "^1.2.14",
14
+ "qs": "^6.13.1"
15
+ },
16
+ "devDependencies": {
17
+ "@questpie/typescript-config": "workspace:*",
18
+ "@types/qs": "^6.9.17",
19
+ "bun-types": "latest",
20
+ "tsdown": "^0.18.3"
21
+ },
22
+ "peerDependencies": {
23
+ "questpie": "workspace:*"
24
+ },
25
+ "exports": {
26
+ ".": {
27
+ "import": "./dist/server.mjs",
28
+ "types": "./dist/server.d.mts"
29
+ },
30
+ "./client": {
31
+ "import": "./dist/client.mjs",
32
+ "types": "./dist/client.d.mts"
33
+ }
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
38
+ }
package/src/client.ts ADDED
@@ -0,0 +1,86 @@
1
+ import { treaty } from "@elysiajs/eden";
2
+ import type { Treaty } from "@elysiajs/eden";
3
+ import { createQuestpieClient, type QuestpieClient } from "questpie/client";
4
+ import type { Questpie } from "questpie";
5
+ import type Elysia from "elysia";
6
+
7
+ /**
8
+ * Elysia client configuration
9
+ */
10
+ export type ElysiaClientConfig = {
11
+ /**
12
+ * Server URL (domain with optional port, no protocol needed for Eden)
13
+ * @example 'localhost:3000'
14
+ * @example 'api.example.com'
15
+ */
16
+ server: string;
17
+
18
+ /**
19
+ * Custom fetch implementation
20
+ * @default globalThis.fetch
21
+ */
22
+ fetch?: typeof fetch;
23
+
24
+ /**
25
+ * Base path for CMS routes
26
+ * @default '/cms'
27
+ */
28
+ basePath?: string;
29
+
30
+ /**
31
+ * Default headers to include in all requests
32
+ */
33
+ headers?: Record<string, string>;
34
+ };
35
+
36
+ /**
37
+ * Create a unified client that combines QUESTPIE CMS CRUD operations
38
+ * with Elysia's native Eden Treaty client for custom routes
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { createClientFromEden } from '@questpie/elysia/client'
43
+ * import type { App } from './server'
44
+ * import type { AppCMS } from './cms'
45
+ *
46
+ * const client = createClientFromEden<App, AppCMS>({
47
+ * server: 'localhost:3000'
48
+ * })
49
+ *
50
+ * // Use CMS CRUD operations
51
+ * const posts = await client.collections.posts.find({ limit: 10 })
52
+ *
53
+ * // Use Eden Treaty for custom routes (fully type-safe!)
54
+ * const result = await client.api.custom.route.get()
55
+ * ```
56
+ */
57
+ export function createClientFromEden<
58
+ TApp extends Elysia<any, any, any, any, any, any, any> = any,
59
+ TCMS extends Questpie<any> = any,
60
+ >(config: ElysiaClientConfig): QuestpieClient<TCMS> & Treaty.Create<TApp> {
61
+ // Determine baseURL with protocol for CMS client
62
+ const baseURL = config.server.startsWith("http")
63
+ ? config.server
64
+ : `http://${config.server}`;
65
+
66
+ // Create CMS client for CRUD operations
67
+ const cmsClient = createQuestpieClient<TCMS>({
68
+ baseURL,
69
+ fetch: config.fetch,
70
+ basePath: config.basePath,
71
+ headers: config.headers,
72
+ });
73
+
74
+ // Create Eden Treaty client for custom routes
75
+ const edenClient = treaty<TApp>(config.server, {
76
+ fetcher: config.fetch,
77
+ headers: config.headers,
78
+ });
79
+
80
+ // Merge both clients
81
+ return {
82
+ ...edenClient,
83
+ collections: cmsClient.collections,
84
+ globals: cmsClient.globals,
85
+ } as QuestpieClient<TCMS> & Treaty.Create<TApp>;
86
+ }