@sx3/ultra 0.2.2 → 0.3.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.
package/dist/auth.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { s as Promisable } from "./types-DDhVsVEu.mjs";
2
- import { n as DeriveRecord, t as BaseContext } from "./context-BdPiiQY2.mjs";
3
- import "./http-DW9-I0jB.mjs";
4
- import { t as Middleware } from "./middleware-BXszEB7Z.mjs";
5
- import { ProceduresMap, Ultra } from "./ultra.mjs";
1
+ import { s as Promisable } from "./types-CKfKFLqV.mjs";
2
+ import { n as BaseContext, r as DeriveRecord } from "./context-DcgEPuHM.mjs";
3
+ import "./http-D4yDA06a.mjs";
4
+ import { t as Middleware } from "./middleware-Dj4LOBOr.mjs";
5
+ import { Ultra } from "./ultra.mjs";
6
6
  import { SessionContext } from "./session.mjs";
7
7
 
8
8
  //#region src/auth.d.ts
@@ -22,7 +22,7 @@ interface AuthContext<User> extends BaseContext {
22
22
  auth: Auth<User>;
23
23
  }
24
24
  declare function defineConfig<User, P extends Record<string, AuthProviderFactory<User>> = Record<string, AuthProviderFactory<User>>>(config: AuthConfig<P>): AuthConfig<P>;
