@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.
- package/.turbo/turbo-build.log +16 -0
- package/.turbo/turbo-check-types.log +1 -0
- package/CHANGELOG.md +9 -0
- package/README.md +248 -0
- package/dist/client.d.mts +56 -0
- package/dist/client.mjs +44 -0
- package/dist/server.d.mts +122 -0
- package/dist/server.mjs +66 -0
- package/package.json +38 -0
- package/src/client.ts +86 -0
- package/src/server.ts +93 -0
- package/tsconfig.json +5 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.ts +10 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
[0m[2m[35m$[0m [2m[1mtsdown[0m
|
|
3
|
+
[34mℹ[39m tsdown [2mv0.18.4[22m powered by rolldown [2mv1.0.0-beta.57[22m
|
|
4
|
+
[34mℹ[39m config file: [4m/Users/drepkovsky/questpie/repos/questpie-cms/packages/elysia/tsdown.config.ts[24m
|
|
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
|
+
[34mℹ[39m entry: [34msrc/server.ts, src/client.ts[39m
|
|
8
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
|
+
[34mℹ[39m Build start
|
|
10
|
+
[34mℹ[39m Cleaning 4 files
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[1mserver.mjs[22m [2m1.53 kB[22m [2m│ gzip: 0.73 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m [2m1.20 kB[22m [2m│ gzip: 0.56 kB[22m
|
|
13
|
+
[34mℹ[39m [2mdist/[22m[32m[1mserver.d.mts[22m[39m [2m2.54 kB[22m [2m│ gzip: 0.96 kB[22m
|
|
14
|
+
[34mℹ[39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m1.60 kB[22m [2m│ gzip: 0.71 kB[22m
|
|
15
|
+
[34mℹ[39m 4 files, total: 6.86 kB
|
|
16
|
+
[32m✔[39m Build complete in [32m5676ms[39m
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ tsc --noEmit
|
package/CHANGELOG.md
ADDED
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 };
|
package/dist/client.mjs
ADDED
|
@@ -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 };
|
package/dist/server.mjs
ADDED
|
@@ -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
|
+
}
|