@elysiajs/eden 0.8.0 → 1.0.0-beta.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.
Files changed (43) hide show
  1. package/.github/FUNDING.yaml +1 -0
  2. package/.github/workflows/ci.yml +28 -0
  3. package/README.md +1 -1
  4. package/dist/chunk-R27QELXO.mjs +1 -0
  5. package/dist/chunk-VMCNRAXS.mjs +1 -0
  6. package/dist/chunk-YTAZNCPF.mjs +1 -0
  7. package/dist/fetch/index.d.ts +1 -1
  8. package/dist/fetch/types.d.ts +11 -13
  9. package/dist/fetch.d.mts +12 -13
  10. package/dist/fetch.d.ts +12 -13
  11. package/dist/fetch.global.js +1 -1
  12. package/dist/fetch.js +1 -1
  13. package/dist/fetch.mjs +1 -1
  14. package/dist/index.d.mts +68 -2
  15. package/dist/index.d.ts +68 -2
  16. package/dist/index.global.js +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/treaty/index.d.ts +1 -1
  20. package/dist/treaty/types.d.ts +58 -61
  21. package/dist/treaty/utils.d.ts +1 -0
  22. package/dist/treaty.d.mts +59 -62
  23. package/dist/treaty.d.ts +59 -62
  24. package/dist/treaty.global.js +1 -1
  25. package/dist/treaty.js +1 -1
  26. package/dist/treaty.mjs +1 -1
  27. package/dist/treaty2/index.d.ts +4 -0
  28. package/dist/treaty2/types.d.ts +64 -0
  29. package/dist/treaty2/ws.d.ts +14 -0
  30. package/dist/{types-d1b334ad.d.ts → types-BQi-Ff9p.d.ts} +22 -1
  31. package/dist/types.d.ts +19 -7
  32. package/package.json +69 -77
  33. package/dist/chunk-3KYW6H6M.mjs +0 -1
  34. package/dist/chunk-NZCTJ6S3.mjs +0 -1
  35. package/dist/chunk-Y6SMVGJX.mjs +0 -1
  36. package/src/errors.ts +0 -16
  37. package/src/fetch/index.ts +0 -82
  38. package/src/fetch/types.ts +0 -81
  39. package/src/index.ts +0 -7
  40. package/src/treaty/index.ts +0 -376
  41. package/src/treaty/types.ts +0 -219
  42. package/src/treaty/utils.ts +0 -15
  43. package/src/types.ts +0 -58
