@elysiajs/eden
Advanced tools
Comparing version 0.2.1 to 0.3.0-exp-230222.2125
/// <reference types="bun-types" /> | ||
import type { Elysia, TypedSchema } from 'elysia'; | ||
import type { Eden, EdenWSEvent } from './types'; | ||
import type { Eden, EdenConfig, EdenWSEvent } from './types'; | ||
export declare class EdenWS<Schema extends TypedSchema<any> = TypedSchema> { | ||
@@ -15,2 +15,2 @@ ws: WebSocket; | ||
} | ||
export declare const eden: <App extends Elysia<any>>(domain: string) => Eden<App>; | ||
export declare const eden: <App extends Elysia<any>>(domain: string, config?: EdenConfig) => Eden<App>; |
@@ -1,1 +0,1 @@ | ||
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});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}addEventListener(e,t,s){return this.ws.addEventListener(e,i=>{if(e==="message"){let r=i.data.toString();const l=r.charCodeAt(0);if(l===47||l===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 b=n=>n.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=(n,e,t)=>{if(n.endsWith("/")||(n+="/"),e=b(e.replace(/index/g,"")),!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)}`},w=(n,e="")=>new Proxy(()=>{},{get(t,s,i){return w(n,`${e}/${s.toString()}`)},apply(t,s,[{$query:i,$fetch:r,$body:l,...f}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){const h=e.lastIndexOf("/"),d=e.slice(h+1),u=p(n,e.slice(0,h),i);if(d==="subscribe")return new v(u.replace(/^([^]+):\/\//,u.startsWith("https://")?"wss://":"ws://"));const o=l??(Object.keys(f).length?f:void 0),g=typeof o=="object";return fetch(u,{method:d,body:g?JSON.stringify(o):o,headers:o?{"content-type":g?"application/json":"text/plain","content-length":o==null?void 0:o.length,...r==null?void 0:r.headers}:void 0,...r}).then(async c=>{var y;if(c.status>300)throw new Error(await c.text());if((y=c.headers.get("content-type"))!=null&&y.includes("application/json"))try{return await c.json()}catch{}let a=await c.text();return Number.isNaN(+a)?a==="true"?!0:a==="false"?!1:a:+a})}}),S=n=>new Proxy({},{get(e,t,s){return w(n,t)}});exports.EdenWS=v;exports.eden=S; | ||
"use strict";var O=Object.create;var E=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var z=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var J=(s,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of P(t))!F.call(s,r)&&r!==e&&E(s,r,{get:()=>t[r],enumerable:!(n=N(t,r))||n.enumerable});return s};var L=(s,t,e)=>(e=s!=null?O(z(s)):{},J(t||!s||!s.__esModule?E(e,"default",{value:s,enumerable:!0}):e,s));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class m extends Error{constructor(t,e){super(),this.status=t,this.value=e}}const A=s=>s.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`),W=(s,t,e)=>{if(s.endsWith("/")||(s+="/"),t=A(t.replace(/index/g,"")),!e||!Object.keys(e).length)return`${s}${t}`;let n="";for(const[r,i]of Object.entries(e))n+=`${r}=${i}&`;return`${s}${t}?${n.slice(0,-1)}`};class p{constructor(t,e){this.pendings=[],this.operation=null,this.isFetching=!1,this.url=t,this.config=e,this.sJson=import("superjson").then(n=>({serialize:n.serialize,deserialize:n.deserialize}))}setConfig(t){this.config=t}clone(t){return new p(this.url,t??this.config)}async run(t,e){var i;const n=+this.pendings.length;if(this.pendings.push(e!==void 0?{n:t,p:e}:{n:t}),this.isFetching)return(i=this.operation)==null?void 0:i.then(o=>o[n]);this.isFetching=!0,this.operation=new Promise(o=>{setTimeout(async()=>{var l;const c=[...this.pendings];this.pendings=[];const{serialize:g,deserialize:y}=await this.sJson,h=await fetch(`${this.url}${this.config.fn??"/~fn"}`,{method:"POST",...this.config.fetch,headers:{"content-type":"elysia/fn",...(l=this.config.fetch)==null?void 0:l.headers},body:JSON.stringify(g(c))});h.status===200?o(h.json().then(u=>y(u))):o(Array(c.length).fill(new Error(await h.text())))},33)});const r=await this.operation.then(o=>o[n]);return this.operation=null,this.isFetching=!1,r}}class ${constructor(t){this.ws=new WebSocket(t),this.url=t}send(t){return Array.isArray(t)?(t.forEach(e=>this.send(e)),this):(this.ws.send(typeof t=="object"?JSON.stringify(t):t.toString()),this)}on(t,e,n){return this.addEventListener(t,e,n)}off(t,e,n){return this.ws.removeEventListener(t,e,n),this}addEventListener(t,e,n){return this.ws.addEventListener(t,r=>{if(t==="message"){let i=r.data.toString();const o=i.charCodeAt(0);if(o===47||o===123)try{i=JSON.parse(i)}catch{}else Number.isNaN(+i)?i==="true"?i=!0:i==="fase"&&(i=!1):i=+i;e({...r,data:i})}else e(r)},n),this}removeEventListener(t,e,n){return this.off(t,e,n),this}close(){return this.ws.close(),this}}const w=(s,t,e)=>new Proxy((...n)=>{},{get(n,r,i){return w(s,[...t,r],e)},apply(n,r,i){const o=i[0];if(t.length===1){if(t[0]in Object.prototype||t[0]in Promise.prototype)return n(i);switch(t[0]){case"toJSON":return n(i);case"$set":return e.setConfig(o);case"$clone":return w(s,[],e.clone(o))}}return e.run(t,o).then(c=>{if(c instanceof Error)throw c;return c})}}),x=(s,t="",e)=>new Proxy(()=>{},{get(n,r,i){return x(s,`${t}/${r.toString()}`,e)},apply(n,r,[{$query:i,$fetch:o,$body:c,...g}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){var b;const y=t.lastIndexOf("/"),h=t.slice(y+1),l=W(s,t.slice(0,y),i);if(h==="subscribe")return new $(l.replace(/^([^]+):\/\//,l.startsWith("https://")?"wss://":"ws://"));const u=c??(Object.keys(g).length?g:void 0),v=typeof u=="object";return fetch(l,{method:h,body:v?JSON.stringify(u):u,...e.fetch,...o,headers:u?{"content-type":v?"application/json":"text/plain",...(b=e.fetch)==null?void 0:b.headers,...o==null?void 0:o.headers}:void 0}).then(async a=>{var S,j;if(a.status>300){let d;if((S=a.headers.get("content-type"))!=null&&S.includes("application/json"))try{d=await a.json()}catch{d=await a.text()}else d=await a.text();return new m(a.status,d)}if((j=a.headers.get("content-type"))!=null&&j.includes("application/json"))try{return await a.json()}catch{}let f=await a.text();return Number.isNaN(+f)?f==="true"?!0:f==="false"?!1:f:+f})}}),C=(s,t={})=>new Proxy({},{get(e,n){return n==="$fn"?w(s,[],new p(s,t)):x(s,n,t)}});exports.EdenWS=$;exports.eden=C; |
@@ -1,1 +0,1 @@ | ||
(function(o,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(o=typeof globalThis<"u"?globalThis:o||self,a(o["@elysia/eden"]={}))})(this,function(o){"use strict";class a{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}addEventListener(e,t,s){return this.ws.addEventListener(e,i=>{if(e==="message"){let n=i.data.toString();const l=n.charCodeAt(0);if(l===47||l===123)try{n=JSON.parse(n)}catch{}else Number.isNaN(+n)?n==="true"?n=!0:n==="fase"&&(n=!1):n=+n;t({...i,data:n})}else t(i)},s),this}removeEventListener(e,t,s){return this.off(e,t,s),this}close(){return this.ws.close(),this}}const b=r=>r.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),S=(r,e,t)=>{if(r.endsWith("/")||(r+="/"),e=b(e.replace(/index/g,"")),!t||!Object.keys(t).length)return`${r}${e}`;let s="";for(const[i,n]of Object.entries(t))s+=`${i}=${n}&`;return`${r}${e}?${s.slice(0,-1)}`},h=(r,e="")=>new Proxy(()=>{},{get(t,s,i){return h(r,`${e}/${s.toString()}`)},apply(t,s,[{$query:i,$fetch:n,$body:l,...y}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){const g=e.lastIndexOf("/"),p=e.slice(g+1),d=S(r,e.slice(0,g),i);if(p==="subscribe")return new a(d.replace(/^([^]+):\/\//,d.startsWith("https://")?"wss://":"ws://"));const c=l??(Object.keys(y).length?y:void 0),v=typeof c=="object";return fetch(d,{method:p,body:v?JSON.stringify(c):c,headers:c?{"content-type":v?"application/json":"text/plain","content-length":c==null?void 0:c.length,...n==null?void 0:n.headers}:void 0,...n}).then(async u=>{var w;if(u.status>300)throw new Error(await u.text());if((w=u.headers.get("content-type"))!=null&&w.includes("application/json"))try{return await u.json()}catch{}let f=await u.text();return Number.isNaN(+f)?f==="true"?!0:f==="false"?!1:f:+f})}}),j=r=>new Proxy({},{get(e,t,s){return h(r,t)}});o.EdenWS=a,o.eden=j,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}); | ||
(function(h,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(h=typeof globalThis<"u"?globalThis:h||self,d(h["@elysia/eden"]={}))})(this,function(h){"use strict";class d extends Error{constructor(t,e){super(),this.status=t,this.value=e}}const N=i=>i.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`),P=(i,t,e)=>{if(i.endsWith("/")||(i+="/"),t=N(t.replace(/index/g,"")),!e||!Object.keys(e).length)return`${i}${t}`;let s="";for(const[o,n]of Object.entries(e))s+=`${o}=${n}&`;return`${i}${t}?${s.slice(0,-1)}`};class v{constructor(t,e){this.pendings=[],this.operation=null,this.isFetching=!1,this.url=t,this.config=e,this.sJson=import("superjson").then(s=>({serialize:s.serialize,deserialize:s.deserialize}))}setConfig(t){this.config=t}clone(t){return new v(this.url,t??this.config)}async run(t,e){var n;const s=+this.pendings.length;if(this.pendings.push(e!==void 0?{n:t,p:e}:{n:t}),this.isFetching)return(n=this.operation)==null?void 0:n.then(r=>r[s]);this.isFetching=!0,this.operation=new Promise(r=>{setTimeout(async()=>{var u;const a=[...this.pendings];this.pendings=[];const{serialize:p,deserialize:w}=await this.sJson,l=await fetch(`${this.url}${this.config.fn??"/~fn"}`,{method:"POST",...this.config.fetch,headers:{"content-type":"elysia/fn",...(u=this.config.fetch)==null?void 0:u.headers},body:JSON.stringify(p(a))});l.status===200?r(l.json().then(f=>w(f))):r(Array(a.length).fill(new Error(await l.text())))},33)});const o=await this.operation.then(r=>r[s]);return this.operation=null,this.isFetching=!1,o}}class j{constructor(t){this.ws=new WebSocket(t),this.url=t}send(t){return Array.isArray(t)?(t.forEach(e=>this.send(e)),this):(this.ws.send(typeof t=="object"?JSON.stringify(t):t.toString()),this)}on(t,e,s){return this.addEventListener(t,e,s)}off(t,e,s){return this.ws.removeEventListener(t,e,s),this}addEventListener(t,e,s){return this.ws.addEventListener(t,o=>{if(t==="message"){let n=o.data.toString();const r=n.charCodeAt(0);if(r===47||r===123)try{n=JSON.parse(n)}catch{}else Number.isNaN(+n)?n==="true"?n=!0:n==="fase"&&(n=!1):n=+n;e({...o,data:n})}else e(o)},s),this}removeEventListener(t,e,s){return this.off(t,e,s),this}close(){return this.ws.close(),this}}const b=(i,t,e)=>new Proxy((...s)=>{},{get(s,o,n){return b(i,[...t,o],e)},apply(s,o,n){const r=n[0];if(t.length===1){if(t[0]in Object.prototype||t[0]in Promise.prototype)return s(n);switch(t[0]){case"toJSON":return s(n);case"$set":return e.setConfig(r);case"$clone":return b(i,[],e.clone(r))}}return e.run(t,r).then(a=>{if(a instanceof Error)throw a;return a})}}),S=(i,t="",e)=>new Proxy(()=>{},{get(s,o,n){return S(i,`${t}/${o.toString()}`,e)},apply(s,o,[{$query:n,$fetch:r,$body:a,...p}={$fetch:void 0,$query:void 0,$body:void 0}]=[{}]){var E;const w=t.lastIndexOf("/"),l=t.slice(w+1),u=P(i,t.slice(0,w),n);if(l==="subscribe")return new j(u.replace(/^([^]+):\/\//,u.startsWith("https://")?"wss://":"ws://"));const f=a??(Object.keys(p).length?p:void 0),x=typeof f=="object";return fetch(u,{method:l,body:x?JSON.stringify(f):f,...e.fetch,...r,headers:f?{"content-type":x?"application/json":"text/plain",...(E=e.fetch)==null?void 0:E.headers,...r==null?void 0:r.headers}:void 0}).then(async c=>{var $,O;if(c.status>300){let y;if(($=c.headers.get("content-type"))!=null&&$.includes("application/json"))try{y=await c.json()}catch{y=await c.text()}else y=await c.text();return new d(c.status,y)}if((O=c.headers.get("content-type"))!=null&&O.includes("application/json"))try{return await c.json()}catch{}let g=await c.text();return Number.isNaN(+g)?g==="true"?!0:g==="false"?!1:g:+g})}}),m=(i,t={})=>new Proxy({},{get(e,s){return s==="$fn"?b(i,[],new v(i,t)):S(i,s,t)}});h.EdenWS=j,h.eden=m,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}); |
/// <reference types="bun-types" /> | ||
import type { Elysia, SCHEMA, TypedRoute, IsPathParameter } from 'elysia'; | ||
import type { Elysia, SCHEMA, TypedRoute, IsPathParameter, EXPOSED } from 'elysia'; | ||
import type { EdenWS } from '.'; | ||
import { type EdenFetchError } from './utils'; | ||
declare type IsAny<T> = unknown extends T ? [T] extends [object] ? true : false : false; | ||
declare type Promisify<T extends (...args: any[]) => any> = T extends (...args: infer Args) => infer Return ? Return extends Promise<any> ? T : (...args: Args) => Promise<Return> : never; | ||
declare type Asynctify<T> = T extends infer Fn extends (...args: any) => any ? Promisify<Fn> : T extends Record<string, any> ? { | ||
[K in keyof T]: EdenFn<T[K]>; | ||
} : never; | ||
declare type EdenFn<T> = T extends { | ||
[EXPOSED]: true; | ||
value: infer Value; | ||
} ? Asynctify<Value> : Asynctify<T>; | ||
declare type CreateEdenFn<Exposed extends Record<string, any>> = EdenFn<Exposed> & { | ||
$set(config: EdenConfig): void; | ||
$clone(config?: EdenConfig): CreateEdenFn<Exposed>; | ||
}; | ||
export declare type Eden<App extends Elysia<any>> = App['store'] extends { | ||
[key in typeof SCHEMA]: any; | ||
} ? IsAny<Elysia> extends true ? 'Please installed Elysia before using Eden' : UnionToIntersection<CreateEden<App['store'][typeof SCHEMA]>> : never; | ||
} ? IsAny<Elysia> extends true ? 'Please install Elysia before using Eden' : UnionToIntersection<CreateEden<App['store'][typeof SCHEMA]>> & { | ||
$fn: CreateEdenFn<App['store'][typeof EXPOSED]>; | ||
} : never; | ||
export interface EdenCall { | ||
@@ -14,2 +29,5 @@ [x: string]: any; | ||
export declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
declare type Prettify<T> = { | ||
[K in keyof T]: T[K]; | ||
} & {}; | ||
declare type TypedRouteToParams<Route extends TypedRoute> = (Route['body'] extends NonNullable<Route['body']> ? Route['body'] extends Record<any, any> ? Route['body'] : { | ||
@@ -25,27 +43,27 @@ $body: Route['body']; | ||
[key in Path extends '' ? 'index' : Path extends `:${infer params}` ? string : Path | CamelCase<Path>]: Full extends keyof Server ? { | ||
[key in keyof Server[Full] extends string ? Lowercase<keyof Server[Full]> : keyof Server[Full]]: keyof TypedRouteToParams<Server[Full][key extends string ? Uppercase<key> : key]> extends never ? key extends 'subscribe' ? unknown extends NonNullable<Server[Full][key]['query']> ? (params?: { | ||
[key in keyof Server[Full] extends string ? Lowercase<keyof Server[Full]> : keyof Server[Full]]: [ | ||
Server[Full][key extends string ? Uppercase<key> : key] | ||
] extends [infer Route extends TypedRoute] ? undefined extends Route['body'] ? (params?: { | ||
$query?: EdenCall['$query']; | ||
}) => EdenWS<Server[Full][key]> : Server[Full][key]['query'] extends NonNullable<Server[Full][key]['query']> ? (params: { | ||
$query: Server[Full][key]['query']; | ||
}) => EdenWS<Server[Full][key]> : (params?: { | ||
$fetch?: EdenCall['$fetch']; | ||
}) => Promise<Route['response'] extends { | ||
200: infer ReturnedType; | ||
} ? ReturnedType | MapError<Route['response']> : unknown> : (params: Prettify<TypedRouteToParams<Route> & { | ||
$query?: EdenCall['$query']; | ||
}) => EdenWS<Server[Full][key]> : (params?: { | ||
$query?: EdenCall['$query']; | ||
$fetch?: EdenCall['$fetch']; | ||
}) => Promise<key extends string ? Server[Full][Uppercase<key>]['response'] extends { | ||
}>) => Promise<Route['response'] extends { | ||
200: infer ReturnedType; | ||
} ? ReturnedType : unknown : Server[Full][key]['response'] extends { | ||
200: infer ReturnedType; | ||
} ? ReturnedType : unknown> : key extends 'subscribe' ? unknown extends NonNullable<Server[Full][key]['query']> ? (params?: { | ||
} ? ReturnedType | MapError<Route['response']> : unknown> : key extends 'subscribe' ? [ | ||
Server[Full][key], | ||
Server[Full][key]['query'] | ||
] extends [ | ||
infer Route extends TypedRoute, | ||
infer Query extends TypedRoute['query'] | ||
] ? unknown extends NonNullable<Query> ? (params?: { | ||
$query?: EdenCall['$query']; | ||
}) => EdenWS<Server[Full][key]> : Server[Full][key]['query'] extends NonNullable<Server[Full][key]['query']> ? (params: { | ||
$query: Server[Full][key]['query']; | ||
}) => EdenWS<Server[Full][key]> : (params?: { | ||
}) => EdenWS<Route> : Query extends NonNullable<Query> ? (params: { | ||
$query: Query; | ||
}) => EdenWS<Route> : (params?: { | ||
$query?: EdenCall['$query']; | ||
}) => EdenWS<Server[Full][key]> : (params: TypedRouteToParams<Server[Full][key extends string ? Uppercase<key> : key]> & { | ||
$query?: EdenCall['$query']; | ||
$fetch?: EdenCall['$fetch']; | ||
}) => Promise<Server[Full][key extends string ? Uppercase<key> : key]['response'] extends { | ||
200: infer ReturnedType; | ||
} ? ReturnedType : unknown>; | ||
}) => EdenWS<Route> : never : never; | ||
} : never; | ||
@@ -59,2 +77,16 @@ } & (Path extends `:${infer params}` ? Record<`$${params}`, `Expected path parameters ':${params}', replace this with any string`> : {}); | ||
export declare type EdenWSEvent<K extends keyof WebSocketEventMap, Data = unknown> = K extends 'message' ? EdenWSOnMessage<Data> : WebSocketEventMap[K]; | ||
export interface EdenConfig { | ||
fn?: string; | ||
fetch?: Omit<RequestInit, 'body'>; | ||
} | ||
declare type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc['length']]>; | ||
declare type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>; | ||
declare type ErrorRange = Range<300, 599>; | ||
declare type MapError<T extends Record<number, unknown>> = [ | ||
{ | ||
[K in keyof T]-?: K extends ErrorRange ? K : never; | ||
}[keyof T] | ||
] extends [infer A extends number] ? { | ||
[K in A]: EdenFetchError<K, T[K]>; | ||
}[A] : false; | ||
export {}; |
{ | ||
"name": "@elysiajs/eden", | ||
"version": "0.2.1", | ||
"version": "0.3.0-exp-230222.2125", | ||
"description": "Fully type-safe Elysia client", | ||
@@ -12,6 +12,8 @@ "author": { | ||
"exports": { | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.mjs", | ||
"node": "./dist/index.js", | ||
"default": "./dist/index.js" | ||
".": { | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.mjs", | ||
"node": "./dist/index.js", | ||
"default": "./dist/index.js" | ||
} | ||
}, | ||
@@ -38,3 +40,3 @@ "types": "./src/index.ts", | ||
"peerDependencies": { | ||
"elysia": ">= 0.2.0" | ||
"elysia": ">= 0.3.0-beta.0" | ||
}, | ||
@@ -46,5 +48,5 @@ "devDependencies": { | ||
"@types/node": "^18.11.7", | ||
"bun-types": "^0.3.0", | ||
"bun-types": "^0.5.0", | ||
"eslint": "^8.26.0", | ||
"elysia": "^0.2.0", | ||
"elysia": "../elysia", | ||
"rimraf": "^3.0.2", | ||
@@ -54,3 +56,6 @@ "typescript": "^4.8.4", | ||
"vite-plugin-dts": "^1.7.1" | ||
}, | ||
"dependencies": { | ||
"superjson": "^1.12.2" | ||
} | ||
} |
@@ -7,5 +7,7 @@ import type { Elysia, TypedSchema, HTTPMethod } from 'elysia' | ||
EdenCall, | ||
EdenConfig, | ||
EdenWSEvent, | ||
UnionToIntersection | ||
} from './types' | ||
import { composePath, EdenFetchError, Signal } from './utils' | ||
@@ -106,28 +108,50 @@ export class EdenWS<Schema extends TypedSchema<any> = TypedSchema> { | ||
const camelToDash = (str: string) => | ||
str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`) | ||
const composePath = ( | ||
const createFn = ( | ||
domain: string, | ||
path: string, | ||
query: EdenCall['$query'] | undefined | ||
) => { | ||
if (!domain.endsWith('/')) domain += '/' | ||
path = camelToDash(path.replace(/index/g, '')) | ||
procedure: string[], | ||
signal: Signal | ||
): Record<string, unknown> => | ||
// @ts-ignore | ||
new Proxy((...v: any[]) => {}, { | ||
get(target, key, value) { | ||
return createFn(domain, [...procedure, key as string], signal) | ||
}, | ||
apply(target, _, params) { | ||
const param = params[0] | ||
if (!query || !Object.keys(query).length) return `${domain}${path}` | ||
if (procedure.length === 1) { | ||
if ( | ||
procedure[0] in Object.prototype || | ||
procedure[0] in Promise.prototype | ||
) | ||
return target(params) | ||
let q = '' | ||
for (const [key, value] of Object.entries(query)) q += `${key}=${value}&` | ||
switch (procedure[0]) { | ||
case 'toJSON': | ||
return target(params) | ||
return `${domain}${path}?${q.slice(0, -1)}` | ||
} | ||
case '$set': | ||
return signal.setConfig(param) | ||
case '$clone': | ||
return createFn(domain, [], signal.clone(param)) | ||
} | ||
} | ||
return signal.run(procedure, param).then((result) => { | ||
if (result instanceof Error) throw result | ||
return result | ||
}) | ||
} | ||
}) | ||
const createProxy = ( | ||
domain: string, | ||
path: string = '' | ||
path: string = '', | ||
config: EdenConfig | ||
): Record<string, unknown> => | ||
new Proxy(() => {}, { | ||
get(target, key, value) { | ||
return createProxy(domain, `${path}/${key.toString()}`) | ||
return createProxy(domain, `${path}/${key.toString()}`, config) | ||
}, | ||
@@ -164,2 +188,4 @@ apply( | ||
body: isObject ? JSON.stringify(body) : body, | ||
...config.fetch, | ||
...$fetch, | ||
headers: body | ||
@@ -170,10 +196,25 @@ ? { | ||
: 'text/plain', | ||
'content-length': body?.length, | ||
...config.fetch?.headers, | ||
...$fetch?.['headers'] | ||
} | ||
: undefined, | ||
...$fetch | ||
: undefined | ||
}).then(async (res) => { | ||
if (res.status > 300) throw new Error(await res.text()) | ||
if (res.status > 300) { | ||
let data | ||
if ( | ||
res.headers | ||
.get('content-type') | ||
?.includes('application/json') | ||
) | ||
try { | ||
data = await res.json() | ||
} catch (_) { | ||
data = await res.text() | ||
} | ||
else data = await res.text() | ||
return new EdenFetchError(res.status, data) | ||
} | ||
if ( | ||
@@ -202,10 +243,16 @@ res.headers | ||
export const eden = <App extends Elysia<any>>(domain: string): Eden<App> => | ||
export const eden = <App extends Elysia<any>>( | ||
domain: string, | ||
config: EdenConfig = {} | ||
): Eden<App> => | ||
new Proxy( | ||
{}, | ||
{ | ||
get(target, key, value) { | ||
return createProxy(domain, key as string) | ||
get(target, key) { | ||
if (key === '$fn') | ||
return createFn(domain, [], new Signal(domain, config)) | ||
return createProxy(domain, key as string, config) | ||
} | ||
} | ||
) as any |
183
src/types.ts
@@ -1,5 +0,12 @@ | ||
import type { Elysia, SCHEMA, TypedRoute, IsPathParameter } from 'elysia' | ||
import type { | ||
Elysia, | ||
SCHEMA, | ||
TypedRoute, | ||
IsPathParameter, | ||
EXPOSED | ||
} from 'elysia' | ||
import type { TObject } from '@sinclair/typebox' | ||
import type { EdenWS } from '.' | ||
import { type EdenFetchError, type Signal } from './utils' | ||
@@ -12,2 +19,30 @@ type IsAny<T> = unknown extends T | ||
type Promisify<T extends (...args: any[]) => any> = T extends ( | ||
...args: infer Args | ||
) => infer Return | ||
? Return extends Promise<any> | ||
? T | ||
: (...args: Args) => Promise<Return> | ||
: never | ||
type Asynctify<T> = T extends infer Fn extends (...args: any) => any | ||
? Promisify<Fn> | ||
: T extends Record<string, any> | ||
? { | ||
[K in keyof T]: EdenFn<T[K]> | ||
} | ||
: never | ||
type EdenFn<T> = T extends { | ||
[EXPOSED]: true | ||
value: infer Value | ||
} | ||
? Asynctify<Value> | ||
: Asynctify<T> | ||
type CreateEdenFn<Exposed extends Record<string, any>> = EdenFn<Exposed> & { | ||
$set(config: EdenConfig): void | ||
$clone(config?: EdenConfig): CreateEdenFn<Exposed> | ||
} | ||
export type Eden<App extends Elysia<any>> = App['store'] extends { | ||
@@ -17,4 +52,6 @@ [key in typeof SCHEMA]: any | ||
? IsAny<Elysia> extends true | ||
? 'Please installed Elysia before using Eden' | ||
: UnionToIntersection<CreateEden<App['store'][typeof SCHEMA]>> | ||
? 'Please install Elysia before using Eden' | ||
: UnionToIntersection<CreateEden<App['store'][typeof SCHEMA]>> & { | ||
$fn: CreateEdenFn<App['store'][typeof EXPOSED]> | ||
} | ||
: never | ||
@@ -34,2 +71,7 @@ | ||
// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20 | ||
type Prettify<T> = { | ||
[K in keyof T]: T[K] | ||
} & {} | ||
type TypedRouteToParams<Route extends TypedRoute> = | ||
@@ -81,71 +123,54 @@ (Route['body'] extends NonNullable<Route['body']> | ||
? Lowercase<keyof Server[Full]> | ||
: keyof Server[Full]]: keyof TypedRouteToParams< | ||
: keyof Server[Full]]: [ | ||
Server[Full][key extends string ? Uppercase<key> : key] | ||
> extends never | ||
? key extends 'subscribe' | ||
? unknown extends NonNullable< | ||
Server[Full][key]['query'] | ||
> | ||
? (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: Server[Full][key]['query'] extends NonNullable< | ||
Server[Full][key]['query'] | ||
> | ||
? (params: { | ||
$query: Server[Full][key]['query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: (params?: { | ||
] extends [infer Route extends TypedRoute] | ||
? undefined extends Route['body'] | ||
? (params?: { | ||
$query?: EdenCall['$query'] | ||
$fetch?: EdenCall['$fetch'] | ||
}) => Promise< | ||
key extends string | ||
? Server[Full][Uppercase<key>]['response'] extends { | ||
200: infer ReturnedType | ||
} | ||
? ReturnedType | ||
: unknown | ||
: Server[Full][key]['response'] extends { | ||
200: infer ReturnedType | ||
} | ||
? ReturnedType | ||
Route['response'] extends { | ||
200: infer ReturnedType | ||
} | ||
? | ||
| ReturnedType | ||
| MapError<Route['response']> | ||
: unknown | ||
> | ||
: ( | ||
params: Prettify< | ||
TypedRouteToParams<Route> & { | ||
$query?: EdenCall['$query'] | ||
$fetch?: EdenCall['$fetch'] | ||
} | ||
> | ||
) => Promise< | ||
Route['response'] extends { | ||
200: infer ReturnedType | ||
} | ||
? | ||
| ReturnedType | ||
| MapError<Route['response']> | ||
: unknown | ||
> | ||
: key extends 'subscribe' | ||
? unknown extends NonNullable< | ||
? // Since subscribe key is only a lower letter | ||
[ | ||
Server[Full][key], | ||
Server[Full][key]['query'] | ||
> | ||
? (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: Server[Full][key]['query'] extends NonNullable< | ||
Server[Full][key]['query'] | ||
> | ||
? (params: { | ||
$query: Server[Full][key]['query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Server[Full][key]> | ||
: ( | ||
params: TypedRouteToParams< | ||
Server[Full][key extends string | ||
? Uppercase<key> | ||
: key] | ||
> & { | ||
$query?: EdenCall['$query'] | ||
$fetch?: EdenCall['$fetch'] | ||
} | ||
) => Promise< | ||
Server[Full][key extends string | ||
? Uppercase<key> | ||
: key]['response'] extends { | ||
200: infer ReturnedType | ||
} | ||
? ReturnedType | ||
: unknown | ||
> | ||
] extends [ | ||
infer Route extends TypedRoute, | ||
infer Query extends TypedRoute['query'] | ||
] | ||
? unknown extends NonNullable<Query> | ||
? (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Route> | ||
: Query extends NonNullable<Query> | ||
? (params: { $query: Query }) => EdenWS<Route> | ||
: (params?: { | ||
$query?: EdenCall['$query'] | ||
}) => EdenWS<Route> | ||
: never | ||
: never | ||
} | ||
@@ -175,1 +200,31 @@ : never | ||
> = K extends 'message' ? EdenWSOnMessage<Data> : WebSocketEventMap[K] | ||
export interface EdenConfig { | ||
fn?: string | ||
fetch?: Omit<RequestInit, 'body'> | ||
} | ||
type Enumerate< | ||
N extends number, | ||
Acc extends number[] = [] | ||
> = Acc['length'] extends N | ||
? Acc[number] | ||
: Enumerate<N, [...Acc, Acc['length']]> | ||
// https://stackoverflow.com/a/39495173 | ||
type Range<F extends number, T extends number> = Exclude< | ||
Enumerate<T>, | ||
Enumerate<F> | ||
> | ||
type ErrorRange = Range<300, 599> | ||
type MapError<T extends Record<number, unknown>> = [ | ||
{ | ||
[K in keyof T]-?: K extends ErrorRange ? K : never | ||
}[keyof T] | ||
] extends [infer A extends number] | ||
? { | ||
[K in A]: EdenFetchError<K, T[K]> | ||
}[A] | ||
: false |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42184
12
871
2
6
+ Addedsuperjson@^1.12.2
+ Addedcopy-anything@3.0.5(transitive)
+ Addedis-what@4.1.16(transitive)
+ Addedsuperjson@1.13.3(transitive)