25
- declare function createAuthModule<User, P extends Record<string, AuthProviderFactory<User>> = Record<string, AuthProviderFactory<User>>>(config: AuthConfig<P>): Ultra<ProceduresMap, DeriveRecord, {
25
+ declare function createAuthModule<User, P extends Record<string, AuthProviderFactory<User>> = Record<string, AuthProviderFactory<User>>>(config: AuthConfig<P>): Ultra<{}, DeriveRecord, {
26
26
  server: Bun.Server<DeriveRecord>;
27
27
  auth: Auth<User, P>;
28
28
  }>;
package/dist/client.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { l as Simplify } from "./types-DDhVsVEu.mjs";
2
- import "./context-BdPiiQY2.mjs";
3
- import "./http-DW9-I0jB.mjs";
4
- import { i as GetOutput, o as Procedure, r as GetInput } from "./middleware-BXszEB7Z.mjs";
1
+ import { c as Simplify } from "./types-CKfKFLqV.mjs";
2
+ import "./context-DcgEPuHM.mjs";
3
+ import "./http-D4yDA06a.mjs";
4
+ import { i as GetOutput, o as Procedure, r as GetInput } from "./middleware-Dj4LOBOr.mjs";
5
5
  import { ProceduresMap, Ultra } from "./ultra.mjs";
6
6
 
7
7
  //#region src/client.d.ts
@@ -30,10 +30,6 @@ interface WebSocketClientOptions {
30
30
  batchDelay?: number;
31
31
  /** @default 1000 characters */
32
32
  compression?: number | false;
33
- /** @default 3 */
34
- retryCount?: number;
35
- /** @default 1000ms */
36
- retryDelay?: number;
37
33
  /** Call before send, you can modify data */
38
34
  onBeforeSend?: (data: SocketMessage) => SocketMessage | void;
39
35
  }
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- import{compress as e}from"./compression.mjs";function t(e,n=[]){return new Proxy(()=>{},{get(r,i){if(typeof i==`string`)return t(e,[...n,i])},apply(t,r,i){if(!n.length)throw Error(`Cannot call client root; select a procedure first`);let a=n.join(`/`),o=i[0],s=i[1];return e(a,o,s)}})}function n(...e){let t=new Headers;for(let n of e)n&&new Headers(n).forEach((e,n)=>t.set(n,e));return t}function r(e){return t(async(t,r,i)=>{let a={...e,...i},o=a?.timeout||1e4,s=new AbortController,c=a?.method||`POST`,l=`${a.baseUrl}/${t}`,u=n(e?.headers,a?.headers,i?.headers),d=null,f=setTimeout(()=>s.abort(`Timeout: ${o}`),o);switch(!0){case c===`GET`:{if(d=null,!r)break;if(typeof r!=`object`)throw Error(`GET requests params to be an object for query string generation`);let e=Object.entries(r).filter(([,e])=>e!=null).map(([e,t])=>[e,String(t)]),t=new URLSearchParams(e).toString();t&&(l+=`?${t}`);break}case r instanceof FormData:d=r;break;case typeof r==`string`:u.set(`Content-Type`,`text/plain`),d=r;break;default:u.set(`Content-Type`,`application/json`),d=JSON.stringify(r)}try{let e=await fetch(l,{method:c,...d&&{body:d},...a,signal:s.signal,headers:u});if(!e.ok)throw Error(`${e.statusText} ${e.status}`);let t=e.headers.get(`Content-Type`)||``;switch(!0){case e.status===204:return null;case t.startsWith(`application/json`):return await e.json();case t.startsWith(`text/`):return await e.text();default:return await e.blob()}}catch(e){throw e.name===`AbortError`?Error(`Request aborted: ${e.message}`):e}finally{clearTimeout(f)}})}function i(n){let{retryCount:r=3,retryDelay:i=1e3,batchSize:a=99,batchDelay:o=0,onBeforeSend:s,compression:c}=n,l=()=>Math.random().toString(36),u=[],d=null,f=(t=0)=>{if(d!==null&&(clearTimeout(d),d=null),!u.length)return;let a=n.socket();if(!a||a.readyState!==WebSocket.OPEN)return t>=r?u.forEach(e=>{clearTimeout(e.timeout),e.reject(`WebSocket is not open`)}):setTimeout(()=>f(t+1),i);let o=e=>{try{let t=JSON.parse(e.data),n=u.find(e=>e.id===t.id);if(!n)return;clearTimeout(n.timeout),`error`in t?n.reject(t.error):n.resolve(t.result),u.length||a.removeEventListener(`message`,o)}catch(e){console.error(`Client failed parse server message`,e)}};a.addEventListener(`message`,o),a.addEventListener(`close`,()=>{a.removeEventListener(`message`,o),setTimeout(f,i)});let l=[];for(let e of u)e.pending||(e.pending=!0,l.push({id:e.id,method:e.method,params:e.params}));let p=JSON.stringify(l);c&&p.length>=c?e(new TextEncoder().encode(p)).then(e=>a.send(s?.(e)??e)):a.send(s?.(p)??p)},p=(e,t)=>(...n)=>{let r=u.findIndex(t=>t.id===e);return r!==-1&&(clearTimeout(u[r].timeout),u.splice(r,1)),t(...n)};return t((e,t,r)=>{let i={timeout:1e4,...n,...r},{promise:s,resolve:c,reject:m}=Promise.withResolvers(),h=l();return u.push({id:h,method:e,params:t,options:i,resolve:p(h,c),reject:p(h,m),timeout:setTimeout(p(h,m),i.timeout),pending:!1}),u.length>=a?f():d===null&&(d=setTimeout(f,o)),s})}function a(e){return t((t,n,r)=>{let i=e.pick(t,n,r),a=t.split(`/`).filter(Boolean),o=i;for(let e of a)o[e]&&(o=o[e]);return o(n,r)})}export{r as createHTTPClient,a as createSuperClient,i as createWebSocketClient};
1
+ import{n as e}from"./rpc-XjW9_Smw.mjs";import{compress as t}from"./compression.mjs";function n(e,t=[]){return new Proxy(()=>{},{get(r,i){if(typeof i==`string`)return n(e,[...t,i])},apply(n,r,i){if(!t.length)throw Error(`Cannot call client root; select a procedure first`);let a=t.join(`/`),o=i[0],s=i[1];return e(a,o,s)}})}function r(...e){let t=new Headers;for(let n of e)n&&new Headers(n).forEach((e,n)=>t.set(n,e));return t}function i(e){return n(async(t,n,i)=>{let a={...e,...i},o=a?.timeout||1e4,s=a?.method||`POST`,c=`${a.baseUrl}/${t}`,l=r(e?.headers,a?.headers,i?.headers),u=null;switch(!0){case s===`GET`:{if(u=null,!n)break;if(typeof n!=`object`)throw Error(`GET requests params to be an object for query string generation`);let e=Object.entries(n).filter(([,e])=>e!=null).map(([e,t])=>[e,String(t)]),t=new URLSearchParams(e).toString();t&&(c+=`?${t}`);break}case n instanceof FormData:u=n;break;case typeof n==`string`:l.set(`Content-Type`,`text/plain`),u=n;break;default:l.set(`Content-Type`,`application/json`),u=JSON.stringify(n)}try{let e=await fetch(c,{method:s,...u&&{body:u},...a,signal:AbortSignal.timeout(o),headers:l});if(!e.ok)throw Error(`${e.statusText} ${e.status}`);let t=e.headers.get(`Content-Type`)||``;switch(!0){case e.status===204:return null;case t.startsWith(`application/json`):return await e.json();case t.startsWith(`text/`):return await e.text();default:return await e.blob()}}catch(e){throw e.name===`AbortError`?Error(`Request aborted: ${e.message}`):e}})}function a(r){let{batchSize:i=99,batchDelay:a=0,onBeforeSend:o,compression:s}=r,c=()=>Math.random().toString(36),l=new Map,u=new TextEncoder,d=null,f=t=>{let n=t.target;try{let r=JSON.parse(t.data);if(!e(r))return;let i=l.get(r.id);if(!i||i.ws!==n)return;clearTimeout(i.timeout),`error`in r?i.reject(r.error):i.resolve(r.result),l.values().some(e=>e.ws===n)||n.removeEventListener(`message`,f)}catch(e){console.error(`Client failed parse server message`,e)}},p=e=>{let t=e.target;t.removeEventListener(`message`,f),l.values().filter(e=>e.ws===t).forEach(e=>e.reject(`Socket close`))},m=(e,t)=>(...n)=>{let r=l.get(e);return r&&(clearTimeout(r.timeout),l.delete(e)),t(...n)},h={once:!0},g=async()=>{d!==null&&(clearTimeout(d),d=null);let e=r.socket();if(!l.size||!e)return;e.addEventListener(`message`,f),e.addEventListener(`close`,p,h),e.addEventListener(`error`,p,h);let n=[];for(let[t,r]of l)r.ws||(r.ws=e,n.push({id:t,method:r.method,params:r.params}));if(!n.length)return;let i=JSON.stringify(n);if(s&&i.length>=s){let n=await t(u.encode(i));e.send(o?.(n)??n)}else e.send(o?.(i)??i)};return n((e,t,n)=>{let o={timeout:1e4,...r,...n},{promise:s,resolve:u,reject:f}=Promise.withResolvers(),p=c();return l.set(p,{id:p,method:e,params:t,options:o,resolve:m(p,u),reject:m(p,f),timeout:setTimeout(m(p,f),o.timeout),ws:null}),l.size>=i?g().catch(console.error):d===null&&(d=setTimeout(()=>g().catch(console.error),a)),s})}function o(e){return n((t,n,r)=>{let i=e.pick(t,n,r),a=t.split(`/`).filter(Boolean),o=i;for(let e of a)o[e]&&(o=o[e]);return o(n,r)})}export{i as createHTTPClient,o as createSuperClient,a as createWebSocketClient};
@@ -1,4 +1,4 @@
1
- import { s as Promisable } from "./types-DDhVsVEu.mjs";
1
+ import { s as Promisable } from "./types-CKfKFLqV.mjs";
2
2
  import { BunRequest, Server, ServerWebSocket } from "bun";
3
3
 
4
4
  //#region src/context.d.ts
@@ -31,5 +31,6 @@ interface WSContext<SD = unknown> extends BaseContext<SD> {
31
31
  }
32
32
  declare function isHTTP<SD>(context: BaseContext<SD>): context is HTTPContext<SD>;
33
33
  declare function isWS<SD>(context: BaseContext<SD>): context is WSContext<SD>;
34
+ type AnyContext<SD> = HTTPContext<SD> | WSContext<SD>;
34
35
  //#endregion
35
- export { DeriveValue as a, HTTPContext as c, isHTTP as d, isWS as f, DeriveUpgradeValue as i, ReplaceSocketData as l, DeriveRecord as n, GetDerived as o, DeriveUpgradePossibleValue as r, GetDerivedUpgradeData as s, BaseContext as t, WSContext as u };
36
+ export { DeriveUpgradeValue as a, GetDerivedUpgradeData as c, WSContext as d, isHTTP as f, DeriveUpgradePossibleValue as i, HTTPContext as l, BaseContext as n, DeriveValue as o, isWS as p, DeriveRecord as r, GetDerived as s, AnyContext as t, ReplaceSocketData as u };
@@ -1,2 +1,2 @@
1
- import { a as DeriveValue, c as HTTPContext, d as isHTTP, f as isWS, i as DeriveUpgradeValue, l as ReplaceSocketData, n as DeriveRecord, o as GetDerived, r as DeriveUpgradePossibleValue, s as GetDerivedUpgradeData, t as BaseContext, u as WSContext } from "./context-BdPiiQY2.mjs";
2
- export { BaseContext, DeriveRecord, DeriveUpgradePossibleValue, DeriveUpgradeValue, DeriveValue, GetDerived, GetDerivedUpgradeData, HTTPContext, ReplaceSocketData, WSContext, isHTTP, isWS };
1
+ import { a as DeriveUpgradeValue, c as GetDerivedUpgradeData, d as WSContext, f as isHTTP, i as DeriveUpgradePossibleValue, l as HTTPContext, n as BaseContext, o as DeriveValue, p as isWS, r as DeriveRecord, s as GetDerived, t as AnyContext, u as ReplaceSocketData } from "./context-DcgEPuHM.mjs";
2
+ export { AnyContext, BaseContext, DeriveRecord, DeriveUpgradePossibleValue, DeriveUpgradeValue, DeriveValue, GetDerived, GetDerivedUpgradeData, HTTPContext, ReplaceSocketData, WSContext, isHTTP, isWS };
package/dist/cors.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { t as BaseContext } from "./context-BdPiiQY2.mjs";
2
- import "./http-DW9-I0jB.mjs";
3
- import { t as Middleware } from "./middleware-BXszEB7Z.mjs";
1
+ import { n as BaseContext } from "./context-DcgEPuHM.mjs";
2
+ import "./http-D4yDA06a.mjs";
3
+ import { t as Middleware } from "./middleware-Dj4LOBOr.mjs";
4
4
 
5
5
  //#region src/cors.d.ts
6
6
  interface CorsConfig {
package/dist/cors.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./response-Cg3awmqM.mjs";import{isHTTP as t}from"./context.mjs";const n={"Access-Control-Allow-Methods":[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`OPTIONS`].join(`, `),"Access-Control-Allow-Headers":[`Accept-Language`,`Accept`,`Content-Type`,`Content-Language`,`Range`].join(`, `),"Access-Control-Expose-Headers":[`Cache-Control`,`Content-Language`,`Content-Type`,`Expires`,`Last-Modified`,`Pragma`].join(`, `),"Access-Control-Max-Age":`3600`};function r(r){let i={...n,...r.methods?.length&&{"Access-Control-Allow-Methods":r.methods.join(`, `)},...r.allowedHeaders?.length&&{"Access-Control-Allow-Headers":r.allowedHeaders.join(`, `)},...r.exposedHeaders?.length&&{"Access-Control-Expose-Headers":r.exposedHeaders.join(`, `)},...r.credentials&&!r.origin.includes(`*`)&&{"Access-Control-Allow-Credentials":`true`},...r.maxAge&&{"Access-Control-Max-Age":r.maxAge.toString()}};return async n=>{if(!t(n.context))return n.next();let a=n.context.request.headers.get(`Origin`);if(!a||!r.origin.includes(a))return n.next();if(n.context.request.method===`OPTIONS`)return new Response(null,{status:204,headers:{"Access-Control-Allow-Origin":a,...i}});let o;try{o=e(await n.next())}catch(t){o=e(t)}for(let e in o.headers.set(`Access-Control-Allow-Origin`,a),i)o.headers.set(e,i[e]);return o}}export{r as createCORSMiddleware};
1
+ import{t as e}from"./response-C6th92gD.mjs";import{isHTTP as t}from"./context.mjs";const n={"Access-Control-Allow-Methods":[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`OPTIONS`].join(`, `),"Access-Control-Allow-Headers":[`Content-Type`,`Authorization`].join(`, `),"Access-Control-Max-Age":`3600`};function r(r){let i={...n,...r.methods?.length&&{"Access-Control-Allow-Methods":r.methods.join(`, `)},...r.allowedHeaders?.length&&{"Access-Control-Allow-Headers":r.allowedHeaders.join(`, `)},...r.maxAge!==void 0&&{"Access-Control-Max-Age":r.maxAge.toString()}},a={...r.exposedHeaders?.length&&{"Access-Control-Expose-Headers":r.exposedHeaders.join(`, `)},...r.credentials&&!r.origin.includes(`*`)&&{"Access-Control-Allow-Credentials":`true`}};return async n=>{if(!t(n.context))return n.next();let o=n.context.request.headers.get(`Origin`);if(!o||!r.origin.includes(o))return n.next();if(n.context.request.method===`OPTIONS`)return new Response(null,{status:204,headers:{"Access-Control-Allow-Origin":o,...i,...a}});let s;try{s=e(await n.next())}catch(t){s=e(t)}for(let e in s.headers.set(`Access-Control-Allow-Origin`,o),a)s.headers.set(e,a[e]);return s}}export{r as createCORSMiddleware};
package/dist/crypto.mjs CHANGED
@@ -1 +1 @@
1
- import{createCipheriv as e,createDecipheriv as t,createHmac as n,randomBytes as r,timingSafeEqual as i}from"node:crypto";const a=`aes-256-gcm`,o=`base64url`;function s(e,t){let r=Buffer.from(e).toString(o);return`${r}.${n(`sha256`,t).update(r).digest(o)}`}function c(e,t){let[r,a]=e.split(`.`);if(!r||!a)return null;let s=n(`sha256`,t).update(r).digest(o),c=Buffer.from(a,o),l=Buffer.from(s,o);return c.length!==l.length||!i(c,l)?null:Buffer.from(r,o).toString()}function l(t,n){let i=r(12),s=e(a,n,i),c=s.update(t,`utf-8`,o);return c+=s.final(o),Buffer.concat([i,s.getAuthTag(),Buffer.from(c,o)]).toString(o)}function u(e,n){let r=Buffer.from(e,o);if(r.length<28)return null;let i=r.subarray(0,12),s=r.subarray(12,28),c=r.subarray(28),l=t(a,n,i);return l.setAuthTag(s),`${l.update(c,void 0,`utf-8`)}${l.final(`utf-8`)}`}export{u as decrypt,l as encrypt,s as sign,c as unsign};
1
+ import{createCipheriv as e,createDecipheriv as t,createHash as n,createHmac as r,randomBytes as i,timingSafeEqual as a}from"node:crypto";const o=`aes-256-gcm`,s=`base64url`;function c(e){return n(`sha256`).update(e).digest()}function l(e,t){let n=c(t),i=Buffer.from(e).toString(s);return`${i}.${r(`sha256`,n).update(i).digest(s)}`}function u(e,t){let[n,i]=e.split(`.`);if(!n||!i)return null;let o=r(`sha256`,c(t)).update(n).digest(s),l=Buffer.from(i,s),u=Buffer.from(o,s);return l.length!==u.length||!a(l,u)?null:Buffer.from(n,s).toString()}function d(t,n){let r=c(n),a=i(12),l=e(o,r,a),u=l.update(t,`utf-8`,s);return u+=l.final(s),Buffer.concat([a,l.getAuthTag(),Buffer.from(u,s)]).toString(s)}function f(e,n){let r=c(n),i=Buffer.from(e,s);if(i.length<28)return null;let a=i.subarray(0,12),l=i.subarray(12,28),u=i.subarray(28),d=t(o,r,a);return d.setAuthTag(l),`${d.update(u,void 0,`utf-8`)}${d.final(`utf-8`)}`}export{f as decrypt,d as encrypt,l as sign,u as unsign};
@@ -1,4 +1,4 @@
1
- import { s as Promisable } from "./types-DDhVsVEu.mjs";
1
+ import { s as Promisable } from "./types-CKfKFLqV.mjs";
2
2
  import { BunRequest, Server } from "bun";
3
3
 
4
4
  //#region src/http.d.ts
package/dist/http.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as BunRoutes, r as HTTPMethod, t as BunRouteHandler } from "./http-DW9-I0jB.mjs";
1
+ import { n as BunRoutes, r as HTTPMethod, t as BunRouteHandler } from "./http-D4yDA06a.mjs";
2
2
  export { BunRouteHandler, BunRoutes, HTTPMethod };
@@ -0,0 +1,62 @@
1
+ import { s as Promisable } from "./types-CKfKFLqV.mjs";
2
+ import { r as HTTPMethod } from "./http-D4yDA06a.mjs";
3
+ import { c as StandardSchemaV1, n as InferInput, r as InferOutput } from "./validation-CBofLqUN.mjs";
4
+
5
+ //#region src/procedure.d.ts
6
+ interface ProcedureOptions<I$1, C$1> {
7
+ input: I$1;
8
+ context: C$1;
9
+ }
10
+ /** Input: I, Output: O, Context: C */
11
+ type ProcedureHandler<I$1, O$1, C$1> = (options: ProcedureOptions<I$1, C$1>) => Promisable<O$1>;
12
+ type GetInput<I$1> = I$1 extends StandardSchemaV1 ? InferInput<I$1> : I$1;
13
+ type GetOutput<O$1> = O$1 extends StandardSchemaV1 ? InferOutput<O$1> : O$1;
14
+ type ProcedureOutput<T> = T extends Procedure<any, infer O, any> ? GetOutput<O> : never;
15
+ type ProcedureToOptions<T> = T extends Procedure<infer I, any, infer C> ? ProcedureOptions<I, C> : never;
16
+ interface HTTPOptions {
17
+ enabled?: boolean;
18
+ method?: HTTPMethod;
19
+ }
20
+ /**
21
+ * @generic I is a Schema or raw value
22
+ * @generic O is a Schema or raw value
23
+ * @generic C is context
24
+ */
25
+ declare class Procedure<I$1 = unknown, O$1 = unknown, C$1 = unknown> {
26
+ protected readonly middlewares: Set<Middleware<GetOutput<I$1>, GetOutput<O$1>, C$1>>;
27
+ protected inputSchema?: StandardSchemaV1<I$1>;
28
+ protected outputSchema?: StandardSchemaV1<O$1>;
29
+ protected handlerFunction?: ProcedureHandler<I$1, O$1, C$1>;
30
+ protected httpOptions?: HTTPOptions;
31
+ /** Set procedure input validation schema or type */
32
+ input<const NI>(schema: NI): Procedure<NI, O$1, C$1>;
33
+ /** Set procedure output validation schema or type */
34
+ output<const NO>(schema?: NO): Procedure<I$1, NO, C$1>;
35
+ /** Set procedure handler function */
36
+ handler<const ActualOutput>(handler: ProcedureHandler<GetOutput<I$1>, GetInput<unknown extends O$1 ? ActualOutput : O$1>, C$1>): Procedure<I$1, unknown extends O$1 ? ActualOutput : O$1, C$1>;
37
+ /** Set HTTP options for the procedure */
38
+ http(options?: HTTPOptions | boolean | HTTPMethod): Procedure<I$1, O$1, C$1>;
39
+ /** Add middleware to the procedure */
40
+ use(middleware: Middleware<GetOutput<I$1>, GetOutput<O$1>, C$1>): this;
41
+ /** Returns a function that checks input and output parameters. */
42
+ compile(): ProcedureHandler<I$1, O$1, C$1>;
43
+ /** Get procedure metadata information */
44
+ metadata(): {
45
+ http: HTTPOptions | undefined;
46
+ middlewares: Set<Middleware<GetOutput<I$1>, GetOutput<O$1>, C$1>>;
47
+ has: {
48
+ handler: boolean;
49
+ middleware: boolean;
50
+ input: boolean;
51
+ output: boolean;
52
+ };
53
+ };
54
+ }
55
+ //#endregion
56
+ //#region src/middleware.d.ts
57
+ interface MiddlewareOptions<I$1, O$1, C$1> extends ProcedureOptions<I$1, C$1> {
58
+ next: () => ReturnType<ProcedureHandler<I$1, O$1, C$1>>;
59
+ }
60
+ type Middleware<I$1, O$1, C$1> = (options: MiddlewareOptions<I$1, O$1, C$1>) => ReturnType<ProcedureHandler<I$1, O$1, C$1>>;
61
+ //#endregion
62
+ export { HTTPOptions as a, ProcedureOptions as c, GetOutput as i, ProcedureOutput as l, MiddlewareOptions as n, Procedure as o, GetInput as r, ProcedureHandler as s, Middleware as t, ProcedureToOptions as u };
@@ -1,3 +1,3 @@
1
- import "./http-DW9-I0jB.mjs";
2
- import { n as MiddlewareOptions, t as Middleware } from "./middleware-BXszEB7Z.mjs";
1
+ import "./http-D4yDA06a.mjs";
2
+ import { n as MiddlewareOptions, t as Middleware } from "./middleware-Dj4LOBOr.mjs";
3
3
  export { Middleware, MiddlewareOptions };
@@ -1,3 +1,3 @@
1
- import "./http-DW9-I0jB.mjs";
2
- import { a as HTTPOptions, c as ProcedureOptions, i as GetOutput, o as Procedure, r as GetInput, s as ProcedureHandler } from "./middleware-BXszEB7Z.mjs";
3
- export { GetInput, GetOutput, HTTPOptions, Procedure, ProcedureHandler, ProcedureOptions };
1
+ import "./http-D4yDA06a.mjs";
2
+ import { a as HTTPOptions, c as ProcedureOptions, i as GetOutput, l as ProcedureOutput, o as Procedure, r as GetInput, s as ProcedureHandler, u as ProcedureToOptions } from "./middleware-Dj4LOBOr.mjs";
3
+ export { GetInput, GetOutput, HTTPOptions, Procedure, ProcedureHandler, ProcedureOptions, ProcedureOutput, ProcedureToOptions };
@@ -0,0 +1 @@
1
+ import{n as e}from"./error-45bzsfk8.mjs";function t(t){switch(!0){case t instanceof Response:return t;case t instanceof e:return t.toResponse();case t instanceof Error:return new Response(t.message,{status:500});case typeof t==`object`:return Response.json(t);case t==null:return new Response(null,{status:204});default:return new Response(String(t))}}function n(t,n){let r;switch(!0){case n instanceof e:r={id:t,error:{code:n.status,message:n.message}};break;case n instanceof Error:r={id:t,error:{code:500,message:n.message}};break;case n instanceof Response:r={id:t,error:{code:n.status,message:n.statusText}};break;case typeof n==`object`||typeof n==`number`||typeof n==`boolean`:r={id:t,result:n};break;default:r={id:t,result:String(n)}}return JSON.stringify(r)}export{n,t};
package/dist/response.mjs CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./response-Cg3awmqM.mjs";export{t as toHTTPResponse,e as toRPCResponse};
1
+ import{n as e,t}from"./response-C6th92gD.mjs";export{t as toHTTPResponse,e as toRPCResponse};
@@ -0,0 +1 @@
1
+ function e(e){return!!e&&typeof e==`object`&&`id`in e&&`method`in e}function t(e){return!!e&&typeof e==`object`&&`id`in e&&(`result`in e||`error`in e)}export{t as n,e as t};
@@ -1,4 +1,4 @@
1
- import { o as JSONValue } from "./types-DDhVsVEu.mjs";
1
+ import { o as JSONValue } from "./types-CKfKFLqV.mjs";
2
2
 
3
3
  //#region src/rpc.d.ts
4
4
  interface ErrorResult {
@@ -19,5 +19,6 @@ interface Payload {
19
19
  params?: JSONValue;
20
20
  }
21
21
  declare function isRPC(value: any): value is Payload;
22
+ declare function isRPCResponse(value: any): value is Result;
22
23
  //#endregion
23
- export { isRPC as a, SuccessResult as i, Payload as n, Result as r, ErrorResult as t };
24
+ export { isRPC as a, SuccessResult as i, Payload as n, isRPCResponse as o, Result as r, ErrorResult as t };
package/dist/rpc.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as isRPC, i as SuccessResult, n as Payload, r as Result, t as ErrorResult } from "./rpc-BzGFmZuu.mjs";
2
- export { ErrorResult, Payload, Result, SuccessResult, isRPC };
1
+ import { a as isRPC, i as SuccessResult, n as Payload, o as isRPCResponse, r as Result, t as ErrorResult } from "./rpc-Y49i4Uuu.mjs";
2
+ export { ErrorResult, Payload, Result, SuccessResult, isRPC, isRPCResponse };
package/dist/rpc.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./rpc-Hr71rqEs.mjs";export{e as isRPC};
1
+ import{n as e,t}from"./rpc-XjW9_Smw.mjs";export{t as isRPC,e as isRPCResponse};
@@ -1,7 +1,7 @@
1
- import { i as JSONObject, o as JSONValue, s as Promisable, t as DeepReadonly } from "./types-DDhVsVEu.mjs";
2
- import { n as DeriveRecord, t as BaseContext } from "./context-BdPiiQY2.mjs";
3
- import "./http-DW9-I0jB.mjs";
4
- import { o as Procedure } from "./middleware-BXszEB7Z.mjs";
1
+ import { i as JSONObject, o as JSONValue, s as Promisable, t as DeepReadonly } from "./types-CKfKFLqV.mjs";
2
+ import { n as BaseContext, r as DeriveRecord } from "./context-DcgEPuHM.mjs";
3
+ import "./http-D4yDA06a.mjs";
4
+ import { o as Procedure } from "./middleware-Dj4LOBOr.mjs";
5
5
  import { ProceduresMap, Ultra } from "./ultra.mjs";
6
6
  import { BunRequest, CookieSameSite, RedisClient } from "bun";
7
7
 
@@ -28,7 +28,7 @@ interface SessionCookieOptions {
28
28
  maxAge: number;
29
29
  }
30
30
  /** Factory for create session store */
31
- type SessionStoreFactory = (config: SessionConfig<any>, context: BaseContext) => SessionStore;
31
+ type SessionStoreFactory = (config: SessionConfig<any>) => SessionStore;
32
32
  interface SessionConfig<S extends Record<string, SessionStoreFactory> = Record<string, SessionStoreFactory>> {
33
33
  /** The name is used as a prefix to cookies and storage with such as Redis */
34
34
  name: string;
@@ -83,7 +83,7 @@ declare class Session<Stores extends Record<string, SessionStoreFactory> = Recor
83
83
  protected sessionId: string;
84
84
  protected sessionState: JSONObject | null;
85
85
  protected modified: boolean;
86
- constructor(config: SessionConfig<Stores>, context: BaseContext);
86
+ constructor(config: SessionConfig<Stores>, context: BaseContext, store: SessionStore);
87
87
  get id(): string;
88
88
  /** Load data from session store */
89
89
  initiate(): Promise<void>;
@@ -112,6 +112,10 @@ declare class RedisSessionStore implements SessionStore {
112
112
  touch(sessionId: string): Promise<void>;
113
113
  }
114
114
  declare class MemorySessionStore implements SessionStore {
115
+ protected readonly sessions: Map<string, {
116
+ data: SessionData;
117
+ touched: number;
118
+ }>;
115
119
  protected readonly config: SessionConfig<any>;
116
120
  protected readonly sweepIntervalMs: number;
117
121
  protected readonly ttlMs: number;
package/dist/session.mjs CHANGED
@@ -1 +1 @@
1
- import{i as e}from"./error-45bzsfk8.mjs";import{Ultra as t}from"./ultra.mjs";import{isHTTP as n,isWS as r}from"./context.mjs";import{sign as i,unsign as a}from"./crypto.mjs";import{Cookie as o}from"bun";import{randomBytes as s}from"node:crypto";function c(e){return{...e,cookie:{path:`/`,httpOnly:!0,secure:!0,sameSite:`lax`,maxAge:e.ttlSec,...e?.cookie}}}function l(e){return new t().deriveUpgrade(t=>{let n=u.getOrCreateId(t.request,e);return{headers:{"Set-Cookie":new o(e.name,i(n,e.secret),e.cookie).toString()},data:{sessionId:n}}}).derive(t=>({session:new u(e,t)})).use(async({context:e,next:t})=>{await e.session.initiate();let n=await t();return await e.session.commit(),n})}var u=class t{static makeId(){return s(16).toString(`base64url`)}static getOrCreateId(e,n){let r=e.cookies.get(n.name);return r&&a(r,n.secret)||t.makeId()}config;context;store;sessionIdFromClient=null;sessionId;sessionState=null;modified=!1;constructor(i,o){switch(this.config=i,this.context=o,this.store=i.stores[i.store](i,o),!0){case n(o):{let e=o.request.cookies.get(i.name);e&&(this.sessionIdFromClient=a(e,i.secret));break}case r(o):this.sessionIdFromClient=o.ws.data.sessionId||null;break;default:throw new e(`Session management is only supported for HTTP and WebSocket protocols.`)}this.sessionId=this.sessionIdFromClient||t.makeId()}get id(){return this.sessionId}async initiate(){this.sessionState||=await this.store.read(this.sessionId)||{}}async commit(){if(this.touch(),this.isEmpty&&this.sessionIdFromClient)return this.store.destroy(this.sessionIdFromClient);this.sessionIdFromClient&&this.sessionIdFromClient!==this.sessionId?(await this.store.destroy(this.sessionIdFromClient),await this.store.write(this.sessionId,this.state)):this.modified?await this.store.write(this.sessionId,this.state):await this.store.touch(this.sessionId)}regenerate(){this.sessionId=t.makeId()}get(e,t){return this.state[e]??t??null}set(e,t){this.state[e]=t,this.modified=!0}has(e){return Object.hasOwn(this.state,e)}all(){return this.state}delete(e){delete this.state[e],this.modified=!0}clear(){this.sessionState={},this.modified=!0}get state(){if(!this.sessionState)throw Error(`Session is not initiated yet.`);return this.sessionState}get isEmpty(){return Object.keys(this.state).length===0}touch(){n(this.context)&&this.context.request.cookies.set(this.config.name,i(this.sessionId,this.config.secret),this.config.cookie)}},d=class{config;connection;constructor(e,t){this.config=e,this.connection=t}async read(e){let t=await this.connection.get(`${this.config.name}:${e}`);return t?JSON.parse(t):null}async write(e,t){await this.connection.set(`${this.config.name}:${e}`,JSON.stringify(t),`EX`,this.config.ttlSec)}async destroy(e){await this.connection.del(`${this.config.name}:${e}`)}async touch(e){await this.connection.expire(`${this.config.name}:${e}`,this.config.ttlSec)}};const f=new Map;var p=class{config;sweepIntervalMs;ttlMs;lastSweepAt=Date.now();constructor(e,t=e.ttlSec){this.config=e,this.sweepIntervalMs=t*1e3,this.ttlMs=e.ttlSec*1e3}read(e){return this.maybeSweep(),f.get(e)?.data??null}write(e,t){this.maybeSweep(),f.set(e,{data:t,touched:Date.now()})}destroy(e){this.maybeSweep(),f.delete(e)}touch(e){this.maybeSweep();let t=f.get(e);t&&(t.touched=Date.now())}maybeSweep(e=Date.now()){if(!(e-this.lastSweepAt<this.sweepIntervalMs)){this.lastSweepAt=e;for(let[t,n]of f)e-n.touched>this.ttlMs&&f.delete(t)}}};export{p as MemorySessionStore,d as RedisSessionStore,u as Session,l as createSessionModule,c as defineConfig};
1
+ import{i as e}from"./error-45bzsfk8.mjs";import{Ultra as t}from"./ultra.mjs";import{isHTTP as n,isWS as r}from"./context.mjs";import{sign as i,unsign as a}from"./crypto.mjs";import{Cookie as o}from"bun";import{randomBytes as s}from"node:crypto";function c(e){return{...e,cookie:{path:`/`,httpOnly:!0,secure:!0,sameSite:`lax`,maxAge:e.ttlSec,...e?.cookie}}}function l(e){let n=e.stores[e.store](e);return new t().deriveUpgrade(t=>{let n=u.getOrCreateId(t.request,e);return{headers:{"Set-Cookie":new o(e.name,i(n,e.secret),e.cookie).toString()},data:{sessionId:n}}}).derive(t=>({session:new u(e,t,n)})).use(async({context:e,next:t})=>{await e.session.initiate();let n=await t();return await e.session.commit(),n})}var u=class t{static makeId(){return s(16).toString(`base64url`)}static getOrCreateId(e,n){let r=e.cookies.get(n.name);return r&&a(r,n.secret)||t.makeId()}config;context;store;sessionIdFromClient=null;sessionId;sessionState=null;modified=!1;constructor(i,o,s){switch(this.config=i,this.context=o,this.store=s,!0){case n(o):{let e=o.request.cookies.get(i.name);e&&(this.sessionIdFromClient=a(e,i.secret));break}case r(o):this.sessionIdFromClient=o.ws.data.sessionId||null;break;default:throw new e(`Session management is only supported for HTTP and WebSocket protocols.`)}this.sessionId=this.sessionIdFromClient||t.makeId()}get id(){return this.sessionId}async initiate(){this.sessionState||=await this.store.read(this.sessionId)||{}}async commit(){if(this.touch(),this.isEmpty&&this.sessionIdFromClient)return this.store.destroy(this.sessionIdFromClient);this.sessionIdFromClient&&this.sessionIdFromClient!==this.sessionId?(await this.store.destroy(this.sessionIdFromClient),await this.store.write(this.sessionId,this.state)):this.modified?await this.store.write(this.sessionId,this.state):await this.store.touch(this.sessionId)}regenerate(){this.sessionId=t.makeId()}get(e,t){return this.state[e]??t??null}set(e,t){this.state[e]=t,this.modified=!0}has(e){return Object.hasOwn(this.state,e)}all(){return this.state}delete(e){delete this.state[e],this.modified=!0}clear(){this.sessionState={},this.modified=!0}get state(){if(!this.sessionState)throw Error(`Session is not initiated yet.`);return this.sessionState}get isEmpty(){return Object.keys(this.state).length===0}touch(){n(this.context)&&this.context.request.cookies.set(this.config.name,i(this.sessionId,this.config.secret),this.config.cookie)}},d=class{config;connection;constructor(e,t){this.config=e,this.connection=t}async read(e){let t=await this.connection.get(`${this.config.name}:${e}`);return t?JSON.parse(t):null}async write(e,t){await this.connection.set(`${this.config.name}:${e}`,JSON.stringify(t),`EX`,this.config.ttlSec)}async destroy(e){await this.connection.del(`${this.config.name}:${e}`)}async touch(e){await this.connection.expire(`${this.config.name}:${e}`,this.config.ttlSec)}},f=class{sessions=new Map;config;sweepIntervalMs;ttlMs;lastSweepAt=Date.now();constructor(e,t=e.ttlSec){this.config=e,this.sweepIntervalMs=t*1e3,this.ttlMs=e.ttlSec*1e3}read(e){return this.maybeSweep(),this.sessions.get(e)?.data??null}write(e,t){this.maybeSweep(),this.sessions.set(e,{data:t,touched:Date.now()})}destroy(e){this.maybeSweep(),this.sessions.delete(e)}touch(e){this.maybeSweep();let t=this.sessions.get(e);t&&(t.touched=Date.now())}maybeSweep(e=Date.now()){if(!(e-this.lastSweepAt<this.sweepIntervalMs)){this.lastSweepAt=e;for(let[t,n]of this.sessions)e-n.touched>this.ttlMs&&this.sessions.delete(t)}}};export{f as MemorySessionStore,d as RedisSessionStore,u as Session,l as createSessionModule,c as defineConfig};
@@ -1,5 +1,7 @@
1
1
  //#region src/types.d.ts
2
2
  type Promisable<T> = T | Promise<T>;
3
+ type GetReturn<T> = T extends ((...args: any[]) => infer R) ? Awaited<R> : T;
4
+ type Simplify<T> = T extends object ? { [K in keyof T]: T[K] } & {} : T;
3
5
  type JSONPrimitive = string | number | boolean | null;
4
6
  interface JSONObject {
5
7
  [key: string]: JSONValue;
@@ -7,8 +9,5 @@ interface JSONObject {
7
9
  type JSONArray = JSONValue[];
8
10
  type JSONValue = JSONPrimitive | JSONObject | JSONArray;
9
11
  type DeepReadonly<T> = T extends Array<infer R> ? ReadonlyArray<DeepReadonly<R>> : T extends object ? { readonly [P in keyof T]: DeepReadonly<T[P]> } : Readonly<T>;
10
- type GetReturn<T> = T extends ((...args: any[]) => infer R) ? Awaited<R> : T;
11
- type ResetRecursion<T> = T & {};
12
- type Simplify<T> = T extends object ? { [K in keyof T]: T[K] } & {} : T;
13
12
  //#endregion
14
- export { JSONPrimitive as a, ResetRecursion as c, JSONObject as i, Simplify as l, GetReturn as n, JSONValue as o, JSONArray as r, Promisable as s, DeepReadonly as t };
13
+ export { JSONPrimitive as a, Simplify as c, JSONObject as i, GetReturn as n, JSONValue as o, JSONArray as r, Promisable as s, DeepReadonly as t };
package/dist/types.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as JSONPrimitive, c as ResetRecursion, i as JSONObject, l as Simplify, n as GetReturn, o as JSONValue, r as JSONArray, s as Promisable, t as DeepReadonly } from "./types-DDhVsVEu.mjs";
2
- export { DeepReadonly, GetReturn, JSONArray, JSONObject, JSONPrimitive, JSONValue, Promisable, ResetRecursion, Simplify };
1
+ import { a as JSONPrimitive, c as Simplify, i as JSONObject, n as GetReturn, o as JSONValue, r as JSONArray, s as Promisable, t as DeepReadonly } from "./types-CKfKFLqV.mjs";
2
+ export { DeepReadonly, GetReturn, JSONArray, JSONObject, JSONPrimitive, JSONValue, Promisable, Simplify };
package/dist/ultra.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { l as Simplify } from "./types-DDhVsVEu.mjs";
2
- import { a as DeriveValue, i as DeriveUpgradeValue, l as ReplaceSocketData, n as DeriveRecord, o as GetDerived, s as GetDerivedUpgradeData, t as BaseContext } from "./context-BdPiiQY2.mjs";
3
- import { n as BunRoutes } from "./http-DW9-I0jB.mjs";
4
- import { o as Procedure, s as ProcedureHandler, t as Middleware } from "./middleware-BXszEB7Z.mjs";
5
- import { n as Payload } from "./rpc-BzGFmZuu.mjs";
1
+ import { c as Simplify } from "./types-CKfKFLqV.mjs";
2
+ import { a as DeriveUpgradeValue, c as GetDerivedUpgradeData, n as BaseContext, o as DeriveValue, r as DeriveRecord, s as GetDerived, t as AnyContext, u as ReplaceSocketData } from "./context-DcgEPuHM.mjs";
3
+ import { n as BunRoutes } from "./http-D4yDA06a.mjs";
4
+ import { o as Procedure, s as ProcedureHandler, t as Middleware } from "./middleware-Dj4LOBOr.mjs";
5
+ import { n as Payload } from "./rpc-Y49i4Uuu.mjs";
6
6
  import { BunRequest, ErrorLike, Server, ServerWebSocket } from "bun";
7
7
 
8
8
  //#region src/ultra.d.ts
@@ -28,7 +28,7 @@ interface UltraOptions {
28
28
  enableByDefault?: boolean;
29
29
  };
30
30
  }
31
- declare class Ultra<const Procedures extends ProceduresMap = ProceduresMap, const SocketData extends DeriveRecord = DeriveRecord, const Context extends BaseContext<SocketData> = BaseContext<SocketData>> {
31
+ declare class Ultra<const Procedures extends ProceduresMap = {}, const SocketData extends DeriveRecord = DeriveRecord, const Context extends BaseContext<SocketData> = BaseContext<SocketData>> {
32
32
  protected readonly initializers: Map<ProcedureMapInitializer<any, Context>, Set<Middleware<any, any, Context>>>;
33
33
  protected readonly events: Map<keyof ServerEventMap<SocketData>, Set<ServerEventListener<SocketData, any>>>;
34
34
  protected readonly middlewares: Set<Middleware<any, any, Context>>;
@@ -36,10 +36,11 @@ declare class Ultra<const Procedures extends ProceduresMap = ProceduresMap, cons
36
36
  protected readonly derivedUpgrade: Set<DeriveUpgradeValue<Context>>;
37
37
  protected readonly options: UltraOptions;
38
38
  protected httpEnabled: boolean;
39
- protected server?: Server<SocketData>;
39
+ protected server: Server<SocketData> | null;
40
+ protected handlers: Map<string, ProcedureHandler<unknown, unknown, Context>> | null;
40
41
  constructor(options?: UltraOptions);
41
42
  /** Register procedures */
42
- routes<const P extends ProceduresMap>(initializer: ProcedureMapInitializer<P, Context>, middlewares?: Middleware<any, any, Context>[]): Ultra<Procedures & P, SocketData, Context>;
43
+ routes<const P extends ProceduresMap>(initializer: ProcedureMapInitializer<P, Context>, middlewares?: Middleware<any, any, Context>[]): Ultra<Simplify<Procedures & P>, SocketData, Context>;
43
44
  /** Register middleware or another Ultra instance */
44
45
  use<const PluginProcedures extends ProceduresMap, const PluginSocketData extends DeriveRecord, const PluginContext extends BaseContext<PluginSocketData>>(entity: Middleware<any, any, Context> | Ultra<PluginProcedures, PluginSocketData, PluginContext>): Ultra<Simplify<Procedures & PluginProcedures>, Simplify<SocketData & PluginSocketData>, Simplify<ReplaceSocketData<Context & PluginContext, SocketData & PluginSocketData>>>;
45
46
  /** Extends context values for every request with provided values */
@@ -53,9 +54,9 @@ declare class Ultra<const Procedures extends ProceduresMap = ProceduresMap, cons
53
54
  on<E extends keyof ServerEventMap<SocketData>>(event: E, listener: ServerEventListener<SocketData, E>): this;
54
55
  off<E extends keyof ServerEventMap<SocketData>>(event: E, listener: ServerEventListener<SocketData, E>): this;
55
56
  emit<E extends keyof ServerEventMap<SocketData>>(event: E, ...args: ServerEventMap<SocketData>[E]): this;
56
- protected handleRPC(handler: ProcedureHandler<unknown, unknown, Context> | undefined, ws: ServerWebSocket<SocketData>, rpc: Payload, context: Context): Promise<void>;
57
+ protected handleRPC(rpc: Payload, ws: ServerWebSocket<SocketData>, context: Context): Promise<void>;
57
58
  /** Enrich context with derived values */
58
- protected enrichContext<const C extends BaseContext>(context: C): Promise<Context>;
59
+ protected enrichContext<C extends AnyContext<SocketData>>(context: C): Promise<Context>;
59
60
  /** Enrich upgrade options with derived values */
60
61
  protected enrichUpgrade(context: Context): Promise<{
61
62
  data: Record<PropertyKey, any>;
package/dist/ultra.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./procedure-DqhXrslI.mjs";import{n as t,t as n}from"./response-Cg3awmqM.mjs";import{t as r}from"./rpc-Hr71rqEs.mjs";import{inflateSync as i,serve as a}from"bun";var o=class{initializers=new Map;events=new Map;middlewares=new Set;derived=new Set;derivedUpgrade=new Set;options={http:{enableByDefault:!1}};httpEnabled=!1;server;constructor(e){e&&(this.options={...this.options,...e}),this.httpEnabled=this.options.http?.enableByDefault??!1}routes(e,t){let n=this.initializers.get(e);return n?t?.forEach(e=>n.add(e)):this.initializers.set(e,new Set(t)),this}use(e){return typeof e==`function`?(this.middlewares.add(e),this):(this.merge(e),this)}derive(e){return this.derived.add(e),this}deriveUpgrade(e){return this.derivedUpgrade.add(e),this}start(e){if(this.server)return console.warn(`Server is already running`),this.server;let{routes:t,handlers:n}=this.build(),o=new TextDecoder,s=this.wrapHandler(()=>new Response(`Not Found`,{status:404}),this.middlewares);return this.server=a({...this.httpEnabled&&{routes:{...t,"/ws":async(e,t)=>{if(this.emit(`http:request`,e,t),!this.derivedUpgrade.size)return t.upgrade(e)?void 0:new Response(`WebSocket upgrade failed`,{status:500});if(!t.upgrade(e,await this.enrichUpgrade(this.derived.size?await this.enrichContext({server:t,request:e}):{server:t,request:e})))return new Response(`WebSocket upgrade failed`,{status:500})},"/*":async(e,t)=>(this.emit(`http:request`,e,t),s({input:null,context:this.derived.size?await this.enrichContext({server:t,request:e}):{server:t,request:e}}))}},websocket:{data:{},open:e=>{this.emit(`ws:open`,e)},close:(e,t,n)=>{this.emit(`ws:close`,e,t,n)},message:async(e,t)=>{this.emit(`ws:message`,e,t);let a=null;try{a=typeof t==`string`?JSON.parse(t):JSON.parse(o.decode(i(t)))}catch(e){console.error(`Message payload parsing failed`,e);return}let s=Array.isArray(a)?a.filter(r):r(a)?[a]:null;if(!s||!s.length)return;let c=this.derived.size?await this.enrichContext({server:this.server,ws:e}):{server:this.server,ws:e};for(let t of s)this.handleRPC(n.get(t.method),e,t,c)}},error:e=>(this.emit(`unhandled:error`,e),console.error(`Unhandled server error:`,e),new Response(`Internal server error`,{status:500})),...e}),this.emit(`server:started`,this.server),this.server}async stop(e=!1){if(!this.server)return console.error(`Server is not running`);await this.server.stop(e),this.emit(`server:stopped`,this.server,e)}on(e,t){return this.events.has(e)||this.events.set(e,new Set),this.events.get(e).add(t),this}off(e,t){return this.events.get(e)?.delete(t),this}emit(e,...t){return this.events.get(e)?.forEach(e=>e(...t)),this}async handleRPC(e,n,r,i){if(!e){n.send(`{"id": "${r.id}", "error": {"code": 404, "message": "Not found"}}`);return}try{n.send(t(r.id,await e({input:r.params,context:i})))}catch(e){this.emit(`error`,e),n.send(t(r.id,e))}}async enrichContext(e){for(let t of this.derived)Object.assign(e,typeof t==`function`?await t(e):t);return e}async enrichUpgrade(e){let t={data:{},headers:new Headers};for(let n of this.derivedUpgrade){let r=typeof n==`function`?await n(e):n;if(`data`in r&&Object.assign(t.data,r.data),`headers`in r)for(let[e,n]of Object.entries(r.headers))t.headers.set(e,n)}return t}merge(e){for(let[t,n]of e.initializers){let e=this.initializers.get(t);e?n.forEach(t=>e.add(t)):this.initializers.set(t,new Set(n))}e.derived.forEach(e=>this.derived.add(e)),e.derivedUpgrade.forEach(e=>this.derivedUpgrade.add(e)),e.middlewares.forEach(e=>this.middlewares.add(e)),e.events.forEach((e,t)=>{this.events.has(t)||this.events.set(t,new Set);let n=this.events.get(t);e.forEach(e=>n.add(e))})}wrapHandler(e,t){if(!t.size)return e;let n=Array.from(t),r=n.length;return async t=>{let i=0,a=()=>i===r?e(t):n[i++]({...t,next:a});return a()}}build(){let t=new Map,r={},i=t=>{let n=new e;return t&&n.input(t),this.options.http?.enableByDefault&&n.http(),n};for(let[a,o]of this.initializers){let s=a(i),c=[];for(let e in s)c.push({path:e,value:s[e]});for(;c.length;){let{path:i,value:a}=c.pop();if(a instanceof e){if(t.has(i))throw Error(`Procedure "${i}" already exists`);let e=a.metadata();!this.httpEnabled&&e.http?.enabled&&(this.httpEnabled=!0);let s=new Set([...this.middlewares,...o,...e.middlewares]),c=this.wrapHandler(a.compile(),s);if(t.set(i,c),!e.http?.enabled)continue;let l=`/${i}`,u=async(e,t)=>{this.emit(`http:request`,e,t);let r=e.body;if(r){if(e.method===`GET`){let t=e.url.indexOf(`?`);t!==-1&&t<e.url.length-1&&(r=Object.fromEntries(new URLSearchParams(e.url.slice(t+1)).entries()))}else if(e.headers.get(`Content-Length`)!==`0`){let t=e.headers.get(`Content-Type`);if(t)switch(!0){case t.startsWith(`application/json`):r=await e.json();break;case t.startsWith(`text`):r=await e.text();break;case t.startsWith(`multipart/form-data`):r=await e.formData();break;default:console.error(`Unsupported Content-Type for procedure ${i}: ${t}`);break}}}try{return n(await c({input:r,context:this.derived.size?await this.enrichContext({server:t,request:e}):{server:t,request:e}}))}catch(e){return this.emit(`error`,e),n(e)}};if(!e.http.method){r[l]=u;continue}r[l]||(r[l]={}),r[l][e.http.method]=u;continue}for(let[e,t]of Object.entries(a)){let n=i?`${i}/${e}`:e;c.push({path:n,value:t})}}}return{handlers:t,routes:r}}};export{o as Ultra};
1
+ import{t as e}from"./error-45bzsfk8.mjs";import{t}from"./procedure-DqhXrslI.mjs";import{n,t as r}from"./response-C6th92gD.mjs";import{t as i}from"./rpc-XjW9_Smw.mjs";import{inflateSync as a,serve as o}from"bun";var s=class{initializers=new Map;events=new Map;middlewares=new Set;derived=new Set;derivedUpgrade=new Set;options={http:{enableByDefault:!1}};httpEnabled=!1;server=null;handlers=null;constructor(e){e&&(this.options={...this.options,...e}),this.httpEnabled=this.options.http?.enableByDefault??!1}routes(e,t){let n=this.initializers.get(e);return n?t?.forEach(e=>n.add(e)):this.initializers.set(e,new Set(t)),this}use(e){return typeof e==`function`?(this.middlewares.add(e),this):(this.merge(e),this)}derive(e){return this.derived.add(e),this}deriveUpgrade(e){return this.derivedUpgrade.add(e),this}start(e){if(this.server)throw Error(`Server is already running. Create a new Ultra instance or stop the existing server first.`);let{routes:t,handlers:n}=this.build();this.handlers=n;let r=new TextDecoder,s=this.wrapHandler(()=>new Response(`Not Found`,{status:404}),this.middlewares);return this.server=o({...this.httpEnabled&&{routes:{...t,"/ws":async(e,t)=>{if(this.emit(`http:request`,e,t),!this.derivedUpgrade.size)return t.upgrade(e)?void 0:new Response(`WebSocket upgrade failed`,{status:500});if(!t.upgrade(e,await this.enrichContext({server:t,request:e}).then(e=>this.enrichUpgrade(e))))return new Response(`WebSocket upgrade failed`,{status:500})},"/*":async(e,t)=>(this.emit(`http:request`,e,t),s({input:null,context:await this.enrichContext({server:t,request:e})}))}},websocket:{data:{},open:e=>{this.emit(`ws:open`,e)},close:(e,t,n)=>{this.emit(`ws:close`,e,t,n)},message:async(e,t)=>{this.emit(`ws:message`,e,t);let n=null;try{n=typeof t==`string`?JSON.parse(t):JSON.parse(r.decode(a(t)))}catch(e){console.error(`Message payload parsing failed`,e);return}let o=Array.isArray(n)?n.filter(i):i(n)?[n]:null;if(!o||!o.length)return;let s=await this.enrichContext({server:this.server,ws:e});for(let t of o)this.handleRPC(t,e,s)}},error:e=>(this.emit(`unhandled:error`,e),console.error(`Unhandled server error:`,e),new Response(`Internal server error`,{status:500})),...e}),this.emit(`server:started`,this.server),this.server}async stop(e=!1){if(!this.server)return console.error(`Server is not running`);await this.server.stop(e),this.emit(`server:stopped`,this.server,e),this.server=null,this.handlers=null}on(e,t){return this.events.has(e)||this.events.set(e,new Set),this.events.get(e).add(t),this}off(e,t){return this.events.get(e)?.delete(t),this}emit(e,...t){return this.events.get(e)?.forEach(e=>e(...t)),this}async handleRPC(t,r,i){let a=this.handlers.get(t.method);if(!a){r.send(n(t.id,new e));return}try{r.send(n(t.id,await a({input:t.params,context:i})))}catch(e){this.emit(`error`,e),r.send(n(t.id,e))}}async enrichContext(e){for(let t of this.derived)e={...e,...typeof t==`function`?await t(e):t};return e}async enrichUpgrade(e){let t={data:{},headers:new Headers};for(let n of this.derivedUpgrade){let r=typeof n==`function`?await n(e):n;if(`data`in r&&(t.data={...t.data,...r.data}),`headers`in r)for(let[e,n]of Object.entries(r.headers))t.headers.set(e,n)}return t}merge(e){for(let[t,n]of e.initializers){let e=this.initializers.get(t);e?n.forEach(t=>e.add(t)):this.initializers.set(t,new Set(n))}e.derived.forEach(e=>this.derived.add(e)),e.derivedUpgrade.forEach(e=>this.derivedUpgrade.add(e)),e.middlewares.forEach(e=>this.middlewares.add(e)),e.events.forEach((e,t)=>{this.events.has(t)||this.events.set(t,new Set);let n=this.events.get(t);e.forEach(e=>n.add(e))})}wrapHandler(e,t){if(!t.size)return e;let n=Array.from(t),r=n.length;return async t=>{let i=0,a=()=>i===r?e(t):n[i++]({...t,next:a});return a()}}build(){let e=new Map,n={},i=e=>{let n=new t;return e&&n.input(e),this.options.http?.enableByDefault&&n.http(),n};for(let[a,o]of this.initializers){let s=a(i),c=[];for(let e in s)c.push({path:e,value:s[e]});for(;c.length;){let{path:i,value:a}=c.pop();if(a instanceof t){if(e.has(i))throw Error(`Procedure "${i}" already exists`);let t=a.metadata();!this.httpEnabled&&t.http?.enabled&&(this.httpEnabled=!0);let s=new Set([...this.middlewares,...o,...t.middlewares]),c=this.wrapHandler(a.compile(),s);if(e.set(i,c),!t.http?.enabled)continue;let l=`/${i}`,u=async(e,t)=>{this.emit(`http:request`,e,t);let n=e.body;if(n){if(e.method===`GET`){let t=e.url.indexOf(`?`);t!==-1&&t<e.url.length-1&&(n=Object.fromEntries(new URLSearchParams(e.url.slice(t+1)).entries()))}else if(e.headers.get(`Content-Length`)!==`0`){let t=e.headers.get(`Content-Type`);if(t)switch(!0){case t.startsWith(`application/json`):n=await e.json();break;case t.startsWith(`text`):n=await e.text();break;case t.startsWith(`multipart/form-data`):n=await e.formData();break;default:console.error(`Unsupported Content-Type for procedure ${i}: ${t}`);break}}}try{return r(await c({input:n,context:await this.enrichContext({server:t,request:e})}))}catch(e){return this.emit(`error`,e),r(e)}};if(!t.http.method){n[l]=u;continue}n[l]||(n[l]={}),n[l][t.http.method]=u;continue}for(let[e,t]of Object.entries(a)){let n=i?`${i}/${e}`:e;c.push({path:n,value:t})}}}return{handlers:e,routes:n}}};export{s as Ultra};
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@sx3/ultra",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "private": false,
6
6
  "description": "Type-safe RPC over HTTP/WebSocket for Bun",
7
7
  "author": "SX3",
8
8
  "license": "MIT",
9
9
  "homepage": "https://github.com/SX-3/ultra",
10
+ "engines": {
11
+ "bun": ">=1.0.0"
12
+ },
10
13
  "repository": {
11
14
  "type": "git",
12
15
  "url": "https://github.com/SX-3/ultra"
@@ -1,60 +0,0 @@
1
- import { s as Promisable } from "./types-DDhVsVEu.mjs";
2
- import { r as HTTPMethod } from "./http-DW9-I0jB.mjs";
3
- import { c as StandardSchemaV1, n as InferInput, r as InferOutput } from "./validation-CBofLqUN.mjs";
4
-
5
- //#region src/procedure.d.ts
6
- interface ProcedureOptions<I, C> {
7
- input: I;
8
- context: C;
9
- }
10
- /** Input: I, Output: O, Context: C */
11
- type ProcedureHandler<I, O, C> = (options: ProcedureOptions<I, C>) => Promisable<O>;
12
- type GetInput<I> = I extends StandardSchemaV1 ? InferInput<I> : I;
13
- type GetOutput<O> = O extends StandardSchemaV1 ? InferOutput<O> : O;
14
- interface HTTPOptions {
15
- enabled?: boolean;
16
- method?: HTTPMethod;
17
- }
18
- /**
19
- * @generic I is a Schema or raw value
20
- * @generic O is a Schema or raw value
21
- * @generic C is context
22
- */
23
- declare class Procedure<I = unknown, O = unknown, C = unknown> {
24
- protected readonly middlewares: Set<Middleware<I, O, C>>;
25
- protected inputSchema?: StandardSchemaV1<I>;
26
- protected outputSchema?: StandardSchemaV1<O>;
27
- protected handlerFunction?: ProcedureHandler<I, O, C>;
28
- protected httpOptions?: HTTPOptions;
29
- /** Set procedure input validation schema or type */
30
- input<const NI>(schema: NI): Procedure<NI, O, C>;
31
- /** Set procedure output validation schema or type */
32
- output<const NO>(schema?: NO): Procedure<I, NO, C>;
33
- /** Set procedure handler function */
34
- handler<const ActualOutput>(handler: ProcedureHandler<GetOutput<I>, GetInput<unknown extends O ? ActualOutput : O>, C>): Procedure<I, unknown extends O ? ActualOutput : O, C>;
35
- /** Set HTTP options for the procedure */
36
- http(options?: HTTPOptions | boolean | HTTPMethod): Procedure<I, O, C>;
37
- /** Add middleware to the procedure */
38
- use(middleware: Middleware<I, O, C>): this;
39
- /** Returns a function that checks input and output parameters. */
40
- compile(): ProcedureHandler<I, O, C>;
41
- /** Get procedure metadata information */
42
- metadata(): {
43
- http: HTTPOptions | undefined;
44
- middlewares: Set<Middleware<I, O, C>>;
45
- has: {
46
- handler: boolean;
47
- middleware: boolean;
48
- input: boolean;
49
- output: boolean;
50
- };
51
- };
52
- }
53
- //#endregion
54
- //#region src/middleware.d.ts
55
- interface MiddlewareOptions<I, O, C> extends ProcedureOptions<I, C> {
56
- next: () => ReturnType<ProcedureHandler<I, O, C>>;
57
- }
58
- type Middleware<I, O, C> = (options: MiddlewareOptions<I, O, C>) => ReturnType<ProcedureHandler<I, O, C>>;
59
- //#endregion
60
- export { HTTPOptions as a, ProcedureOptions as c, GetOutput as i, MiddlewareOptions as n, Procedure as o, GetInput as r, ProcedureHandler as s, Middleware as t };
@@ -1 +0,0 @@
1
- import{n as e}from"./error-45bzsfk8.mjs";function t(t){switch(!0){case t instanceof Response:return t;case t instanceof e:return t.toResponse();case t instanceof Error:return new Response(t.message,{status:500});case typeof t==`object`:return Response.json(t);case!t:return new Response(null,{status:204});default:return new Response(String(t))}}function n(t,n){let r;switch(!0){case n instanceof e:r={id:t,error:{code:n.status,message:n.message}};break;case n instanceof Error:r={id:t,error:{code:500,message:n.message}};break;case n instanceof Response:r={id:t,error:{code:n.status,message:n.statusText}};break;case typeof n==`object`||typeof n==`number`||typeof n==`boolean`:r={id:t,result:n};break;default:r={id:t,result:String(n)}}return JSON.stringify(r)}export{n,t};
@@ -1 +0,0 @@
1
- function e(e){return!!e&&typeof e==`object`&&`id`in e&&`method`in e}export{e as t};