@elysiajs/eden 0.3.0 → 0.3.2

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.
@@ -1,4 +1,3 @@
1
- /// <reference types="bun-types" />
2
1
  import type { Elysia, SCHEMA } from 'elysia';
3
2
  import type { EdenFetchError } from '../utils';
4
3
  import type { MapError, IsUnknown, IsNever } from '../types';
package/dist/fetch.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("./utils-0d7d9b21.js"),h=(o,p)=>async(n,{params:i,body:a,...c}={})=>{var u;i&&Object.entries(i).forEach(([e,t])=>{n=n.replace(`:${e}`,t)});const s=(u=c.headers)==null?void 0:u["Content-Type"];return(!s||s==="application/json")&&(a=JSON.stringify(a)),fetch(o+n,{...c,headers:{"content-type":"application/json",...c.headers},body:a}).then(async e=>{var l;let t;switch((l=e.headers.get("Content-Type"))==null?void 0:l.split(";")[0]){case"application/json":t=await e.json();break;default:t=await e.text().then(r=>Number.isNaN(+r)?r==="true"?!0:r==="false"?!1:r:+r)}return e.status>300?{data:null,error:new f.EdenFetchError(e.status,t)}:{data:t,error:null}})};exports.edenFetch=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("./utils-0d7d9b21.js"),o=(f,p)=>async(c,{params:i,body:a,...n}={})=>{var u;i&&Object.entries(i).forEach(([e,t])=>{c=c.replace(`:${e}`,t)});const s=(u=n.headers)==null?void 0:u["Content-Type"];if(!s||s==="application/json")try{a=JSON.stringify(a)}catch{}return fetch(f+c,{...n,headers:a?{"content-type":"application/json",...n.headers}:n.headers,body:a}).then(async e=>{var l;let t;switch((l=e.headers.get("Content-Type"))==null?void 0:l.split(";")[0]){case"application/json":t=await e.json();break;default:t=await e.text().then(r=>Number.isNaN(+r)?r==="true"?!0:r==="false"?!1:r:+r);break}return e.status>300?{data:null,error:new h.EdenFetchError(e.status,t)}:{data:t,error:null}})};exports.edenFetch=o;
package/dist/fetch.mjs CHANGED
@@ -1,18 +1,23 @@
1
- import { E as o } from "./utils-0d2b8b1a.mjs";
2
- const j = (l, h) => (
1
+ import { E as l } from "./utils-0d2b8b1a.mjs";
2
+ const j = (h, o) => (
3
3
  // @ts-ignore
4
- async (n, { params: i, body: a, ...c } = {}) => {
4
+ async (c, { params: s, body: a, ...n } = {}) => {
5
5
  var u;
6
- i && Object.entries(i).forEach(([e, t]) => {
7
- n = n.replace(`:${e}`, t);
6
+ s && Object.entries(s).forEach(([e, t]) => {
7
+ c = c.replace(`:${e}`, t);
8
8
  });
9
- const s = (u = c.headers) == null ? void 0 : u["Content-Type"];
10
- return (!s || s === "application/json") && (a = JSON.stringify(a)), fetch(l + n, {
11
- ...c,
12
- headers: {
9
+ const i = (u = n.headers) == null ? void 0 : u["Content-Type"];
10
+ if (!i || i === "application/json")
11
+ try {
12
+ a = JSON.stringify(a);
13
+ } catch {
14
+ }
15
+ return fetch(h + c, {
16
+ ...n,
17
+ headers: a ? {
13
18
  "content-type": "application/json",
14
- ...c.headers
15
- },
19
+ ...n.headers
20
+ } : n.headers,
16
21
  body: a
17
22
  }).then(async (e) => {
18
23
  var f;
@@ -23,10 +28,11 @@ const j = (l, h) => (
23
28
  break;
24
29
  default:
25
30
  t = await e.text().then((r) => Number.isNaN(+r) ? r === "true" ? !0 : r === "false" ? !1 : r : +r);
31
+ break;
26
32
  }
27
33
  return e.status > 300 ? {
28
34
  data: null,
29
- error: new o(e.status, t)
35
+ error: new l(e.status, t)
30
36
  } : { data: t, error: null };
31
37
  });
32
38
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="bun-types" />
2
1
  import type { Elysia, EXPOSED } from 'elysia';
3
2
  export declare namespace EdenFn {
4
3
  type Create<App extends Elysia<any>> = App['meta'] extends Record<typeof EXPOSED, infer Schema extends Record<string, any>> ? EdenFn.Compose<Schema> : 'Please install Elysia before using Eden';
@@ -1,4 +1,3 @@
1
- /// <reference types="bun-types" />
2
1
  import type { Elysia, TypedSchema } from 'elysia';
3
2
  import type { EdenTreaty } from './types';
4
3
  export type { EdenTreaty } from './types';
@@ -1,8 +1,10 @@
1
- /// <reference types="bun-types" />
2
1
  import type { Elysia, SCHEMA, AnyTypedSchema } from 'elysia';
3
2
  import type { EdenWS } from './index';
4
3
  import type { IsNever, IsUnknown, MapError, UnionToIntersect } from '../types';
5
4
  import { EdenFetchError } from '../utils';
5
+ type Replace<RecordType, TargetType, GenericType> = {
6
+ [K in keyof RecordType]: RecordType[K] extends TargetType ? GenericType : RecordType[K];
7
+ };
6
8
  export declare namespace EdenTreaty {
7
9
  type Create<App extends Elysia<any>> = App['meta'] extends Record<typeof SCHEMA, infer Schema extends Record<string, any>> ? EdenTreaty.Sign<Schema> : 'Please install Elysia before using Eden';
8
10
  interface Config {
@@ -24,7 +26,7 @@ export declare namespace EdenTreaty {
24
26
  } | {
25
27
  data: null;
26
28
  error: MapError<Route['response']> extends infer Errors ? IsNever<Errors> extends true ? EdenFetchError<number, string> : Errors : EdenFetchError<number, string>;
27
- }> : (params: Route['body'] & {
29
+ }> : (params: Replace<Route['body'], Blob | Blob[], File | FileList> & {
28
30
  $query?: Record<string, string>;
29
31
  $fetch?: RequestInit;
30
32
  }) => Promise<{
@@ -52,7 +54,7 @@ export declare namespace EdenTreaty {
52
54
  } | {
53
55
  data: null;
54
56
  error: MapError<Route['response']> extends infer Errors ? IsNever<Errors> extends true ? EdenFetchError<number, string> : Errors : EdenFetchError<number, string>;
55
- }> : (params: Route['body'] & {
57
+ }> : (params: Replace<Route['body'], Blob | Blob[], File | FileList> & {
56
58
  $query?: Record<string, string>;
57
59
  $fetch?: RequestInit;
58
60
  }) => Promise<{
@@ -77,5 +79,5 @@ export declare namespace EdenTreaty {
77
79
  $query?: Record<string, string>;
78
80
  }
79
81
  }
80
- type NestPath<T extends string, V> = T extends `${infer First}/${infer Rest}` ? First extends `:${infer Parameter}` ? Record<string | number | `:${Parameter}`, NestPath<Rest, V>> : Record<First, NestPath<Rest, V>> : T extends `:${infer Parameter}` ? Record<string | number | T, V> : Record<T, V>;
82
+ type NestPath<T extends string, V> = T extends `${infer First}/${infer Rest}` ? First extends `:${infer Parameter}` ? Record<(string & {}) | number | `:${Parameter}`, NestPath<Rest, V>> : Record<First, NestPath<Rest, V>> : T extends `:${infer Parameter}` ? Record<(string & {}) | number | T, V> : Record<T, V>;
81
83
  export {};
package/dist/treaty.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("./utils-0d7d9b21.js"),p=(n,e,t)=>{if(n.endsWith("/")||(n+="/"),e==="index"&&(e=""),!t||!Object.keys(t).length)return`${n}${e}`;let s="";for(const[i,r]of Object.entries(t))s+=`${i}=${r}&`;return`${n}${e}?${s.slice(0,-1)}`};class v{constructor(e){this.ws=new WebSocket(e),this.url=e}send(e){return Array.isArray(e)?(e.forEach(t=>this.send(t)),this):(this.ws.send(typeof e=="object"?JSON.stringify(e):e.toString()),this)}on(e,t,s){return this.addEventListener(e,t,s)}off(e,t,s){return this.ws.removeEventListener(e,t,s),this}subscribe(e,t){return this.addEventListener("message",e,t)}addEventListener(e,t,s){return this.ws.addEventListener(e,i=>{if(e==="message"){let r=i.data.toString();const o=r.charCodeAt(0);if(o===47||o===123)try{r=JSON.parse(r)}catch{}else Number.isNaN(+r)?r==="true"?r=!0:r==="fase"&&(r=!1):r=+r;t({...i,data:r})}else t(i)},s),this}removeEventListener(e,t,s){return this.off(e,t,s),this}close(){return this.ws.close(),this}}const w=(n,e="",t)=>new Proxy(()=>{},{get(s,i,r){return w(n,`${e}/${i.toString()}`)},apply(s,i,[{$query:r,$fetch:o,$body:E,...d}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){const h=e.lastIndexOf("/"),y=e.slice(h+1),f=p(n,e.slice(0,h),r);if(y==="subscribe")return new v(f.replace(/^([^]+):\/\//,f.startsWith("https://")?"wss://":"ws://"));const l=E??(Object.keys(d).length?d:void 0),g=typeof l=="object";return fetch(f,{method:y,body:g?JSON.stringify(l):l,...o,headers:l?{"content-type":g?"application/json":"text/plain",...o==null?void 0:o.headers}:void 0}).then(async c=>{var b;let u;switch((b=c.headers.get("Content-Type"))==null?void 0:b.split(";")[0]){case"application/json":u=await c.json();break;default:u=await c.text().then(a=>Number.isNaN(+a)?a==="true"?!0:a==="false"?!1:a:+a)}return c.status>300?{data:u,error:new S.EdenFetchError(c.status,await u)}:{data:u,error:null}})}}),j=(n,e={})=>new Proxy({},{get(t,s){return w(n,s)}});exports.EdenWS=v;exports.edenTreaty=j;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const L=require("./utils-0d7d9b21.js"),N=(r,e,t)=>{if(r.endsWith("/")||(r+="/"),e==="index"&&(e=""),!t||!Object.keys(t).length)return`${r}${e}`;let n="";for(const[f,s]of Object.entries(t))n+=`${f}=${s}&`;return`${r}${e}?${n.slice(0,-1)}`},b=r=>typeof FileList>"u"?!1:r instanceof FileList||r instanceof File,O=r=>{for(let e in r){if(b(r[e]))return!0;if(Array.isArray(r[e])&&r[e].find(t=>b(t)))return!0}return!1},v=r=>new Promise(e=>{const t=new FileReader;t.onload=()=>{e(new Blob([t.result],{type:r.type}))},t.readAsArrayBuffer(r)});class E{constructor(e){this.ws=new WebSocket(e),this.url=e}send(e){return Array.isArray(e)?(e.forEach(t=>this.send(t)),this):(this.ws.send(typeof e=="object"?JSON.stringify(e):e.toString()),this)}on(e,t,n){return this.addEventListener(e,t,n)}off(e,t,n){return this.ws.removeEventListener(e,t,n),this}subscribe(e,t){return this.addEventListener("message",e,t)}addEventListener(e,t,n){return this.ws.addEventListener(e,f=>{if(e==="message"){let s=f.data.toString();const i=s.charCodeAt(0);if(i===47||i===123)try{s=JSON.parse(s)}catch{}else Number.isNaN(+s)?s==="true"?s=!0:s==="fase"&&(s=!1):s=+s;t({...f,data:s})}else t(f)},n),this}removeEventListener(e,t,n){return this.off(e,t,n),this}close(){return this.ws.close(),this}}const F=(r,e="",t)=>new Proxy(()=>{},{get(n,f,s){return F(r,`${e}/${f.toString()}`)},apply(n,f,[{$query:s,$fetch:i,$body:S,...w}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){const g=e.lastIndexOf("/"),p=e.slice(g+1),d=N(r,e.slice(0,g),s);return p==="subscribe"?new E(d.replace(/^([^]+):\/\//,d.startsWith("https://")?"wss://":"ws://")):(async()=>{let c=S??(Object.keys(w).length?w:void 0);const y=typeof c=="object",h=y&&O(c);if(h){const o=new FormData;for(const[a,l]of Object.entries(c))if(l instanceof File)o.append(a,await v(l));else if(l instanceof FileList)for(let u=0;u<l.length;u++)o.append(a,await v(l[u]));else o.append(a,l);c=o}else y&&(c=JSON.stringify(c));return fetch(d,{method:p,body:c,...i,headers:c?h?i==null?void 0:i.headers:{"content-type":y?"application/json":"text/plain",...i==null?void 0:i.headers}:i==null?void 0:i.headers}).then(async o=>{var l;let a;switch((l=o.headers.get("Content-Type"))==null?void 0:l.split(";")[0]){case"application/json":a=await o.json();break;default:a=await o.text().then(u=>Number.isNaN(+u)?u==="true"?!0:u==="false"?!1:u:+u)}return o.status>300?{data:a,error:new L.EdenFetchError(o.status,await a)}:{data:a,error:null}})})()}}),m=(r,e={})=>new Proxy({},{get(t,n){return F(r,n)}});exports.EdenWS=E;exports.edenTreaty=m;
package/dist/treaty.mjs CHANGED
@@ -1,13 +1,26 @@
1
- import { E as p } from "./utils-0d2b8b1a.mjs";
2
- const E = (n, e, t) => {
3
- if (n.endsWith("/") || (n += "/"), e === "index" && (e = ""), !t || !Object.keys(t).length)
4
- return `${n}${e}`;
5
- let s = "";
6
- for (const [i, r] of Object.entries(t))
7
- s += `${i}=${r}&`;
8
- return `${n}${e}?${s.slice(0, -1)}`;
9
- };
10
- class N {
1
+ import { E as m } from "./utils-0d2b8b1a.mjs";
2
+ const L = (r, e, t) => {
3
+ if (r.endsWith("/") || (r += "/"), e === "index" && (e = ""), !t || !Object.keys(t).length)
4
+ return `${r}${e}`;
5
+ let n = "";
6
+ for (const [f, s] of Object.entries(t))
7
+ n += `${f}=${s}&`;
8
+ return `${r}${e}?${n.slice(0, -1)}`;
9
+ }, b = (r) => typeof FileList > "u" ? !1 : r instanceof FileList || r instanceof File, N = (r) => {
10
+ for (let e in r) {
11
+ if (b(r[e]))
12
+ return !0;
13
+ if (Array.isArray(r[e]) && r[e].find((t) => b(t)))
14
+ return !0;
15
+ }
16
+ return !1;
17
+ }, v = (r) => new Promise((e) => {
18
+ const t = new FileReader();
19
+ t.onload = () => {
20
+ e(new Blob([t.result], { type: r.type }));
21
+ }, t.readAsArrayBuffer(r);
22
+ });
23
+ class x {
11
24
  constructor(e) {
12
25
  this.ws = new WebSocket(e), this.url = e;
13
26
  }
@@ -16,102 +29,118 @@ class N {
16
29
  typeof e == "object" ? JSON.stringify(e) : e.toString()
17
30
  ), this);
18
31
  }
19
- on(e, t, s) {
20
- return this.addEventListener(e, t, s);
32
+ on(e, t, n) {
33
+ return this.addEventListener(e, t, n);
21
34
  }
22
- off(e, t, s) {
23
- return this.ws.removeEventListener(e, t, s), this;
35
+ off(e, t, n) {
36
+ return this.ws.removeEventListener(e, t, n), this;
24
37
  }
25
38
  subscribe(e, t) {
26
39
  return this.addEventListener("message", e, t);
27
40
  }
28
- addEventListener(e, t, s) {
41
+ addEventListener(e, t, n) {
29
42
  return this.ws.addEventListener(
30
43
  e,
31
- (i) => {
44
+ (f) => {
32
45
  if (e === "message") {
33
- let r = i.data.toString();
34
- const o = r.charCodeAt(0);
35
- if (o === 47 || o === 123)
46
+ let s = f.data.toString();
47
+ const i = s.charCodeAt(0);
48
+ if (i === 47 || i === 123)
36
49
  try {
37
- r = JSON.parse(r);
50
+ s = JSON.parse(s);
38
51
  } catch {
39
52
  }
40
53
  else
41
- Number.isNaN(+r) ? r === "true" ? r = !0 : r === "fase" && (r = !1) : r = +r;
54
+ Number.isNaN(+s) ? s === "true" ? s = !0 : s === "fase" && (s = !1) : s = +s;
42
55
  t({
43
- ...i,
44
- data: r
56
+ ...f,
57
+ data: s
45
58
  });
46
59
  } else
47
- t(i);
60
+ t(f);
48
61
  },
49
- s
62
+ n
50
63
  ), this;
51
64
  }
52
- removeEventListener(e, t, s) {
53
- return this.off(e, t, s), this;
65
+ removeEventListener(e, t, n) {
66
+ return this.off(e, t, n), this;
54
67
  }
55
68
  close() {
56
69
  return this.ws.close(), this;
57
70
  }
58
71
  }
59
- const v = (n, e = "", t) => new Proxy(() => {
72
+ const E = (r, e = "", t) => new Proxy(() => {
60
73
  }, {
61
- get(s, i, r) {
62
- return v(n, `${e}/${i.toString()}`);
74
+ get(n, f, s) {
75
+ return E(r, `${e}/${f.toString()}`);
63
76
  },
64
- apply(s, i, [
65
- { $query: r, $fetch: o, $body: w, ...h } = {
77
+ apply(n, f, [
78
+ { $query: s, $fetch: i, $body: F, ...w } = {
66
79
  $fetch: void 0,
67
80
  $query: void 0,
68
81
  $body: void 0
69
82
  }
70
83
  ] = [{}]) {
71
- const d = e.lastIndexOf("/"), y = e.slice(d + 1), l = E(n, e.slice(0, d), r);
72
- if (y === "subscribe")
73
- return new N(
74
- l.replace(
75
- /^([^]+):\/\//,
76
- l.startsWith("https://") ? "wss://" : "ws://"
77
- )
78
- );
79
- const f = w ?? (Object.keys(h).length ? h : void 0), g = typeof f == "object";
80
- return fetch(l, {
81
- method: y,
82
- body: g ? JSON.stringify(f) : f,
83
- // ...config.fetch,
84
- ...o,
85
- headers: f ? {
86
- "content-type": g ? "application/json" : "text/plain",
87
- // ...config.fetch?.headers,
88
- ...o == null ? void 0 : o.headers
89
- } : void 0
90
- }).then(async (c) => {
91
- var b;
92
- let u;
93
- switch ((b = c.headers.get("Content-Type")) == null ? void 0 : b.split(";")[0]) {
94
- case "application/json":
95
- u = await c.json();
96
- break;
97
- default:
98
- u = await c.text().then((a) => Number.isNaN(+a) ? a === "true" ? !0 : a === "false" ? !1 : a : +a);
99
- }
100
- return c.status > 300 ? {
101
- data: u,
102
- error: new p(c.status, await u)
103
- } : { data: u, error: null };
104
- });
84
+ const p = e.lastIndexOf("/"), g = e.slice(p + 1), d = L(r, e.slice(0, p), s);
85
+ return g === "subscribe" ? new x(
86
+ d.replace(
87
+ /^([^]+):\/\//,
88
+ d.startsWith("https://") ? "wss://" : "ws://"
89
+ )
90
+ ) : (async () => {
91
+ let c = F ?? (Object.keys(w).length ? w : void 0);
92
+ const y = typeof c == "object", h = y && N(c);
93
+ if (h) {
94
+ const o = new FormData();
95
+ for (const [a, l] of Object.entries(c))
96
+ if (l instanceof File)
97
+ o.append(a, await v(l));
98
+ else if (l instanceof FileList)
99
+ for (let u = 0; u < l.length; u++)
100
+ o.append(
101
+ a,
102
+ await v(l[u])
103
+ );
104
+ else
105
+ o.append(a, l);
106
+ c = o;
107
+ } else
108
+ y && (c = JSON.stringify(c));
109
+ return fetch(d, {
110
+ method: g,
111
+ body: c,
112
+ // ...config.fetch,
113
+ ...i,
114
+ headers: c ? h ? i == null ? void 0 : i.headers : {
115
+ "content-type": y ? "application/json" : "text/plain",
116
+ ...i == null ? void 0 : i.headers
117
+ } : i == null ? void 0 : i.headers
118
+ }).then(async (o) => {
119
+ var l;
120
+ let a;
121
+ switch ((l = o.headers.get("Content-Type")) == null ? void 0 : l.split(";")[0]) {
122
+ case "application/json":
123
+ a = await o.json();
124
+ break;
125
+ default:
126
+ a = await o.text().then((u) => Number.isNaN(+u) ? u === "true" ? !0 : u === "false" ? !1 : u : +u);
127
+ }
128
+ return o.status > 300 ? {
129
+ data: a,
130
+ error: new m(o.status, await a)
131
+ } : { data: a, error: null };
132
+ });
133
+ })();
105
134
  }
106
- }), x = (n, e = {}) => new Proxy(
135
+ }), S = (r, e = {}) => new Proxy(
107
136
  {},
108
137
  {
109
- get(t, s) {
110
- return v(n, s);
138
+ get(t, n) {
139
+ return E(r, n);
111
140
  }
112
141
  }
113
142
  );
114
143
  export {
115
- N as EdenWS,
116
- x as edenTreaty
144
+ x as EdenWS,
145
+ S as edenTreaty
117
146
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elysiajs/eden",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Fully type-safe Elysia client",
5
5
  "author": {
6
6
  "name": "saltyAom",
@@ -63,9 +63,9 @@
63
63
  }
64
64
  },
65
65
  "devDependencies": {
66
- "@elysiajs/cors": "^0.1.0",
66
+ "@elysiajs/cors": "^0.3.0",
67
67
  "@sinclair/typebox": "^0.25.24",
68
- "@types/node": "^18.11.7",
68
+ "@types/node": "^18.15.5",
69
69
  "bun-types": "^0.5.7",
70
70
  "elysia": "^0.3.0",
71
71
  "eslint": "^8.26.0",
@@ -19,16 +19,22 @@ export const edenFetch =
19
19
  const contentType = options.headers?.['Content-Type']
20
20
 
21
21
  if (!contentType || contentType === 'application/json')
22
- body = JSON.stringify(body)
22
+ try {
23
+ body = JSON.stringify(body)
24
+ } catch (error) {
25
+ //
26
+ }
23
27
 
24
28
  // @ts-ignore
25
29
  return fetch(server + endpoint, {
26
30
  ...options,
27
- headers: {
28
- 'content-type': 'application/json',
29
- ...options.headers
30
- },
31
- body
31
+ headers: body
32
+ ? {
33
+ 'content-type': 'application/json',
34
+ ...options.headers
35
+ }
36
+ : options.headers,
37
+ body: body as any
32
38
  }).then(async (res) => {
33
39
  let data
34
40
 
@@ -38,13 +44,14 @@ export const edenFetch =
38
44
  break
39
45
 
40
46
  default:
41
- data = await res.text().then((data) => {
42
- if (!Number.isNaN(+data)) return +data
43
- if (data === 'true') return true
44
- if (data === 'false') return false
47
+ data = await res.text().then((d) => {
48
+ if (!Number.isNaN(+d)) return +d
49
+ if (d === 'true') return true
50
+ if (d === 'false') return false
45
51
 
46
- return data
52
+ return d
47
53
  })
54
+ break
48
55
  }
49
56
 
50
57
  if (res.status > 300)
@@ -7,6 +7,40 @@ import type { EdenTreaty } from './types'
7
7
 
8
8
  export type { EdenTreaty } from './types'
9
9
 
10
+ // @ts-ignore
11
+ const isFile = (v: any) => {
12
+ if (typeof FileList === 'undefined') return false
13
+
14
+ return v instanceof FileList || v instanceof File
15
+ }
16
+
17
+ // FormData is 1 level deep
18
+ const hasFile = (obj: Record<string, any>) => {
19
+ for (let key in obj) {
20
+ if (isFile(obj[key])) return true
21
+ else if (
22
+ Array.isArray(obj[key]) &&
23
+ (obj[key] as unknown[]).find((x) => isFile(x))
24
+ )
25
+ return true
26
+ }
27
+
28
+ return false
29
+ }
30
+
31
+ // @ts-ignore
32
+ const fileToBlob = (v: File) =>
33
+ new Promise<Blob>((resolve) => {
34
+ // @ts-ignore
35
+ const reader = new FileReader()
36
+
37
+ reader.onload = () => {
38
+ resolve(new Blob([reader.result!], { type: v.type }))
39
+ }
40
+
41
+ reader.readAsArrayBuffer(v)
42
+ })
43
+
10
44
  export class EdenWS<Schema extends TypedSchema<any> = TypedSchema> {
11
45
  ws: WebSocket
12
46
  url: string
@@ -77,15 +111,11 @@ export class EdenWS<Schema extends TypedSchema<any> = TypedSchema> {
77
111
  else if (data === 'true') data = true
78
112
  else if (data === 'fase') data = false
79
113
 
80
- // @ts-ignore
81
114
  listener({
82
115
  ...ws,
83
116
  data
84
- })
85
- } else {
86
- // @ts-ignore
87
- listener(ws)
88
- }
117
+ } as any)
118
+ } else listener(ws as any)
89
119
  },
90
120
  options
91
121
  )
@@ -142,50 +172,77 @@ const createProxy = (
142
172
  )
143
173
  )
144
174
 
145
- const body =
146
- $body ?? (Object.keys(bodyObj).length ? bodyObj : undefined)
147
- const isObject = typeof body === 'object'
148
-
149
- return fetch(url, {
150
- method,
151
- body: isObject ? JSON.stringify(body) : body,
152
- // ...config.fetch,
153
- ...$fetch,
154
- headers: body
155
- ? {
156
- 'content-type': isObject
157
- ? 'application/json'
158
- : 'text/plain',
159
- // ...config.fetch?.headers,
160
- ...$fetch?.['headers']
161
- }
162
- : undefined
163
- }).then(async (res) => {
164
- let data
165
-
166
- switch (res.headers.get('Content-Type')?.split(';')[0]) {
167
- case 'application/json':
168
- data = await res.json()
169
- break
170
-
171
- default:
172
- data = await res.text().then((data) => {
173
- if (!Number.isNaN(+data)) return +data
174
- if (data === 'true') return true
175
- if (data === 'false') return false
176
-
177
- return data
178
- })
179
- }
175
+ return (async () => {
176
+ let body =
177
+ $body ?? (Object.keys(bodyObj).length ? bodyObj : undefined)
178
+ const isObject = typeof body === 'object'
179
+ const isFormData = isObject && hasFile(body)
180
180
 
181
- if (res.status > 300)
182
- return {
183
- data,
184
- error: new EdenFetchError(res.status, await data)
181
+ if (isFormData) {
182
+ const newBody = new FormData()
183
+
184
+ // FormData is 1 level deep
185
+ for (const [key, field] of Object.entries(body)) {
186
+ // @ts-ignore
187
+ if (field instanceof File)
188
+ newBody.append(key, await fileToBlob(field as any))
189
+ // @ts-ignore
190
+ else if (field instanceof FileList) {
191
+ // @ts-ignore
192
+ for (let i = 0; i < field.length; i++) {
193
+ newBody.append(
194
+ key as any,
195
+ await fileToBlob((field as any)[i])
196
+ )
197
+ }
198
+ } else newBody.append(key, field as string)
185
199
  }
186
200
 
187
- return { data, error: null }
188
- })
201
+ body = newBody
202
+ } else if (isObject) body = JSON.stringify(body)
203
+
204
+ return fetch(url, {
205
+ method,
206
+ body,
207
+ // ...config.fetch,
208
+ ...$fetch,
209
+ headers: body
210
+ ? isFormData
211
+ ? $fetch?.['headers']
212
+ : {
213
+ 'content-type': isObject
214
+ ? 'application/json'
215
+ : 'text/plain',
216
+ ...$fetch?.['headers']
217
+ }
218
+ : $fetch?.['headers']
219
+ }).then(async (res) => {
220
+ let data
221
+
222
+ switch (res.headers.get('Content-Type')?.split(';')[0]) {
223
+ case 'application/json':
224
+ data = await res.json()
225
+ break
226
+
227
+ default:
228
+ data = await res.text().then((data) => {
229
+ if (!Number.isNaN(+data)) return +data
230
+ if (data === 'true') return true
231
+ if (data === 'false') return false
232
+
233
+ return data
234
+ })
235
+ }
236
+
237
+ if (res.status > 300)
238
+ return {
239
+ data,
240
+ error: new EdenFetchError(res.status, await data)
241
+ }
242
+
243
+ return { data, error: null }
244
+ })
245
+ })()
189
246
  }
190
247
  }) as unknown as Record<string, unknown>
191
248
 
@@ -4,6 +4,12 @@ import type { EdenWS } from './index'
4
4
  import type { IsNever, IsUnknown, MapError, UnionToIntersect } from '../types'
5
5
  import { EdenFetchError } from '../utils'
6
6
 
7
+ type Replace<RecordType, TargetType, GenericType> = {
8
+ [K in keyof RecordType]: RecordType[K] extends TargetType
9
+ ? GenericType
10
+ : RecordType[K]
11
+ }
12
+
7
13
  export namespace EdenTreaty {
8
14
  export type Create<App extends Elysia<any>> = App['meta'] extends Record<
9
15
  typeof SCHEMA,
@@ -66,7 +72,11 @@ export namespace EdenTreaty {
66
72
  }
67
73
  >
68
74
  : (
69
- params: Route['body'] & {
75
+ params: Replace<
76
+ Route['body'],
77
+ Blob | Blob[],
78
+ File | FileList
79
+ > & {
70
80
  $query?: Record<string, string>
71
81
  $fetch?: RequestInit
72
82
  }
@@ -137,7 +147,11 @@ export namespace EdenTreaty {
137
147
  }
138
148
  >
139
149
  : (
140
- params: Route['body'] & {
150
+ params: Replace<
151
+ Route['body'],
152
+ Blob | Blob[],
153
+ File | FileList
154
+ > & {
141
155
  $query?: Record<string, string>
142
156
  $fetch?: RequestInit
143
157
  }
@@ -188,8 +202,8 @@ export namespace EdenTreaty {
188
202
 
189
203
  type NestPath<T extends string, V> = T extends `${infer First}/${infer Rest}`
190
204
  ? First extends `:${infer Parameter}`
191
- ? Record<string | number | `:${Parameter}`, NestPath<Rest, V>>
205
+ ? Record<(string & {}) | number | `:${Parameter}`, NestPath<Rest, V>>
192
206
  : Record<First, NestPath<Rest, V>>
193
207
  : T extends `:${infer Parameter}`
194
- ? Record<string | number | T, V>
208
+ ? Record<(string & {}) | number | T, V>
195
209
  : Record<T, V>