@@ -1,376 +0,0 @@
1
- import type { Elysia, InputSchema } from 'elysia'
2
-
3
- import { EdenFetchError } from '../errors'
4
-
5
- import { composePath } from './utils'
6
- import type { EdenTreaty } from './types'
7
-
8
- export type { EdenTreaty } from './types'
9
-
10
- // @ts-ignore
11
- const isServer = typeof FileList === 'undefined'
12
-
13
- const isFile = (v: any) => {
14
- // @ts-ignore
15
- if (isServer) {
16
- return v instanceof Blob
17
- } else {
18
- // @ts-ignore
19
- return v instanceof FileList || v instanceof File
20
- }
21
- }
22
-
23
- // FormData is 1 level deep
24
- const hasFile = (obj: Record<string, any>) => {
25
- if (!obj) return false
26
-
27
- for (const key in obj) {
28
- if (isFile(obj[key])) return true
29
- else if (
30
- Array.isArray(obj[key]) &&
31
- (obj[key] as unknown[]).find((x) => isFile(x))
32
- )
33
- return true
34
- }
35
-
36
- return false
37
- }
38
-
39
- // @ts-ignore
40
- const createNewFile = (v: File) =>
41
- isServer
42
- ? v
43
- : new Promise<File>((resolve) => {
44
- // @ts-ignore
45
- const reader = new FileReader()
46
-
47
- reader.onload = () => {
48
- const file = new File([reader.result!], v.name, {
49
- lastModified: v.lastModified,
50
- type: v.type
51
- })
52
- resolve(file)
53
- }
54
-
55
- reader.readAsArrayBuffer(v)
56
- })
57
-
58
- export class EdenWS<Schema extends InputSchema<any> = InputSchema> {
59
- ws: WebSocket
60
- url: string
61
-
62
- constructor(url: string) {
63
- this.ws = new WebSocket(url)
64
- this.url = url
65
- }
66
-
67
- send(data: Schema['body'] | Schema['body'][]) {
68
- if (Array.isArray(data)) {
69
- data.forEach((datum) => this.send(datum))
70
-
71
- return this
72
- }
73
-
74
- this.ws.send(
75
- typeof data === 'object' ? JSON.stringify(data) : data.toString()
76
- )
77
-
78
- return this
79
- }
80
-
81
- on<K extends keyof WebSocketEventMap>(
82
- type: K,
83
- listener: (event: EdenTreaty.WSEvent<K, Schema['response']>) => void,
84
- options?: boolean | AddEventListenerOptions
85
- ) {
86
- return this.addEventListener(type, listener, options)
87
- }
88
-
89
- off<K extends keyof WebSocketEventMap>(
90
- type: K,
91
- listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any,
92
- options?: boolean | EventListenerOptions
93
- ) {
94
- this.ws.removeEventListener(type, listener, options)
95
-
96
- return this
97
- }
98
-
99
- subscribe(
100
- onMessage: (
101
- event: EdenTreaty.WSEvent<'message', Schema['response']>
102
- ) => void,
103
- options?: boolean | AddEventListenerOptions
104
- ) {
105
- return this.addEventListener('message', onMessage, options)
106
- }
107
-
108
- addEventListener<K extends keyof WebSocketEventMap>(
109
- type: K,
110
- listener: (event: EdenTreaty.WSEvent<K, Schema['response']>) => void,
111
- options?: boolean | AddEventListenerOptions
112
- ) {
113
- this.ws.addEventListener(
114
- type,
115
- (ws) => {
116
- if (type === 'message') {
117
- let data = (ws as MessageEvent).data.toString() as any
118
- const start = data.charCodeAt(0)
119
-
120
- if (start === 47 || start === 123)
121
- try {
122
- data = JSON.parse(data)
123
- } catch {
124
- // Not Empty
125
- }
126
- else if (!Number.isNaN(+data)) data = +data
127
- else if (data === 'true') data = true
128
- else if (data === 'false') data = false
129
-
130
- listener({
131
- ...ws,
132
- data
133
- } as any)
134
- } else listener(ws as any)
135
- },
136
- options
137
- )
138
-
139
- return this
140
- }
141
-
142
- removeEventListener<K extends keyof WebSocketEventMap>(
143
- type: K,
144
- listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any,
145
- options?: boolean | EventListenerOptions
146
- ) {
147
- this.off(type, listener, options)
148
-
149
- return this
150
- }
151
-
152
- close() {
153
- this.ws.close()
154
-
155
- return this
156
- }
157
- }
158
-
159
- const createProxy = (
160
- domain: string,
161
- path = '',
162
- config: EdenTreaty.Config
163
- ): Record<string, unknown> =>
164
- new Proxy(() => {}, {
165
- get(target, key, value) {
166
- return createProxy(domain, `${path}/${key.toString()}`, config)
167
- },
168
- // @ts-ignore
169
- apply(
170
- target,
171
- _,
172
- [initialBody, options = {}]: [
173
- {
174
- [x: string]: any
175
- $fetch?: RequestInit
176
- $headers?: HeadersInit
177
- $query?: Record<string, string>
178
- getRaw?: boolean
179
- },
180
- {
181
- fetch?: RequestInit
182
- transform?: EdenTreaty.Transform
183
- headers?: Record<string, string>
184
- query?: Record<string, string | number>
185
- }
186
- ] = [{}, {}]
187
- ) {
188
- let bodyObj: any =
189
- initialBody !== undefined &&
190
- (typeof initialBody !== 'object' || Array.isArray(initialBody))
191
- ? initialBody
192
- : undefined
193
-
194
- const { $query, $fetch, $headers, $transform, getRaw, ...restBody } =
195
- initialBody ?? {}
196
-
197
- bodyObj ??= restBody
198
-
199
- const i = path.lastIndexOf('/'),
200
- method = path.slice(i + 1).toUpperCase(),
201
- url = composePath(
202
- domain,
203
- i === -1 ? '/' : path.slice(0, i),
204
- Object.assign(options.query ?? {}, $query)
205
- )
206
-
207
- const fetcher = config.fetcher ?? fetch
208
- let transforms = config.transform
209
- ? Array.isArray(config.transform)
210
- ? config.transform
211
- : [config.transform]
212
- : undefined
213
-
214
- const $transforms = $transform
215
- ? Array.isArray($transform)
216
- ? $transform
217
- : [$transform]
218
- : undefined
219
-
220
- if ($transforms) {
221
- if (transforms) transforms = $transforms.concat(transforms)
222
- else transforms = $transforms as any
223
- }
224
-
225
- if (method === 'SUBSCRIBE')
226
- return new EdenWS(
227
- url.replace(
228
- /^([^]+):\/\//,
229
- url.startsWith('https://') ? 'wss://' : 'ws://'
230
- )
231
- )
232
-
233
- const execute = async <T extends EdenTreaty.ExecuteOptions>(modifiers: T): Promise<EdenTreaty.ExecuteReturnType<T>> => {
234
- let body: any
235
-
236
- const headers = {
237
- ...config.$fetch?.headers,
238
- ...$fetch?.headers,
239
- ...options.headers,
240
- ...$headers
241
- } as Record<string, string>
242
-
243
- if (method !== 'GET' && method !== 'HEAD') {
244
- body = Object.keys(bodyObj).length
245
- ? bodyObj
246
- : Array.isArray(bodyObj)
247
- ? bodyObj
248
- : undefined
249
-
250
- const isObject =
251
- typeof body === 'object' || Array.isArray(bodyObj)
252
- const isFormData = isObject && hasFile(body)
253
-
254
- if (isFormData) {
255
- const newBody = new FormData()
256
-
257
- // FormData is 1 level deep
258
- for (const [key, field] of Object.entries(body)) {
259
- if (isServer) {
260
- newBody.append(key, field as any)
261
- } else {
262
- // @ts-ignore
263
- if (field instanceof File)
264
- newBody.append(
265
- key,
266
- await createNewFile(field as any)
267
- )
268
- // @ts-ignore
269
- else if (field instanceof FileList) {
270
- // @ts-ignore
271
- for (let i = 0; i < field.length; i++) {
272
- newBody.append(
273
- key as any,
274
- await createNewFile(
275
- (field as any)[i]
276
- )
277
- )
278
- }
279
- } else if (Array.isArray(field)) {
280
- for (let i = 0; i < field.length; i++) {
281
- const value = (field as any)[i]
282
-
283
- newBody.append(
284
- key as any,
285
- value instanceof File
286
- ? await createNewFile(value)
287
- : value
288
- )
289
- }
290
- } else newBody.append(key, field as string)
291
- }
292
- }
293
-
294
- body = newBody
295
- } else {
296
- headers['content-type'] = isObject
297
- ? 'application/json'
298
- : 'text/plain'
299
-
300
- body = isObject ? JSON.stringify(body) : bodyObj
301
- }
302
- }
303
-
304
- const response = await fetcher(url, {
305
- method,
306
- body,
307
- ...config.$fetch,
308
- ...options.fetch,
309
- ...$fetch,
310
- headers
311
- })
312
-
313
- let data
314
-
315
- if (modifiers.getRaw) return response as any
316
- switch (response.headers.get('Content-Type')?.split(';')[0]) {
317
- case 'application/json':
318
- data = await response.json()
319
- break
320
-
321
- default:
322
- data = await response.text().then((data) => {
323
- if (!Number.isNaN(+data)) return +data
324
- if (data === 'true') return true
325
- if (data === 'false') return false
326
-
327
- return data
328
- })
329
- }
330
-
331
- const error =
332
- response.status >= 300 || response.status < 200
333
- ? new EdenFetchError(response.status, data)
334
- : null
335
-
336
- if (transforms)
337
- for (const transform of transforms) {
338
- let temp = transform({
339
- data,
340
- status: response.status,
341
- headers: response.headers,
342
- response,
343
- error
344
- })
345
- if (temp instanceof Promise) temp = await temp
346
-
347
- if (temp !== undefined && temp !== null) data = temp
348
- }
349
-
350
- return {
351
- data,
352
- error,
353
- response: response,
354
- status: response.status,
355
- headers: response.headers
356
- } as any
357
- }
358
-
359
- return execute({ getRaw })
360
- }
361
- }) as unknown as Record<string, unknown>
362
-
363
- export const edenTreaty = <App extends Elysia<any, any, any, any, any, any>>(
364
- domain: string,
365
- config: EdenTreaty.Config = {
366
- fetcher: fetch
367
- }
368
- ): EdenTreaty.Create<App> =>
369
- new Proxy(
370
- {},
371
- {
372
- get(target, key) {
373
- return createProxy(domain, key as string, config)
374
- }
375
- }
376
- ) as any
@@ -1,219 +0,0 @@
1
- /// <reference lib="dom" />
2
- import type { Elysia } from 'elysia'
3
- import type { EdenWS } from './index'
4
- import type {
5
- IsUnknown,
6
- IsNever,
7
- IsAny,
8
- UnionToIntersect,
9
- MapError
10
- } from '../types'
11
- import type { EdenFetchError } from '../errors'
12
-
13
- type Files = File | FileList
14
-
15
- type Replace<RecordType, TargetType, GenericType> = {
16
- [K in keyof RecordType]: RecordType[K] extends TargetType
17
- ? GenericType
18
- : RecordType[K]
19
- }
20
-
21
- type Split<S extends string> = S extends `${infer Head}/${infer Tail}`
22
- ? Head extends ''
23
- ? Tail extends ''
24
- ? []
25
- : Split<Tail>
26
- : [Head, ...Split<Tail>]
27
- : S extends `/`
28
- ? []
29
- : S extends `${infer Head}/`
30
- ? [Head]
31
- : [S]
32
-
33
- type Prettify<T> = {
34
- [K in keyof T]: T[K]
35
- } & {}
36
-
37
- type AnySchema = {
38
- body: unknown
39
- headers: unknown
40
- query: unknown
41
- params: unknown
42
- response: any
43
- }
44
-
45
- type MaybeArray<T> = T | T[]
46
-
47
- export namespace EdenTreaty {
48
- export type Create<App extends Elysia<any, any, any, any, any, any>> =
49
- App extends {
50
- schema: infer Schema extends Record<string, any>
51
- }
52
- ? UnionToIntersect<Sign<Schema>>
53
- : 'Please install Elysia before using Eden'
54
-
55
- type SplitKeys<T> = T extends [infer First, ...infer Rest]
56
- ? [First, Rest]
57
- : T extends [infer First, ...infer Rest][number]
58
- ? [First, Rest]
59
- : never
60
-
61
- type UnwrapPromise<T> = T extends Promise<infer A> ? A : T
62
-
63
- export type Transform<T = unknown> = MaybeArray<
64
- (
65
- response: unknown extends T
66
- ? {
67
- data: any
68
- error: any
69
- response: Response
70
- status: number
71
- headers: Headers
72
- }
73
- : UnwrapPromise<T>
74
- ) => UnwrapPromise<T> | void
75
- >
76
-
77
- export interface Config {
78
- /**
79
- * Default options to pass to fetch
80
- */
81
- $fetch?: RequestInit
82
- fetcher?: typeof fetch
83
- transform?: Transform
84
- }
85
-
86
- export type DetailedResponse = {
87
- data: any
88
- error: any
89
- response: Response
90
- status: number
91
- headers: Headers
92
- };
93
-
94
- export type Sign<
95
- Schema extends Record<string, Record<string, unknown>>,
96
- Paths extends (string | number)[] = Split<keyof Schema & string>,
97
- Carry extends string = ''
98
- > = Paths extends [
99
- infer Prefix extends string | number,
100
- ...infer Rest extends (string | number)[]
101
- ]
102
- ? {
103
- [Key in Prefix as Prefix extends `:${string}`
104
- ? (string & {}) | number | Prefix
105
- : Prefix]: Sign<Schema, Rest, `${Carry}/${Key}`>
106
- }
107
- : Schema[Carry extends '' ? '/' : Carry] extends infer Routes
108
- ? {
109
- [Method in keyof Routes]: Routes[Method] extends infer Route extends
110
- AnySchema
111
- ? Method extends 'subscribe'
112
- ? undefined extends Route['query']
113
- ? (params?: {
114
- $query?: Record<string, string>
115
- }) => EdenWS<Route>
116
- : (params: {
117
- $query: Route['query']
118
- }) => EdenWS<Route>
119
- : ((
120
- params: {
121
- $fetch?: RequestInit
122
- getRaw?: boolean
123
- } & (IsUnknown<Route['body']> extends false
124
- ? Replace<
125
- Route['body'],
126
- Blob | Blob[],
127
- Files
128
- >
129
- : {}) &
130
- (undefined extends Route['query']
131
- ? {
132
- $query?: Record<string, string>
133
- }
134
- : {
135
- $query: Route['query']
136
- }) &
137
- (undefined extends Route['headers']
138
- ? {
139
- $headers?: Record<string, unknown>
140
- }
141
- : {
142
- $headers: Route['headers']
143
- })
144
- ) => Promise<
145
- (
146
- | {
147
- data: Route['response'] extends {
148
- 200: infer ReturnedType
149
- }
150
- ? Awaited<ReturnedType>
151
- : unknown
152
- error: null
153
- }
154
- | {
155
- data: null
156
- error: MapError<
157
- Route['response']
158
- > extends infer Errors
159
- ? IsNever<Errors> extends true
160
- ? EdenFetchError<
161
- number,
162
- string
163
- >
164
- : Errors
165
- : EdenFetchError<number, string>
166
- }
167
- ) & {
168
- status: number
169
- response: Response
170
- headers: Record<string, string>
171
- }
172
- >) extends (params: infer Params) => infer Response
173
- ? {
174
- $params: undefined
175
- $headers: undefined
176
- $query: undefined
177
- } extends Params
178
- ? (
179
- params?: Params,
180
- options?: {
181
- fetch?: RequestInit
182
- transform?: EdenTreaty.Transform<Response>
183
- // @ts-ignore
184
- query?: Params['query']
185
- // @ts-ignore
186
- headers?: Params['headers']
187
- }
188
- ) => Response
189
- : (
190
- params: Params,
191
- options?: {
192
- fetch?: RequestInit
193
- transform?: EdenTreaty.Transform<Response>
194
- // @ts-ignore
195
- query?: Params['query']
196
- // @ts-ignore
197
- headers?: Params['headers']
198
- }
199
- ) => Response
200
- : never
201
- : never
202
- }
203
- : {}
204
-
205
- export interface OnMessage<Data = unknown> extends MessageEvent {
206
- data: Data
207
- rawData: MessageEvent['data']
208
- }
209
-
210
- export type ExecuteOptions = {
211
- getRaw?: boolean
212
- };
213
- export type ExecuteReturnType<T extends ExecuteOptions> = T['getRaw'] extends true ? Response : DetailedResponse;
214
-
215
- export type WSEvent<
216
- K extends keyof WebSocketEventMap,
217
- Data = unknown
218
- > = K extends 'message' ? OnMessage<Data> : WebSocketEventMap[K]
219
- }
@@ -1,15 +0,0 @@
1
- export const composePath = (
2
- domain: string,
3
- path: string,
4
- query: Record<string, string> | undefined
5
- ) => {
6
- if (!domain.endsWith('/')) domain += '/'
7
- if (path === 'index') path = ''
8
-
9
- if (!query || !Object.keys(query).length) return `${domain}${path}`
10
-
11
- let q = ''
12
- for (const [key, value] of Object.entries(query)) q += `${key}=${value}&`
13
-
14
- return `${domain}${path}?${q.slice(0, -1)}`
15
- }
package/src/types.ts DELETED
@@ -1,58 +0,0 @@
1
- import type { EdenFetchError } from './errors'
2
-
3
- // https://stackoverflow.com/a/39495173
4
- type Range<F extends number, T extends number> = Exclude<
5
- Enumerate<T>,
6
- Enumerate<F>
7
- >
8
-
9
- type Enumerate<
10
- N extends number,
11
- Acc extends number[] = []
12
- > = Acc['length'] extends N
13
- ? Acc[number]
14
- : Enumerate<N, [...Acc, Acc['length']]>
15
-
16
- type ErrorRange = Range<300, 599>
17
-
18
- export type MapError<T extends Record<number, unknown>> = [
19
- {
20
- [K in keyof T]-?: K extends ErrorRange ? K : never
21
- }[keyof T]
22
- ] extends [infer A extends number]
23
- ? {
24
- [K in A]: EdenFetchError<K, T[K]>
25
- }[A]
26
- : false
27
-
28
- export type UnionToIntersect<U> = (
29
- U extends any ? (arg: U) => any : never
30
- ) extends (arg: infer I) => void
31
- ? I
32
- : never
33
-
34
- export type UnionToTuple<T> = UnionToIntersect<
35
- T extends any ? (t: T) => T : never
36
- > extends (_: any) => infer W
37
- ? [...UnionToTuple<Exclude<T, W>>, W]
38
- : []
39
-
40
- export type IsAny<T> = 0 extends 1 & T ? true : false
41
-
42
- export type IsNever<T> = [T] extends [never] ? true : false
43
-
44
- export type IsUnknown<T> = IsAny<T> extends true
45
- ? false
46
- : unknown extends T
47
- ? true
48
- : false
49
-
50
- export type AnyTypedRoute = {
51
- body: unknown
52
- headers: Record<string, any> | undefined
53
- query: Record<string, any> | undefined
54
- params: Record<string, any> | undefined
55
- response: Record<string, unknown> & {
56
- '200': unknown
57
- }
58
- }