spiceflow 1.0.6 → 1.0.8
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/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +0 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/elysia-fork/types.d.ts +1 -3
- package/dist/elysia-fork/types.d.ts.map +1 -1
- package/dist/elysia-fork/utils.d.ts +1 -62
- package/dist/elysia-fork/utils.d.ts.map +1 -1
- package/dist/openapi.d.ts +35 -4
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +25 -20
- package/dist/openapi.js.map +1 -1
- package/dist/openapi.test.d.ts +2 -0
- package/dist/openapi.test.d.ts.map +1 -0
- package/dist/openapi.test.js +267 -0
- package/dist/openapi.test.js.map +1 -0
- package/dist/spiceflow.d.ts +7 -7
- package/dist/spiceflow.d.ts.map +1 -1
- package/dist/spiceflow.js +1 -1
- package/dist/spiceflow.js.map +1 -1
- package/dist/types.test.d.ts +2 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +35 -0
- package/dist/types.test.js.map +1 -0
- package/package.json +1 -1
- package/src/elysia-fork/types.ts +1 -1
- package/src/openapi.test.ts +294 -0
- package/src/openapi.ts +71 -84
- package/src/spiceflow.ts +4 -15
- package/src/types.test.ts +50 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { expect, test } from 'vitest'
|
|
2
|
+
import { Spiceflow } from './spiceflow.js'
|
|
3
|
+
import { openapi } from './openapi.js'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
test('openapi response', async () => {
|
|
7
|
+
const app = await new Spiceflow()
|
|
8
|
+
.use(
|
|
9
|
+
openapi({
|
|
10
|
+
documentation: {
|
|
11
|
+
info: {
|
|
12
|
+
title: 'Spiceflow Docs',
|
|
13
|
+
version: '0.0.0',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
}),
|
|
17
|
+
)
|
|
18
|
+
.use(
|
|
19
|
+
new Spiceflow({ basePath: '/one' }).get(
|
|
20
|
+
'/ids/:id',
|
|
21
|
+
({ params }) => {
|
|
22
|
+
if (Math.random() < 0.5) {
|
|
23
|
+
// TODO add a way to set status
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
message: 'sdf',
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return params.id
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
response: {
|
|
33
|
+
200: z.string(),
|
|
34
|
+
404: z.object({
|
|
35
|
+
message: z.string(),
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
.patch(
|
|
42
|
+
'/addBody',
|
|
43
|
+
async (c) => {
|
|
44
|
+
let body = await c.request.json()
|
|
45
|
+
return body
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
body: z.object({
|
|
49
|
+
name: z.string(),
|
|
50
|
+
}),
|
|
51
|
+
response: z.object({
|
|
52
|
+
name: z.string().optional(),
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
.get(
|
|
57
|
+
'/queryParams',
|
|
58
|
+
async (c) => {
|
|
59
|
+
const query = c.query
|
|
60
|
+
return query
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
query: z.object({
|
|
64
|
+
name: z.string(),
|
|
65
|
+
}),
|
|
66
|
+
response: z.object({
|
|
67
|
+
name: z.string().optional(),
|
|
68
|
+
}),
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
.post(
|
|
72
|
+
'/queryParams',
|
|
73
|
+
async (c) => {
|
|
74
|
+
const query = c.query
|
|
75
|
+
return query
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
detail: {
|
|
79
|
+
description: 'This is a post',
|
|
80
|
+
operationId: 'postQueryParamsXXX',
|
|
81
|
+
},
|
|
82
|
+
body: z.object({
|
|
83
|
+
name: z.string(),
|
|
84
|
+
}),
|
|
85
|
+
response: z.object({
|
|
86
|
+
name: z.string().optional(),
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
.use(
|
|
91
|
+
new Spiceflow({ basePath: '/two' }).get(
|
|
92
|
+
'/ids/:id',
|
|
93
|
+
({ params }) => params.id,
|
|
94
|
+
{
|
|
95
|
+
params: z.object({
|
|
96
|
+
id: z.string(),
|
|
97
|
+
}),
|
|
98
|
+
},
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
const openapiSchema = await app
|
|
102
|
+
.handle(new Request('http://localhost/openapi'))
|
|
103
|
+
.then((x) => x.json())
|
|
104
|
+
expect(openapiSchema).toMatchInlineSnapshot(`
|
|
105
|
+
{
|
|
106
|
+
"components": {
|
|
107
|
+
"schemas": {},
|
|
108
|
+
},
|
|
109
|
+
"info": {
|
|
110
|
+
"description": "Development documentation",
|
|
111
|
+
"title": "Spiceflow Docs",
|
|
112
|
+
"version": "0.0.0",
|
|
113
|
+
},
|
|
114
|
+
"openapi": "3.0.3",
|
|
115
|
+
"paths": {
|
|
116
|
+
"/addBody": {
|
|
117
|
+
"patch": {
|
|
118
|
+
"operationId": "patchAddBody",
|
|
119
|
+
"parameters": [],
|
|
120
|
+
"requestBody": {
|
|
121
|
+
"content": {
|
|
122
|
+
"application/json": {
|
|
123
|
+
"schema": {
|
|
124
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
125
|
+
"additionalProperties": false,
|
|
126
|
+
"properties": {
|
|
127
|
+
"name": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
"required": [
|
|
132
|
+
"name",
|
|
133
|
+
],
|
|
134
|
+
"type": "object",
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
"required": true,
|
|
139
|
+
},
|
|
140
|
+
"responses": {
|
|
141
|
+
"200": {
|
|
142
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
143
|
+
"content": {
|
|
144
|
+
"application/json": {
|
|
145
|
+
"schema": {
|
|
146
|
+
"properties": {
|
|
147
|
+
"name": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
"type": "object",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
"/one/ids/{id}": {
|
|
160
|
+
"get": {
|
|
161
|
+
"operationId": "getOneIdsById",
|
|
162
|
+
"responses": {
|
|
163
|
+
"200": {
|
|
164
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
165
|
+
"content": {
|
|
166
|
+
"application/json": {
|
|
167
|
+
"schema": {
|
|
168
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
169
|
+
"type": "string",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
"404": {
|
|
175
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
176
|
+
"content": {
|
|
177
|
+
"application/json": {
|
|
178
|
+
"schema": {
|
|
179
|
+
"properties": {
|
|
180
|
+
"message": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
"required": [
|
|
185
|
+
"message",
|
|
186
|
+
],
|
|
187
|
+
"type": "object",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
"/openapi": {
|
|
196
|
+
"get": {
|
|
197
|
+
"operationId": "getOpenapi",
|
|
198
|
+
"responses": {},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
"/queryParams": {
|
|
202
|
+
"get": {
|
|
203
|
+
"operationId": "getQueryParams",
|
|
204
|
+
"parameters": [
|
|
205
|
+
{
|
|
206
|
+
"in": "query",
|
|
207
|
+
"name": "name",
|
|
208
|
+
"required": true,
|
|
209
|
+
"schema": {
|
|
210
|
+
"type": "string",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
"responses": {
|
|
215
|
+
"200": {
|
|
216
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
217
|
+
"content": {
|
|
218
|
+
"application/json": {
|
|
219
|
+
"schema": {
|
|
220
|
+
"properties": {
|
|
221
|
+
"name": {
|
|
222
|
+
"type": "string",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
"type": "object",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
"post": {
|
|
233
|
+
"description": "This is a post",
|
|
234
|
+
"operationId": "postQueryParamsXXX",
|
|
235
|
+
"parameters": [],
|
|
236
|
+
"requestBody": {
|
|
237
|
+
"content": {
|
|
238
|
+
"application/json": {
|
|
239
|
+
"schema": {
|
|
240
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
241
|
+
"additionalProperties": false,
|
|
242
|
+
"properties": {
|
|
243
|
+
"name": {
|
|
244
|
+
"type": "string",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
"required": [
|
|
248
|
+
"name",
|
|
249
|
+
],
|
|
250
|
+
"type": "object",
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
"required": true,
|
|
255
|
+
},
|
|
256
|
+
"responses": {
|
|
257
|
+
"200": {
|
|
258
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
259
|
+
"content": {
|
|
260
|
+
"application/json": {
|
|
261
|
+
"schema": {
|
|
262
|
+
"properties": {
|
|
263
|
+
"name": {
|
|
264
|
+
"type": "string",
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
"type": "object",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
"/two/ids/{id}": {
|
|
276
|
+
"get": {
|
|
277
|
+
"operationId": "getTwoIdsById",
|
|
278
|
+
"parameters": [
|
|
279
|
+
{
|
|
280
|
+
"in": "path",
|
|
281
|
+
"name": "id",
|
|
282
|
+
"required": true,
|
|
283
|
+
"schema": {
|
|
284
|
+
"type": "string",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
"responses": {},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
}
|
|
293
|
+
`)
|
|
294
|
+
})
|
package/src/openapi.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
1
|
import { JSONSchemaType } from 'ajv'
|
|
3
2
|
import { InternalRoute, isZodSchema, Spiceflow } from './spiceflow.js'
|
|
4
3
|
import { ZodType } from 'zod'
|
|
@@ -6,11 +5,8 @@ import { ZodType } from 'zod'
|
|
|
6
5
|
import type { OpenAPIV3 } from 'openapi-types'
|
|
7
6
|
|
|
8
7
|
let excludeMethods = ['OPTIONS']
|
|
9
|
-
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
10
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
11
|
-
import type { HTTPMethod, LocalHook, TypeSchema } from './elysia-fork/types.js'
|
|
12
8
|
|
|
13
|
-
import {
|
|
9
|
+
import type { HTTPMethod, LocalHook, TypeSchema } from './elysia-fork/types.js'
|
|
14
10
|
|
|
15
11
|
import deepClone from 'lodash.clonedeep'
|
|
16
12
|
import { z } from 'zod'
|
|
@@ -143,14 +139,19 @@ export const registerSchemaPath = ({
|
|
|
143
139
|
? [contentType]
|
|
144
140
|
: contentType ?? ['application/json']
|
|
145
141
|
|
|
146
|
-
const bodySchema = hook?.body
|
|
142
|
+
const bodySchema = getJsonSchema(hook?.body)
|
|
147
143
|
const paramsSchema = hook?.params
|
|
148
144
|
// const headerSchema = hook?.headers
|
|
149
145
|
const querySchema = hook?.query
|
|
150
|
-
let responseSchema = hook?.response as unknown as
|
|
146
|
+
let responseSchema = hook?.response as unknown as TypeSchema
|
|
147
|
+
let openapiResponse: OpenAPIV3.ResponsesObject = {}
|
|
151
148
|
|
|
152
149
|
if (typeof responseSchema === 'object') {
|
|
153
|
-
|
|
150
|
+
const isStatusMap = Object.keys(responseSchema).every(
|
|
151
|
+
(key) => typeof key === 'number' || Number.isInteger(Number(key)),
|
|
152
|
+
)
|
|
153
|
+
if (!isStatusMap) {
|
|
154
|
+
let jsonSchema = getJsonSchema(responseSchema)
|
|
154
155
|
const {
|
|
155
156
|
type,
|
|
156
157
|
properties,
|
|
@@ -158,13 +159,9 @@ export const registerSchemaPath = ({
|
|
|
158
159
|
additionalProperties,
|
|
159
160
|
patternProperties,
|
|
160
161
|
...rest
|
|
161
|
-
} =
|
|
162
|
-
type: string
|
|
163
|
-
properties: Object
|
|
164
|
-
required: string[]
|
|
165
|
-
}
|
|
162
|
+
} = jsonSchema
|
|
166
163
|
|
|
167
|
-
|
|
164
|
+
openapiResponse = {
|
|
168
165
|
'200': {
|
|
169
166
|
...rest,
|
|
170
167
|
description: rest.description as any,
|
|
@@ -175,71 +172,64 @@ export const registerSchemaPath = ({
|
|
|
175
172
|
type,
|
|
176
173
|
properties,
|
|
177
174
|
patternProperties,
|
|
178
|
-
items:
|
|
175
|
+
items: jsonSchema.items,
|
|
179
176
|
required,
|
|
180
177
|
} as any)
|
|
181
|
-
:
|
|
178
|
+
: jsonSchema,
|
|
182
179
|
),
|
|
183
180
|
},
|
|
184
181
|
}
|
|
185
182
|
} else {
|
|
186
|
-
Object.entries(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
...rest,
|
|
207
|
-
description: rest.description as any,
|
|
208
|
-
content: mapTypesResponse(contentTypes, value),
|
|
209
|
-
}
|
|
210
|
-
} else {
|
|
211
|
-
const {
|
|
212
|
-
type,
|
|
213
|
-
properties,
|
|
214
|
-
required,
|
|
215
|
-
additionalProperties,
|
|
216
|
-
patternProperties,
|
|
217
|
-
...rest
|
|
218
|
-
} = value as typeof value & {
|
|
219
|
-
type: string
|
|
220
|
-
properties: Object
|
|
221
|
-
required: string[]
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
responseSchema[key] = {
|
|
225
|
-
...rest,
|
|
226
|
-
description: rest.description as any,
|
|
227
|
-
content: mapTypesResponse(
|
|
228
|
-
contentTypes,
|
|
229
|
-
type === 'object' || type === 'array'
|
|
230
|
-
? ({
|
|
231
|
-
type,
|
|
232
|
-
properties,
|
|
233
|
-
patternProperties,
|
|
234
|
-
items: value.items,
|
|
235
|
-
required,
|
|
236
|
-
} as any)
|
|
237
|
-
: value,
|
|
238
|
-
),
|
|
239
|
-
}
|
|
183
|
+
Object.entries(
|
|
184
|
+
responseSchema as Record<string, TypeSchema>,
|
|
185
|
+
).forEach(([key, value]) => {
|
|
186
|
+
if (typeof value === 'string') {
|
|
187
|
+
if (!models[value]) return
|
|
188
|
+
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
190
|
+
const {
|
|
191
|
+
type,
|
|
192
|
+
properties,
|
|
193
|
+
required,
|
|
194
|
+
additionalProperties: _1,
|
|
195
|
+
patternProperties: _2,
|
|
196
|
+
...rest
|
|
197
|
+
} = getJsonSchema(models[value])
|
|
198
|
+
|
|
199
|
+
openapiResponse[key] = {
|
|
200
|
+
...rest,
|
|
201
|
+
description: rest.description as any,
|
|
202
|
+
content: mapTypesResponse(contentTypes, value),
|
|
240
203
|
}
|
|
241
|
-
}
|
|
242
|
-
|
|
204
|
+
} else {
|
|
205
|
+
const schema = getJsonSchema(value)
|
|
206
|
+
const {
|
|
207
|
+
type,
|
|
208
|
+
properties,
|
|
209
|
+
required,
|
|
210
|
+
additionalProperties,
|
|
211
|
+
patternProperties,
|
|
212
|
+
...rest
|
|
213
|
+
} = schema
|
|
214
|
+
|
|
215
|
+
openapiResponse[key] = {
|
|
216
|
+
...rest,
|
|
217
|
+
description: rest.description as any,
|
|
218
|
+
content: mapTypesResponse(
|
|
219
|
+
contentTypes,
|
|
220
|
+
type === 'object' || type === 'array'
|
|
221
|
+
? ({
|
|
222
|
+
type,
|
|
223
|
+
properties,
|
|
224
|
+
patternProperties,
|
|
225
|
+
items: rest.items,
|
|
226
|
+
required,
|
|
227
|
+
} as any)
|
|
228
|
+
: schema,
|
|
229
|
+
),
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
})
|
|
243
233
|
}
|
|
244
234
|
} else if (typeof responseSchema === 'string') {
|
|
245
235
|
if (!(responseSchema in models)) return
|
|
@@ -252,13 +242,9 @@ export const registerSchemaPath = ({
|
|
|
252
242
|
additionalProperties: _1,
|
|
253
243
|
patternProperties: _2,
|
|
254
244
|
...rest
|
|
255
|
-
} = models[responseSchema]
|
|
256
|
-
type: string
|
|
257
|
-
properties: Object
|
|
258
|
-
required: string[]
|
|
259
|
-
}
|
|
245
|
+
} = getJsonSchema(models[responseSchema])
|
|
260
246
|
|
|
261
|
-
|
|
247
|
+
openapiResponse = {
|
|
262
248
|
// @ts-ignore
|
|
263
249
|
'200': {
|
|
264
250
|
...rest,
|
|
@@ -279,9 +265,9 @@ export const registerSchemaPath = ({
|
|
|
279
265
|
...((paramsSchema || querySchema || bodySchema
|
|
280
266
|
? ({ parameters } as any)
|
|
281
267
|
: {}) satisfies OpenAPIV3.ParameterObject),
|
|
282
|
-
...(
|
|
268
|
+
...(openapiResponse
|
|
283
269
|
? {
|
|
284
|
-
responses:
|
|
270
|
+
responses: openapiResponse,
|
|
285
271
|
}
|
|
286
272
|
: {}),
|
|
287
273
|
operationId:
|
|
@@ -312,10 +298,10 @@ export const registerSchemaPath = ({
|
|
|
312
298
|
* @see https://github.com/elysiajs/elysia-swagger
|
|
313
299
|
*/
|
|
314
300
|
export const openapi = <Path extends string = '/openapi'>({
|
|
315
|
-
path,
|
|
301
|
+
path = '/openapi' as Path,
|
|
316
302
|
documentation = {},
|
|
317
303
|
}: {
|
|
318
|
-
path
|
|
304
|
+
path?: Path
|
|
319
305
|
/**
|
|
320
306
|
* Customize Swagger config, refers to Swagger 2.0 config
|
|
321
307
|
*
|
|
@@ -326,7 +312,7 @@ export const openapi = <Path extends string = '/openapi'>({
|
|
|
326
312
|
| 'x-express-openapi-additional-middleware'
|
|
327
313
|
| 'x-express-openapi-validation-strict'
|
|
328
314
|
>
|
|
329
|
-
}) => {
|
|
315
|
+
} = {}) => {
|
|
330
316
|
const schema = {}
|
|
331
317
|
let totalRoutes = 0
|
|
332
318
|
|
|
@@ -392,7 +378,7 @@ export const openapi = <Path extends string = '/openapi'>({
|
|
|
392
378
|
// (tag) => !excludeTags?.includes(tag?.name),
|
|
393
379
|
// ),
|
|
394
380
|
info: {
|
|
395
|
-
title: '
|
|
381
|
+
title: 'Spiceflow Documentation',
|
|
396
382
|
description: 'Development documentation',
|
|
397
383
|
version: '0.0.0',
|
|
398
384
|
...documentation.info,
|
|
@@ -417,6 +403,7 @@ export const openapi = <Path extends string = '/openapi'>({
|
|
|
417
403
|
}
|
|
418
404
|
|
|
419
405
|
function getJsonSchema(schema: TypeSchema): JSONSchemaType<any> {
|
|
406
|
+
if (!schema) return undefined as any
|
|
420
407
|
if (isZodSchema(schema)) {
|
|
421
408
|
let fn = zodToJsonSchema.default ?? zodToJsonSchema
|
|
422
409
|
let jsonSchema = fn(schema, {})
|
package/src/spiceflow.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
HTTPMethod,
|
|
15
15
|
InlineHandler,
|
|
16
16
|
InputSchema,
|
|
17
|
+
IsAny,
|
|
17
18
|
JoinPath,
|
|
18
19
|
LocalHook,
|
|
19
20
|
MaybeArray,
|
|
@@ -889,20 +890,8 @@ export class Spiceflow<
|
|
|
889
890
|
|
|
890
891
|
use<const NewSpiceflow extends AnySpiceflow>(
|
|
891
892
|
instance: NewSpiceflow,
|
|
892
|
-
): NewSpiceflow
|
|
893
|
-
?
|
|
894
|
-
BasePath,
|
|
895
|
-
Scoped,
|
|
896
|
-
// @ts-expect-error - This is truly ideal
|
|
897
|
-
Prettify2<Singleton & NewSpiceflow['_types']['Singleton']>,
|
|
898
|
-
Prettify2<Definitions & NewSpiceflow['_types']['Definitions']>,
|
|
899
|
-
Prettify2<Metadata & NewSpiceflow['_types']['Metadata']>,
|
|
900
|
-
BasePath extends ``
|
|
901
|
-
? Routes & NewSpiceflow['_routes']
|
|
902
|
-
: Routes & CreateEden<BasePath, NewSpiceflow['_routes']>,
|
|
903
|
-
Ephemeral,
|
|
904
|
-
Prettify2<Volatile & NewSpiceflow['_ephemeral']>
|
|
905
|
-
>
|
|
893
|
+
): IsAny<NewSpiceflow> extends true
|
|
894
|
+
? this
|
|
906
895
|
: Spiceflow<
|
|
907
896
|
BasePath,
|
|
908
897
|
Scoped,
|
|
@@ -980,7 +969,7 @@ export class Spiceflow<
|
|
|
980
969
|
async handle(request: Request, platform?: P): Promise<Response> {
|
|
981
970
|
platform ??= {} as P
|
|
982
971
|
|
|
983
|
-
let u = new URL(request.url)
|
|
972
|
+
let u = new URL(request.url, 'http://localhost')
|
|
984
973
|
let path = u.pathname + u.search
|
|
985
974
|
const defaultContext = {
|
|
986
975
|
redirect,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { test, describe, expect } from 'vitest'
|
|
2
|
+
import { Type } from '@sinclair/typebox'
|
|
3
|
+
import { bfs, Spiceflow } from './spiceflow.js'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
import { createSpiceflowClient } from './client/index.js'
|
|
6
|
+
import { Prettify } from './elysia-fork/types.js'
|
|
7
|
+
|
|
8
|
+
test('`use` on non Spiceflow return', async () => {
|
|
9
|
+
function nonSpiceflowReturn() {
|
|
10
|
+
return new Spiceflow() as any
|
|
11
|
+
}
|
|
12
|
+
const app = new Spiceflow()
|
|
13
|
+
.use(nonSpiceflowReturn())
|
|
14
|
+
.post('/xxx', () => 'hi')
|
|
15
|
+
const res = await app.handle(
|
|
16
|
+
new Request('http://localhost/xxx', { method: 'POST' }),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
let client = createSpiceflowClient(app)
|
|
20
|
+
|
|
21
|
+
type ClientType = Prettify<typeof client>
|
|
22
|
+
// @ts-expect-error
|
|
23
|
+
client.something
|
|
24
|
+
|
|
25
|
+
client.xxx.post()
|
|
26
|
+
expect(res.status).toBe(200)
|
|
27
|
+
expect(await res.json()).toEqual('hi')
|
|
28
|
+
})
|
|
29
|
+
test('`use` on Spiceflow return', async () => {
|
|
30
|
+
function nonSpiceflowReturn() {
|
|
31
|
+
return new Spiceflow().post('/usePost', () => 'hi')
|
|
32
|
+
}
|
|
33
|
+
const app = new Spiceflow()
|
|
34
|
+
.use(nonSpiceflowReturn())
|
|
35
|
+
.post('/xxx', () => 'hi')
|
|
36
|
+
const res = await app.handle(
|
|
37
|
+
new Request('http://localhost/xxx', { method: 'POST' }),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
let client = createSpiceflowClient(app)
|
|
41
|
+
client.xxx.post()
|
|
42
|
+
client.usePost.post()
|
|
43
|
+
|
|
44
|
+
type ClientType = Prettify<typeof client>
|
|
45
|
+
// @ts-expect-error
|
|
46
|
+
client.something
|
|
47
|
+
|
|
48
|
+
expect(res.status).toBe(200)
|
|
49
|
+
expect(await res.json()).toEqual('hi')
|
|
50
|
+
})
|