@mateosuarezdev/brpc 1.0.8 → 1.0.10

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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ declare class BrpcClientError extends Error {
2
+ readonly status: number;
3
+ readonly code?: string;
4
+ readonly clientCode?: string;
5
+ readonly data?: any;
6
+ constructor(message: string, status: number, code?: string, clientCode?: string, data?: any);
7
+ isClientError(clientCode: string): boolean;
8
+ isUnauthorized(): boolean;
9
+ isForbidden(): boolean;
10
+ isNotFound(): boolean;
11
+ isValidationError(): boolean;
12
+ }
13
+ export { BrpcClientError };
@@ -0,0 +1,7 @@
1
+ export {};
2
+ /**
3
+ * Type safe error checker utility
4
+ * @param error
5
+ * @param clientCode
6
+ * @returns boolean
7
+ */
@@ -0,0 +1,4 @@
1
+ export * from "./storage";
2
+ export * from "./service";
3
+ export * from "./brpc-client-error";
4
+ export type { Headers, InferClientRoutes } from "./types";
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ function g(L,{provider:N,placeholder:O}={provider:"s3"}){if(!L)return O??"PLACEHOLDER";if(L.url)return L.url;if(L.key){if(N==="s3")return`${import.meta.env.VITE_S3_CDN_ENDPOINT}/${L.key}`;return`/storage/${L.key}`}return O??"PLACEHOLDER"}class V extends Error{status;code;clientCode;data;constructor(L,N,O,G,F){super(L);this.name="BrpcClientError",this.status=N,this.code=O,this.clientCode=G,this.data=F}isClientError(L){return this.clientCode===L}isUnauthorized(){return this.status===401}isForbidden(){return this.status===403}isNotFound(){return this.status===404}isValidationError(){return this.status===400||this.code==="BAD_REQUEST"}}class D{baseUrl;ws=null;subscriptions=new Map;messageQueue=[];isConnected=!1;reconnectTimeout=null;WebSocketImpl;getHeaders;authToken=null;debug;pendingAuth=!1;authActions=[];constructor(L,N,O,G=!1){this.baseUrl=L;this.WebSocketImpl=N,this.debug=G&&import.meta.env.VITE_NODE_ENV==="development",this.getHeaders=async()=>{if(typeof O==="function")return await O();return O||{}},this.connect()}async connect(){try{let L=await this.getHeaders();this.authToken=L.Authorization||null;let N=this.baseUrl;if(this.debug)console.log(`Connecting to WebSocket: ${N}`);this.ws=new this.WebSocketImpl(N),this.ws.onopen=async()=>{if(this.debug)console.log("WebSocket connection established");if(this.isConnected=!0,this.authActions=[],this.authToken){if(this.pendingAuth=!0,this.send({type:"authenticate",token:this.authToken}),this.debug)console.log("Sent authentication token, waiting for response");this.authActions.push(()=>{for(let O of this.subscriptions.keys())if(this.send({type:"subscribe",topic:O}),this.debug)console.log(`Resubscribed to topic: ${O}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((O)=>this.send(O)),this.messageQueue=[]})}else{for(let O of this.subscriptions.keys())if(this.send({type:"subscribe",topic:O}),this.debug)console.log(`Resubscribed to topic: ${O}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((O)=>this.send(O)),this.messageQueue=[]}},this.ws.onmessage=(O)=>{try{if(this.debug)console.log("WebSocket message received:",O.data);let G=JSON.parse(O.data);if(G.type==="auth_success"){let F=G.authenticated!==!1;if(this.debug)console.log(`WebSocket ${F?"authentication":"deauthentication"} successful`);if(this.pendingAuth=!1,F)this.authActions.forEach((E)=>E());this.authActions=[];return}if(G.type==="auth_error"){console.error("WebSocket authentication failed:",G.error),this.pendingAuth=!1,this.authActions=[];return}if(this.debug)console.log("Got new message",G);if(G.topic&&this.subscriptions.has(G.topic)){let F=this.subscriptions.get(G.topic);if(this.debug)console.log("Calling subscription callbacks");F?.forEach((E)=>E(G.data))}else if(G.error)console.error("WebSocket error:",G.error);else console.warn("Unhandled WebSocket message format:",G)}catch(G){if(this.debug)console.error("Error processing WebSocket message:",G),console.error("Raw message:",O.data)}},this.ws.onclose=(O)=>{if(this.isConnected=!1,this.pendingAuth=!1,this.debug)console.log(`WebSocket connection closed. Code: ${O.code}, Reason: ${O.reason}`);this.reconnectTimeout=setTimeout(()=>this.connect(),2000)},this.ws.onerror=(O)=>{if(this.debug)console.log("WebSocket error:",O)}}catch(L){if(this.debug)console.log("Failed to create WebSocket connection:",L);this.pendingAuth=!1,this.reconnectTimeout=setTimeout(()=>this.connect(),2000)}}disconnect(){if(this.reconnectTimeout)clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null;if(this.ws)this.ws.close(),this.ws=null;this.isConnected=!1,this.pendingAuth=!1,this.authActions=[],this.subscriptions.clear()}send(L){if(this.isConnected&&this.ws?.readyState===this.WebSocketImpl.OPEN){if(this.pendingAuth&&L.type!=="authenticate"){if(this.messageQueue.push(L),this.debug)console.log("Message queued until authentication completes:",L);return}let N=JSON.stringify(L);if(this.ws.send(N),this.debug)console.log("WebSocket message sent:",N)}else if(this.messageQueue.push(L),this.debug)console.log("WebSocket message queued (not connected):",L)}subscribe(L,N){if(!this.subscriptions.has(L)){if(this.subscriptions.set(L,new Set),this.isConnected){if(this.pendingAuth)this.authActions.push(()=>{if(this.send({type:"subscribe",topic:L}),this.debug)console.log(`Subscribed to topic after auth: ${L}`)});else if(this.send({type:"subscribe",topic:L}),this.debug)console.log(`Subscribed to topic: ${L}`)}}return this.subscriptions.get(L).add(N),{unsubscribe:()=>this.unsubscribe(L,N),publish:(O)=>this.publish(L,O)}}unsubscribe(L,N){let O=this.subscriptions.get(L);if(O){if(O.delete(N),O.size===0){if(this.subscriptions.delete(L),this.send({type:"unsubscribe",topic:L}),this.debug)console.log(`Unsubscribed from topic: ${L}`)}}}publish(L,N){if(this.send({type:"publish",topic:L,data:N}),this.debug)console.log(`Published to topic: ${L}`,N)}async updateAuth(){let N=(await this.getHeaders()).Authorization||"",O=N.startsWith("Bearer ")?N.substring(7).trim():N.trim(),G=O.length>0,F=this.authToken!==null&&this.authToken.trim().length>0;if((G!==F||O!==this.authToken)&&this.isConnected){if(this.authToken=O,this.pendingAuth=G,this.send({type:"authenticate",token:N}),this.debug)if(G)console.log("Updated authentication token, waiting for confirmation");else console.log("Sent empty token for deauthentication"),this.pendingAuth=!1,this.authActions=[]}}}function m(L,N={}){let O=N.fetch||fetch,G=N.WebSocket||(typeof WebSocket<"u"?WebSocket:null),F=N.prefix||"",E=N.debug||!1;if(!G)throw Error("WebSocket is not available in this environment");let R=L||window.location.origin;R=R.endsWith("/")?R.slice(0,-1):R;let T=F?F.startsWith("/")?F:`/${F}`:"",x=T.endsWith("/")?T.slice(0,-1):T,S=`${R.replace(/^http/,"ws")}${x}/ws`,B=new D(S,G,N.headers||{},E),H=async(Z=!0)=>{let M={};if(Z)M["Content-Type"]="application/json";if(typeof N.headers==="function"){let $=await N.headers();return{...M,...$}}else return{...M,...N.headers||{}}},w=async(Z)=>{if(!Z.ok){let $;try{$=await Z.json()}catch{$={error:await Z.text()}}if($?.error&&typeof $.error==="object"){let z=$.error;throw new V(z.message||Z.statusText,Z.status,z.code,z.clientCode,z.data)}let X=$?.error||$?.message||Z.statusText;throw new V(X,Z.status,void 0,void 0,$)}let M=Z.headers.get("Content-Type")||"";if(M.includes("application/json"))return(await Z.json()).data;else if(M.includes("text/"))return Z.text();else return Z.blob()},U=(Z=[])=>{return new Proxy({},{get(M,$){if(typeof $==="symbol")return;if($==="query"||$==="mutation"||$==="formMutation"||$==="subscription"||$==="getStringKey"||$==="getArrayKey"||$==="getNoInputsArrayKey"){let X=Z.join("/"),z=`${R}${x}/${X}`;if(E)console.log(`BRPC ${$} procedure path: ${X}`),console.log(`BRPC ${$} full URL: ${z}`);if($==="query")return async(J)=>{let q=await H(!0);if(E)console.log(`BRPC query request to ${X}`,{input:J,headers:q});let Q=new URL(z);if(J&&typeof J==="object")Object.entries(J).forEach(([Y,A])=>{if(A!==void 0)Q.searchParams.append(Y,String(A))});try{let Y=await O(Q.toString(),{method:"GET",headers:q,credentials:"include"}),A=await w(Y);if(E)console.log(`BRPC query response from ${X}:`,A);return A}catch(Y){throw console.error(`BRPC query error to ${X}:`,Y),Y}};else if($==="mutation")return async(J)=>{let q=await H(!0);if(E)console.log(`BRPC mutation request to ${X}`,{input:J,headers:q});let Q,Y={...q};if(J instanceof FormData)Q=J,delete Y["Content-Type"];else Q=JSON.stringify(J);try{let A=await O(z,{method:"POST",headers:Y,body:Q,credentials:"include"}),_=await w(A);if(E)console.log(`BRPC mutation response from ${X}:`,_);return _}catch(A){throw console.error(`BRPC mutation error to ${X}:`,A),A}};else if($==="formMutation")return async(J)=>{let q=await H(!1);if(E)console.log(`BRPC formMutation request to ${X}`,{input:J,headers:q});let Q=new FormData,Y=(A,_,j)=>{let W=j?`${j}[${A}]`:A;if(_===null||_===void 0)return;else if(_ instanceof File||_ instanceof Blob)Q.append(W,_);else if(Array.isArray(_))_.forEach((I,C)=>{if(I instanceof File||I instanceof Blob)Q.append(`${W}[${C}]`,I);else if(typeof I==="object"&&I!==null)Object.entries(I).forEach(([P,f])=>{Y(P,f,`${W}[${C}]`)});else Q.append(`${W}[${C}]`,String(I))});else if(typeof _==="object"&&_!==null)Object.entries(_).forEach(([I,C])=>{Y(I,C,W)});else Q.append(W,String(_))};Object.entries(J).forEach(([A,_])=>{Y(A,_)});try{let A=await O(z,{method:"POST",headers:q,body:Q,credentials:"include"}),_=await w(A);if(E)console.log(`BRPC formMutation response from ${X}:`,_);return _}catch(A){throw console.error(`BRPC formMutation error to ${X}:`,A),A}};else if($==="subscription")return(J)=>{if(E)console.log(`BRPC subscription to ${X}`);return B.updateAuth(),B.subscribe(X,J)};else if($==="getStringKey")return(J)=>{let q=X;if(!J||Object.keys(J).length===0)return q;let Q=Object.keys(J).sort().reduce((A,_)=>{let j=J[_];if(j!==void 0&&j!==null)A[_]=j;return A},{});if(Object.keys(Q).length===0)return q;let Y=JSON.stringify(Q);return`${q}?${Y}`};else if($==="getArrayKey")return(J)=>{let q=X;if(!J||Object.keys(J).length===0)return[q];let Q=[];if(Object.keys(J).sort().forEach((A)=>{let _=J[A];if(_!==void 0&&_!==null){let j=_;if(typeof _==="boolean"||typeof _==="number")j=String(_);else if(typeof _==="object")j=JSON.stringify(_);Q.push([A,j])}}),Q.length===0)return[q];let Y=Q.flatMap(([A,_])=>[A,_]);return[q,...Y]};else if($==="getNoInputsArrayKey")return()=>{return[X]}}return U([...Z,$])}})},K=U();if(E)console.log("BRPC client created",{baseUrl:R,prefix:T,wsUrl:S});return{routes:K,updateWsAuth:async()=>await B.updateAuth()}}export{g as getObjectUrl,m as createBrpcClient,V as BrpcClientError};
3
+
4
+ //# debugId=12DEE9196908E49D64756E2164756E21
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["..\\src\\client\\storage.ts", "..\\src\\client\\brpc-client-error.ts", "..\\src\\client\\ws-manager.ts", "..\\src\\client\\service.ts"],
4
+ "sourcesContent": [
5
+ "function getObjectUrl<T extends { key: string | null; url: string | null }>(\r\n object?: T | null,\r\n {\r\n provider,\r\n placeholder,\r\n }: { provider?: \"local\" | \"s3\"; placeholder?: string; bucket?: string } = {\r\n provider: \"s3\",\r\n }\r\n) {\r\n if (!object) return placeholder ?? \"PLACEHOLDER\";\r\n\r\n if (object.url) return object.url;\r\n\r\n if (object.key) {\r\n if (provider === \"s3\") {\r\n return `${import.meta.env.VITE_S3_CDN_ENDPOINT}/${object.key}`;\r\n }\r\n return `/storage/${object.key}`;\r\n }\r\n\r\n return placeholder ?? \"PLACEHOLDER\";\r\n}\r\n\r\nexport { getObjectUrl };\r\n",
6
+ "class BrpcClientError extends Error {\r\n readonly status: number;\r\n readonly code?: string;\r\n readonly clientCode?: string;\r\n readonly data?: any;\r\n\r\n constructor(\r\n message: string,\r\n status: number,\r\n code?: string,\r\n clientCode?: string,\r\n data?: any\r\n ) {\r\n super(message);\r\n this.name = \"BrpcClientError\";\r\n this.status = status;\r\n this.code = code;\r\n this.clientCode = clientCode;\r\n this.data = data;\r\n }\r\n\r\n // Helper method to check if this is a specific client error\r\n isClientError(clientCode: string): boolean {\r\n return this.clientCode === clientCode;\r\n }\r\n\r\n // Helper methods for common error types\r\n isUnauthorized(): boolean {\r\n return this.status === 401;\r\n }\r\n\r\n isForbidden(): boolean {\r\n return this.status === 403;\r\n }\r\n\r\n isNotFound(): boolean {\r\n return this.status === 404;\r\n }\r\n\r\n isValidationError(): boolean {\r\n return this.status === 400 || this.code === \"BAD_REQUEST\";\r\n }\r\n}\r\n\r\nexport { BrpcClientError };\r\n",
7
+ "import type { HeadersResolver } from \"./types\";\r\n\r\n// WebSocket Manager with improved authentication handling\r\nclass WebSocketManager {\r\n private ws: WebSocket | null = null;\r\n private subscriptions: Map<string, Set<(data: any) => void>> = new Map();\r\n private messageQueue: any[] = [];\r\n private isConnected: boolean = false;\r\n private reconnectTimeout: any = null;\r\n private WebSocketImpl: typeof WebSocket;\r\n private getHeaders: () => Promise<Record<string, string>>;\r\n private authToken: string | null = null;\r\n private debug: boolean;\r\n private pendingAuth: boolean = false; // Track if we're waiting for auth response\r\n private authActions: (() => void)[] = []; // Actions to perform after successful auth\r\n\r\n constructor(\r\n private baseUrl: string,\r\n WebSocketImpl: typeof WebSocket,\r\n headersResolver: HeadersResolver,\r\n debug: boolean = false\r\n ) {\r\n this.WebSocketImpl = WebSocketImpl;\r\n this.debug = debug && import.meta.env.VITE_NODE_ENV === \"development\";\r\n\r\n // Create headers resolver function\r\n this.getHeaders = async () => {\r\n if (typeof headersResolver === \"function\") {\r\n return await headersResolver();\r\n }\r\n return headersResolver || {};\r\n };\r\n\r\n this.connect();\r\n }\r\n\r\n private async connect() {\r\n try {\r\n // Get latest headers for authentication\r\n const headers = await this.getHeaders();\r\n this.authToken = headers[\"Authorization\"] || null;\r\n\r\n const wsUrl = this.baseUrl;\r\n\r\n if (this.debug) {\r\n console.log(`Connecting to WebSocket: ${wsUrl}`);\r\n }\r\n\r\n this.ws = new this.WebSocketImpl(wsUrl);\r\n\r\n this.ws.onopen = async () => {\r\n if (this.debug) {\r\n console.log(\"WebSocket connection established\");\r\n }\r\n\r\n this.isConnected = true;\r\n\r\n // Clear any pending auth actions from previous connection attempts\r\n this.authActions = [];\r\n\r\n // If we have auth token, send it first and mark auth as pending\r\n if (this.authToken) {\r\n this.pendingAuth = true;\r\n this.send({ type: \"authenticate\", token: this.authToken });\r\n if (this.debug) {\r\n console.log(\"Sent authentication token, waiting for response\");\r\n }\r\n\r\n // Queue resubscriptions to happen after authentication\r\n this.authActions.push(() => {\r\n // Resubscribe to all topics\r\n for (const topic of this.subscriptions.keys()) {\r\n this.send({ type: \"subscribe\", topic });\r\n if (this.debug) {\r\n console.log(`Resubscribed to topic: ${topic}`);\r\n }\r\n }\r\n\r\n // Send any queued messages\r\n if (this.messageQueue.length > 0 && this.debug) {\r\n console.log(\r\n `Sending ${this.messageQueue.length} queued messages`\r\n );\r\n }\r\n\r\n this.messageQueue.forEach((msg) => this.send(msg));\r\n this.messageQueue = [];\r\n });\r\n } else {\r\n // No auth needed, proceed with subscriptions immediately\r\n for (const topic of this.subscriptions.keys()) {\r\n this.send({ type: \"subscribe\", topic });\r\n if (this.debug) {\r\n console.log(`Resubscribed to topic: ${topic}`);\r\n }\r\n }\r\n\r\n // Send any queued messages\r\n if (this.messageQueue.length > 0 && this.debug) {\r\n console.log(`Sending ${this.messageQueue.length} queued messages`);\r\n }\r\n\r\n this.messageQueue.forEach((msg) => this.send(msg));\r\n this.messageQueue = [];\r\n }\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n try {\r\n if (this.debug) {\r\n // console.log(\"Active subscriptions\", this.subscriptions);\r\n console.log(\"WebSocket message received:\", event.data);\r\n }\r\n\r\n const message = JSON.parse(event.data);\r\n\r\n // Handle auth-specific messages\r\n if (message.type === \"auth_success\") {\r\n // Check if authentication was successful or if it was a logout confirmation\r\n const isAuthenticated = message.authenticated !== false;\r\n\r\n if (this.debug) {\r\n console.log(\r\n `WebSocket ${\r\n isAuthenticated ? \"authentication\" : \"deauthentication\"\r\n } successful`\r\n );\r\n }\r\n\r\n // Clear pending auth state\r\n this.pendingAuth = false;\r\n\r\n // Only execute queued actions for successful authentication\r\n if (isAuthenticated) {\r\n // Execute all queued actions that were waiting for authentication\r\n this.authActions.forEach((action) => action());\r\n }\r\n\r\n // Clear action queue\r\n this.authActions = [];\r\n\r\n return;\r\n }\r\n\r\n if (message.type === \"auth_error\") {\r\n console.error(\"WebSocket authentication failed:\", message.error);\r\n\r\n // Clear pending auth state but don't process queued actions\r\n this.pendingAuth = false;\r\n this.authActions = [];\r\n\r\n return;\r\n }\r\n\r\n if (this.debug) {\r\n console.log(\"Got new message\", message);\r\n }\r\n\r\n if (message.topic && this.subscriptions.has(message.topic)) {\r\n const callbacks = this.subscriptions.get(message.topic);\r\n if (this.debug) {\r\n console.log(\"Calling subscription callbacks\");\r\n }\r\n callbacks?.forEach((callback) => callback(message.data));\r\n } else if (message.error) {\r\n console.error(\"WebSocket error:\", message.error);\r\n } else {\r\n // Log unknown message formats to help debug\r\n console.warn(\"Unhandled WebSocket message format:\", message);\r\n }\r\n } catch (error) {\r\n if (this.debug) {\r\n console.error(\"Error processing WebSocket message:\", error);\r\n console.error(\"Raw message:\", event.data);\r\n }\r\n }\r\n };\r\n\r\n this.ws.onclose = (event) => {\r\n this.isConnected = false;\r\n this.pendingAuth = false; // Reset auth state\r\n\r\n if (this.debug) {\r\n console.log(\r\n `WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason}`\r\n );\r\n }\r\n\r\n // Try to reconnect after a delay\r\n this.reconnectTimeout = setTimeout(() => this.connect(), 2000);\r\n };\r\n\r\n this.ws.onerror = (error) => {\r\n if (this.debug) {\r\n console.log(\"WebSocket error:\", error);\r\n }\r\n };\r\n } catch (error) {\r\n if (this.debug) {\r\n console.log(\"Failed to create WebSocket connection:\", error);\r\n }\r\n this.pendingAuth = false;\r\n // Try to reconnect after a delay\r\n this.reconnectTimeout = setTimeout(() => this.connect(), 2000);\r\n }\r\n }\r\n\r\n public disconnect() {\r\n if (this.reconnectTimeout) {\r\n clearTimeout(this.reconnectTimeout);\r\n this.reconnectTimeout = null;\r\n }\r\n\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n\r\n this.isConnected = false;\r\n this.pendingAuth = false;\r\n this.authActions = [];\r\n this.subscriptions.clear();\r\n }\r\n\r\n public send(message: any) {\r\n if (this.isConnected && this.ws?.readyState === this.WebSocketImpl.OPEN) {\r\n // If authentication is pending and this isn't an auth message, queue it\r\n if (this.pendingAuth && message.type !== \"authenticate\") {\r\n this.messageQueue.push(message);\r\n if (this.debug) {\r\n console.log(\r\n \"Message queued until authentication completes:\",\r\n message\r\n );\r\n }\r\n return;\r\n }\r\n\r\n const messageStr = JSON.stringify(message);\r\n this.ws.send(messageStr);\r\n\r\n if (this.debug) {\r\n console.log(\"WebSocket message sent:\", messageStr);\r\n }\r\n } else {\r\n this.messageQueue.push(message);\r\n\r\n if (this.debug) {\r\n console.log(\"WebSocket message queued (not connected):\", message);\r\n }\r\n }\r\n }\r\n\r\n public subscribe(topic: string, callback: (data: any) => void) {\r\n if (!this.subscriptions.has(topic)) {\r\n this.subscriptions.set(topic, new Set());\r\n\r\n // If we're connected, send the subscription (with auth awareness)\r\n if (this.isConnected) {\r\n if (this.pendingAuth) {\r\n // Queue the subscription for after auth\r\n this.authActions.push(() => {\r\n this.send({ type: \"subscribe\", topic });\r\n if (this.debug) {\r\n console.log(`Subscribed to topic after auth: ${topic}`);\r\n }\r\n });\r\n } else {\r\n // Send immediately\r\n this.send({ type: \"subscribe\", topic });\r\n if (this.debug) {\r\n console.log(`Subscribed to topic: ${topic}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n this.subscriptions.get(topic)!.add(callback);\r\n\r\n return {\r\n unsubscribe: () => this.unsubscribe(topic, callback),\r\n publish: (data: any) => this.publish(topic, data),\r\n };\r\n }\r\n\r\n private unsubscribe(topic: string, callback: (data: any) => void) {\r\n const callbacks = this.subscriptions.get(topic);\r\n if (callbacks) {\r\n callbacks.delete(callback);\r\n if (callbacks.size === 0) {\r\n this.subscriptions.delete(topic);\r\n this.send({ type: \"unsubscribe\", topic });\r\n\r\n if (this.debug) {\r\n console.log(`Unsubscribed from topic: ${topic}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n public publish(topic: string, data: any) {\r\n this.send({ type: \"publish\", topic, data });\r\n\r\n if (this.debug) {\r\n console.log(`Published to topic: ${topic}`, data);\r\n }\r\n }\r\n\r\n // Method to update auth token when it changes\r\n public async updateAuth() {\r\n const headers = await this.getHeaders();\r\n const authHeader = headers[\"Authorization\"] || \"\";\r\n\r\n // Extract token from header - may be empty (\"Bearer \")\r\n const newToken = authHeader.startsWith(\"Bearer \")\r\n ? authHeader.substring(7).trim()\r\n : authHeader.trim();\r\n\r\n const hasValidToken = newToken.length > 0;\r\n const hadValidToken =\r\n this.authToken !== null && this.authToken.trim().length > 0;\r\n\r\n // If token status changed and we're connected, handle the change\r\n if (\r\n (hasValidToken !== hadValidToken || newToken !== this.authToken) &&\r\n this.isConnected\r\n ) {\r\n // Update stored token\r\n this.authToken = newToken;\r\n\r\n // Always send authenticate message, but with empty token when logging out\r\n this.pendingAuth = hasValidToken;\r\n this.send({ type: \"authenticate\", token: authHeader });\r\n\r\n if (this.debug) {\r\n if (hasValidToken) {\r\n console.log(\"Updated authentication token, waiting for confirmation\");\r\n } else {\r\n console.log(\"Sent empty token for deauthentication\");\r\n // Since we're not expecting auth confirmation for logout, clear pending state\r\n this.pendingAuth = false;\r\n this.authActions = [];\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport { WebSocketManager };\r\n",
8
+ "import { BrpcClientError } from \"./brpc-client-error\";\r\nimport type {\r\n HeadersResolver,\r\n BrpcClient,\r\n InferClientRoutes,\r\n BrpcClientOptions,\r\n} from \"./types\";\r\nimport { WebSocketManager } from \"./ws-manager\";\r\n\r\n/**\r\n * Creates a type-safe client for the BRPC API\r\n * @param baseUrl The base URL of the BRPC server\r\n * @param options Client configuration options\r\n * @returns A client object that mirrors the server routes\r\n */\r\nexport function createBrpcClient<TRoutesStructure>(\r\n baseUrl: string,\r\n options: BrpcClientOptions = {}\r\n): BrpcClient<TRoutesStructure> {\r\n const fetchImpl = options.fetch || fetch;\r\n const WebSocketImpl =\r\n options.WebSocket || (typeof WebSocket !== \"undefined\" ? WebSocket : null);\r\n const prefix = options.prefix || \"\";\r\n const debug = options.debug || false;\r\n\r\n if (!WebSocketImpl) {\r\n throw new Error(\"WebSocket is not available in this environment\");\r\n }\r\n\r\n // Properly format the base URL\r\n let formattedBaseUrl = baseUrl || window.location.origin;\r\n // Remove trailing slash if present\r\n formattedBaseUrl = formattedBaseUrl.endsWith(\"/\")\r\n ? formattedBaseUrl.slice(0, -1)\r\n : formattedBaseUrl;\r\n\r\n // Ensure prefix always starts with a slash but doesn't include trailing slash\r\n const prefixPath = prefix\r\n ? prefix.startsWith(\"/\")\r\n ? prefix\r\n : `/${prefix}`\r\n : \"\";\r\n const cleanPrefixPath = prefixPath.endsWith(\"/\")\r\n ? prefixPath.slice(0, -1)\r\n : prefixPath;\r\n\r\n // Create WebSocket URL with proper path joining\r\n const wsUrl = `${formattedBaseUrl.replace(\r\n /^http/,\r\n \"ws\"\r\n )}${cleanPrefixPath}/ws`;\r\n\r\n // Create WebSocket manager with headers resolver\r\n const wsManager = new WebSocketManager(\r\n wsUrl,\r\n WebSocketImpl,\r\n options.headers || {},\r\n debug\r\n );\r\n\r\n // Helper to resolve headers before each request\r\n const resolveHeaders = async (\r\n defaultContentType = true\r\n ): Promise<Record<string, string>> => {\r\n const baseHeaders: Record<string, string> = {};\r\n\r\n // Add Content-Type by default\r\n if (defaultContentType) {\r\n baseHeaders[\"Content-Type\"] = \"application/json\";\r\n }\r\n\r\n // Resolve dynamic or static headers\r\n if (typeof options.headers === \"function\") {\r\n const dynamicHeaders = await options.headers();\r\n return { ...baseHeaders, ...dynamicHeaders };\r\n } else {\r\n return { ...baseHeaders, ...(options.headers || {}) };\r\n }\r\n };\r\n\r\n // Helper to handle HTTP responses\r\n const handleResponse = async (response: Response) => {\r\n if (!response.ok) {\r\n let errorData;\r\n try {\r\n errorData = await response.json();\r\n } catch {\r\n errorData = { error: await response.text() };\r\n }\r\n\r\n // Handle the new BRPCError format from server\r\n if (errorData?.error && typeof errorData.error === \"object\") {\r\n const serverError = errorData.error;\r\n\r\n throw new BrpcClientError(\r\n serverError.message || response.statusText,\r\n response.status,\r\n serverError.code,\r\n serverError.clientCode,\r\n serverError.data\r\n );\r\n }\r\n\r\n // Handle legacy error format or simple string errors\r\n const errorMessage =\r\n errorData?.error || errorData?.message || response.statusText;\r\n\r\n throw new BrpcClientError(\r\n errorMessage,\r\n response.status,\r\n undefined,\r\n undefined,\r\n errorData\r\n );\r\n }\r\n\r\n // Check content type to determine how to handle the response\r\n const contentType = response.headers.get(\"Content-Type\") || \"\";\r\n\r\n if (contentType.includes(\"application/json\")) {\r\n const result = await response.json();\r\n return result.data;\r\n } else if (contentType.includes(\"text/\")) {\r\n return response.text();\r\n } else {\r\n return response.blob();\r\n }\r\n };\r\n\r\n // Create a proxy for a specific path\r\n const createProxy = (pathSegments: string[] = []): any => {\r\n return new Proxy(\r\n {},\r\n {\r\n get(_, key: string | symbol) {\r\n if (typeof key === \"symbol\") return undefined;\r\n\r\n // Special methods for procedures\r\n if (\r\n key === \"query\" ||\r\n key === \"mutation\" ||\r\n key === \"formMutation\" ||\r\n key === \"subscription\" ||\r\n key === \"getStringKey\" ||\r\n key === \"getArrayKey\" ||\r\n key === \"getNoInputsArrayKey\"\r\n ) {\r\n // The path up to this point is the procedure path\r\n const procedurePath = pathSegments.join(\"/\");\r\n const fullUrl = `${formattedBaseUrl}${cleanPrefixPath}/${procedurePath}`;\r\n\r\n if (debug) {\r\n console.log(`BRPC ${key} procedure path: ${procedurePath}`);\r\n console.log(`BRPC ${key} full URL: ${fullUrl}`);\r\n }\r\n\r\n if (key === \"query\") {\r\n return async (input: any) => {\r\n // Get fresh headers for this request\r\n const headers = await resolveHeaders(true);\r\n\r\n if (debug) {\r\n console.log(`BRPC query request to ${procedurePath}`, {\r\n input,\r\n headers,\r\n });\r\n }\r\n\r\n const url = new URL(fullUrl);\r\n\r\n // Add input parameters to URL for GET request\r\n if (input && typeof input === \"object\") {\r\n Object.entries(input).forEach(([k, v]) => {\r\n if (v !== undefined) {\r\n url.searchParams.append(k, String(v));\r\n }\r\n });\r\n }\r\n\r\n try {\r\n const response = await fetchImpl(url.toString(), {\r\n method: \"GET\",\r\n headers,\r\n credentials: \"include\", //always include credentials\r\n });\r\n\r\n const result = await handleResponse(response);\r\n\r\n if (debug) {\r\n console.log(\r\n `BRPC query response from ${procedurePath}:`,\r\n result\r\n );\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n console.error(`BRPC query error to ${procedurePath}:`, error);\r\n throw error;\r\n }\r\n };\r\n } else if (key === \"mutation\") {\r\n return async (input: any) => {\r\n // Get fresh headers for this request\r\n const headers = await resolveHeaders(true);\r\n\r\n if (debug) {\r\n console.log(`BRPC mutation request to ${procedurePath}`, {\r\n input,\r\n headers,\r\n });\r\n }\r\n\r\n let body;\r\n const requestHeaders = { ...headers };\r\n\r\n // Handle FormData for file uploads\r\n if (input instanceof FormData) {\r\n body = input;\r\n // Let the browser set the correct Content-Type for FormData\r\n delete requestHeaders[\"Content-Type\"];\r\n } else {\r\n body = JSON.stringify(input);\r\n }\r\n\r\n try {\r\n const response = await fetchImpl(fullUrl, {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body,\r\n credentials: \"include\",\r\n });\r\n\r\n const result = await handleResponse(response);\r\n\r\n if (debug) {\r\n console.log(\r\n `BRPC mutation response from ${procedurePath}:`,\r\n result\r\n );\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n console.error(\r\n `BRPC mutation error to ${procedurePath}:`,\r\n error\r\n );\r\n throw error;\r\n }\r\n };\r\n } else if (key === \"formMutation\") {\r\n return async (input: Record<string, any>) => {\r\n // Get fresh headers for this request (no Content-Type for FormData)\r\n const headers = await resolveHeaders(false);\r\n\r\n if (debug) {\r\n console.log(`BRPC formMutation request to ${procedurePath}`, {\r\n input,\r\n headers,\r\n });\r\n }\r\n\r\n // Convert object input to FormData\r\n const formData = new FormData();\r\n\r\n // Helper function to append values to FormData\r\n const appendToFormData = (\r\n key: string,\r\n value: any,\r\n parentKey?: string\r\n ) => {\r\n const fullKey = parentKey ? `${parentKey}[${key}]` : key;\r\n\r\n if (value === null || value === undefined) {\r\n // Skip null/undefined values\r\n return;\r\n } else if (value instanceof File || value instanceof Blob) {\r\n // Handle files directly\r\n formData.append(fullKey, value);\r\n } else if (Array.isArray(value)) {\r\n // Handle arrays\r\n value.forEach((item, index) => {\r\n if (item instanceof File || item instanceof Blob) {\r\n formData.append(`${fullKey}[${index}]`, item);\r\n } else if (typeof item === \"object\" && item !== null) {\r\n Object.entries(item).forEach(([subKey, subValue]) => {\r\n appendToFormData(\r\n subKey,\r\n subValue,\r\n `${fullKey}[${index}]`\r\n );\r\n });\r\n } else {\r\n formData.append(`${fullKey}[${index}]`, String(item));\r\n }\r\n });\r\n } else if (typeof value === \"object\" && value !== null) {\r\n // Handle nested objects\r\n Object.entries(value).forEach(([subKey, subValue]) => {\r\n appendToFormData(subKey, subValue, fullKey);\r\n });\r\n } else {\r\n // Handle primitive values\r\n formData.append(fullKey, String(value));\r\n }\r\n };\r\n\r\n // Convert input object to FormData\r\n Object.entries(input).forEach(([key, value]) => {\r\n appendToFormData(key, value);\r\n });\r\n\r\n try {\r\n const response = await fetchImpl(fullUrl, {\r\n method: \"POST\",\r\n headers, // No Content-Type header for FormData\r\n body: formData,\r\n credentials: \"include\",\r\n });\r\n\r\n const result = await handleResponse(response);\r\n\r\n if (debug) {\r\n console.log(\r\n `BRPC formMutation response from ${procedurePath}:`,\r\n result\r\n );\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n console.error(\r\n `BRPC formMutation error to ${procedurePath}:`,\r\n error\r\n );\r\n throw error;\r\n }\r\n };\r\n } else if (key === \"subscription\") {\r\n return (callback: (data: any) => void) => {\r\n if (debug) {\r\n console.log(`BRPC subscription to ${procedurePath}`);\r\n }\r\n\r\n // Update WebSocket auth if needed before subscribing\r\n wsManager.updateAuth();\r\n\r\n // Return an object with unsubscribe and publish methods\r\n return wsManager.subscribe(procedurePath, callback);\r\n };\r\n } else if (key === \"getStringKey\") {\r\n return (input?: any) => {\r\n // Create a deterministic key based on procedure path and input\r\n const baseKey = procedurePath;\r\n\r\n if (!input || Object.keys(input).length === 0) {\r\n return baseKey;\r\n }\r\n\r\n // Sort input keys for deterministic key generation\r\n const sortedInput = Object.keys(input)\r\n .sort()\r\n .reduce((result, key) => {\r\n const value = input[key];\r\n if (value !== undefined && value !== null) {\r\n result[key] = value;\r\n }\r\n return result;\r\n }, {} as Record<string, any>);\r\n\r\n // Only add input hash if there are actual values\r\n if (Object.keys(sortedInput).length === 0) {\r\n return baseKey;\r\n }\r\n\r\n // Create a simple hash from the sorted input\r\n const inputString = JSON.stringify(sortedInput);\r\n return `${baseKey}?${inputString}`;\r\n };\r\n } else if (key === \"getArrayKey\") {\r\n return (input?: any) => {\r\n // Use the full procedure path as the first segment for easier invalidation\r\n const basePath = procedurePath;\r\n\r\n if (!input || Object.keys(input).length === 0) {\r\n return [basePath];\r\n }\r\n\r\n // Normalize and sort input keys for deterministic key generation\r\n const normalizedPairs: Array<[string, any]> = [];\r\n\r\n Object.keys(input)\r\n .sort()\r\n .forEach((key) => {\r\n const value = input[key];\r\n if (value !== undefined && value !== null) {\r\n // Normalize values for consistent comparison\r\n let normalizedValue = value;\r\n\r\n // Convert primitives to strings for consistency\r\n if (\r\n typeof value === \"boolean\" ||\r\n typeof value === \"number\"\r\n ) {\r\n normalizedValue = String(value);\r\n } else if (typeof value === \"object\") {\r\n // For objects/arrays, use JSON representation\r\n normalizedValue = JSON.stringify(value);\r\n }\r\n\r\n normalizedPairs.push([key, normalizedValue]);\r\n }\r\n });\r\n\r\n // Only add input segments if there are actual values\r\n if (normalizedPairs.length === 0) {\r\n return [basePath];\r\n }\r\n\r\n // Create individual segments for each input pair\r\n // This allows for better pattern matching\r\n const inputSegments = normalizedPairs.flatMap(\r\n ([key, value]) => [key, value]\r\n );\r\n\r\n return [basePath, ...inputSegments];\r\n };\r\n } else if (key === \"getNoInputsArrayKey\") {\r\n return () => {\r\n // Always return just the procedure path, ignoring any inputs\r\n // Perfect for invalidating all variants of a procedure\r\n return [procedurePath];\r\n };\r\n }\r\n }\r\n\r\n // Continue traversing the path for nested routes\r\n return createProxy([...pathSegments, key]);\r\n },\r\n }\r\n );\r\n };\r\n\r\n // Create the base proxy\r\n const clientProxy = createProxy() as InferClientRoutes<TRoutesStructure>;\r\n\r\n if (debug) {\r\n console.log(\"BRPC client created\", {\r\n baseUrl: formattedBaseUrl,\r\n prefix: prefixPath,\r\n wsUrl: wsUrl,\r\n });\r\n }\r\n\r\n return {\r\n routes: clientProxy,\r\n updateWsAuth: async () => await wsManager.updateAuth(),\r\n //todo add storage methods\r\n };\r\n}\r\n"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "12DEE9196908E49D64756E2164756E21",
12
+ "names": []
13
+ }
@@ -0,0 +1 @@
1
+ export * from "./use-subscription";
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{useCallback as z,useEffect as A,useRef as B}from"react";function G(j,q){let m=B(null);return A(()=>{let{publish:x,unsubscribe:w}=j(q||((y)=>console.log("New data received",y)));return m.current=x,()=>{m.current=null,w()}},[j,q]),{publish:z((x)=>{m.current?.(x)},[])}}export{G as useSubscription};
3
+
4
+ //# debugId=12418FDC428A9F4964756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["..\\src\\client\\react\\use-subscription.tsx"],
4
+ "sourcesContent": [
5
+ "import { useCallback, useEffect, useRef } from \"react\";\r\n\r\n/**\r\n * Custom hook for managing brpc subscriptions\r\n * @param subscription A function that sets up a subscription and returns publish/unsubscribe handlers\r\n * @param callback Optional callback function to handle incoming data\r\n * @returns A stable publish function that can be called directly\r\n */\r\nfunction useSubscription<TInput, TOutput>(\r\n subscription: (callback: (data: TOutput) => void) => {\r\n publish: (data: TInput) => void;\r\n unsubscribe: () => void;\r\n },\r\n callback?: (data: TOutput) => void\r\n) {\r\n // Create a ref to store the publish function\r\n const publishRef = useRef<((data: TInput) => void) | null>(null);\r\n\r\n useEffect(() => {\r\n // Set up the subscription with the provided or default callback\r\n const { publish, unsubscribe } = subscription(\r\n callback || ((data) => console.log(\"New data received\", data))\r\n );\r\n\r\n // Store the publish function in the ref\r\n publishRef.current = publish;\r\n\r\n // Clean up the subscription when the component unmounts\r\n return () => {\r\n publishRef.current = null;\r\n unsubscribe();\r\n };\r\n }, [subscription, callback]);\r\n\r\n // Create a stable function that delegates to the current ref value\r\n const stablePublish = useCallback((data: TInput) => {\r\n publishRef.current?.(data);\r\n }, []);\r\n\r\n return { publish: stablePublish };\r\n}\r\n\r\nexport { useSubscription };\r\n"
6
+ ],
7
+ "mappings": ";AAAA,sBAAS,eAAa,YAAW,cAQjC,SAAS,CAAgC,CACvC,EAIA,EACA,CAEA,IAAM,EAAa,EAAwC,IAAI,EAuB/D,OArBA,EAAU,IAAM,CAEd,IAAQ,UAAS,eAAgB,EAC/B,IAAa,CAAC,IAAS,QAAQ,IAAI,oBAAqB,CAAI,EAC9D,EAMA,OAHA,EAAW,QAAU,EAGd,IAAM,CACX,EAAW,QAAU,KACrB,EAAY,IAEb,CAAC,EAAc,CAAQ,CAAC,EAOpB,CAAE,QAJa,EAAY,CAAC,IAAiB,CAClD,EAAW,UAAU,CAAI,GACxB,CAAC,CAAC,CAE2B",
8
+ "debugId": "12418FDC428A9F4964756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Custom hook for managing brpc subscriptions
3
+ * @param subscription A function that sets up a subscription and returns publish/unsubscribe handlers
4
+ * @param callback Optional callback function to handle incoming data
5
+ * @returns A stable publish function that can be called directly
6
+ */
7
+ declare function useSubscription<TInput, TOutput>(subscription: (callback: (data: TOutput) => void) => {
8
+ publish: (data: TInput) => void;
9
+ unsubscribe: () => void;
10
+ }, callback?: (data: TOutput) => void): {
11
+ publish: (data: TInput) => void;
12
+ };
13
+ export { useSubscription };
@@ -0,0 +1,8 @@
1
+ import type { BrpcClient, BrpcClientOptions } from "./types";
2
+ /**
3
+ * Creates a type-safe client for the BRPC API
4
+ * @param baseUrl The base URL of the BRPC server
5
+ * @param options Client configuration options
6
+ * @returns A client object that mirrors the server routes
7
+ */
8
+ export declare function createBrpcClient<TRoutesStructure>(baseUrl: string, options?: BrpcClientOptions): BrpcClient<TRoutesStructure>;
@@ -0,0 +1,9 @@
1
+ declare function getObjectUrl<T extends {
2
+ key: string | null;
3
+ url: string | null;
4
+ }>(object?: T | null, { provider, placeholder, }?: {
5
+ provider?: "local" | "s3";
6
+ placeholder?: string;
7
+ bucket?: string;
8
+ }): string;
9
+ export { getObjectUrl };
@@ -0,0 +1,93 @@
1
+ import { z } from "zod";
2
+ import type { BaseProcedure } from "../types";
3
+ export type InferProcedureInput<T> = T extends {
4
+ _input: z.ZodType<infer I>;
5
+ } ? I : never;
6
+ export type InferProcedureOutput<T> = T extends {
7
+ _output: infer O;
8
+ } ? O : never;
9
+ export type InferProcedureType<T> = T extends {
10
+ _type: infer P;
11
+ } ? P : never;
12
+ export type InferRouterOutput<T> = {
13
+ [K in keyof T]: T[K] extends BaseProcedure ? InferProcedureOutput<T[K]> : T[K] extends Record<string, any> ? InferRouterOutput<T[K]> : never;
14
+ };
15
+ export type IsOptionalInput<T> = undefined extends InferProcedureInput<T> ? true : {} extends InferProcedureInput<T> & {} ? true : false;
16
+ export type SubscriptionHandlers<InputType, _OutputType> = {
17
+ unsubscribe: () => void;
18
+ publish: (data: InputType) => void;
19
+ };
20
+ export type ProcedureMethods<T extends BaseProcedure> = T["_type"] extends "query" | "streamQuery" | "file" | "html" ? IsOptionalInput<T> extends true ? {
21
+ query: (input?: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
22
+ getStringKey: (input?: InferProcedureInput<T>) => string;
23
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
24
+ getNoInputsArrayKey: () => (string | number | boolean)[];
25
+ } : {
26
+ query: (input: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
27
+ getStringKey: (input?: InferProcedureInput<T>) => string;
28
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
29
+ getNoInputsArrayKey: () => (string | number | boolean)[];
30
+ } : T["_type"] extends "mutation" | "streamMutation" ? IsOptionalInput<T> extends true ? {
31
+ mutation: (input?: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
32
+ getStringKey: (input?: InferProcedureInput<T>) => string;
33
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
34
+ getNoInputsArrayKey: () => (string | number | boolean)[];
35
+ } : {
36
+ mutation: (input: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
37
+ getStringKey: (input?: InferProcedureInput<T>) => string;
38
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
39
+ getNoInputsArrayKey: () => (string | number | boolean)[];
40
+ } : T["_type"] extends "formMutation" ? IsOptionalInput<T> extends true ? {
41
+ formMutation: (input?: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
42
+ getStringKey: (input?: InferProcedureInput<T>) => string;
43
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
44
+ getNoInputsArrayKey: () => (string | number | boolean)[];
45
+ } : {
46
+ formMutation: (input: InferProcedureInput<T>) => Promise<InferProcedureOutput<T>>;
47
+ getStringKey: (input?: InferProcedureInput<T>) => string;
48
+ getArrayKey: (input?: InferProcedureInput<T>) => (string | number | boolean)[];
49
+ getNoInputsArrayKey: () => (string | number | boolean)[];
50
+ } : T["_type"] extends "subscription" ? {
51
+ subscription: (callback: (data: InferProcedureOutput<T>) => void) => SubscriptionHandlers<InferProcedureInput<T>, InferProcedureOutput<T>>;
52
+ getStringKey: (input?: InferProcedureInput<T>) => string;
53
+ getArrayKey: (input?: InferProcedureInput<T>) => string[];
54
+ } : never;
55
+ export type InferClientRoutes<T> = {
56
+ [K in keyof T]: T[K] extends BaseProcedure ? ProcedureMethods<T[K]> : T[K] extends Record<string, any> ? InferClientRoutes<T[K]> : never;
57
+ };
58
+ export interface BrpcClientOptions {
59
+ /**
60
+ * Headers to include with each request. Can be either a static object or
61
+ * an async function that returns headers.
62
+ */
63
+ headers?: HeadersResolver;
64
+ /**
65
+ * Custom fetch implementation to use. Defaults to the global fetch.
66
+ */
67
+ fetch?: typeof fetch;
68
+ /**
69
+ * Custom WebSocket implementation. Defaults to the global WebSocket.
70
+ */
71
+ WebSocket?: typeof WebSocket;
72
+ /**
73
+ * API path prefix. Will be prepended to all request paths.
74
+ * Example: "/api" for "https://example.com/api/endpoint"
75
+ */
76
+ prefix?: string;
77
+ /**
78
+ * Enable debug logging for requests, responses, and WebSocket communication.
79
+ */
80
+ debug?: boolean;
81
+ }
82
+ /**
83
+ * Creates a type-safe client for the BRPC API
84
+ * @param baseUrl The base URL of the BRPC server
85
+ * @param options Client configuration options
86
+ * @returns A client object that mirrors the server routes
87
+ */
88
+ export type BrpcClient<T> = {
89
+ routes: InferClientRoutes<T>;
90
+ updateWsAuth: () => Promise<void>;
91
+ };
92
+ export type Headers = Record<string, string>;
93
+ export type HeadersResolver = Headers | (() => Promise<Headers> | Headers);
@@ -0,0 +1,27 @@
1
+ import type { HeadersResolver } from "./types";
2
+ declare class WebSocketManager {
3
+ private baseUrl;
4
+ private ws;
5
+ private subscriptions;
6
+ private messageQueue;
7
+ private isConnected;
8
+ private reconnectTimeout;
9
+ private WebSocketImpl;
10
+ private getHeaders;
11
+ private authToken;
12
+ private debug;
13
+ private pendingAuth;
14
+ private authActions;
15
+ constructor(baseUrl: string, WebSocketImpl: typeof WebSocket, headersResolver: HeadersResolver, debug?: boolean);
16
+ private connect;
17
+ disconnect(): void;
18
+ send(message: any): void;
19
+ subscribe(topic: string, callback: (data: any) => void): {
20
+ unsubscribe: () => void;
21
+ publish: (data: any) => void;
22
+ };
23
+ private unsubscribe;
24
+ publish(topic: string, data: any): void;
25
+ updateAuth(): Promise<void>;
26
+ }
27
+ export { WebSocketManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mateosuarezdev/brpc",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "A Type-Safe, Flexible Web application framework for Bun",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -16,6 +16,16 @@
16
16
  "types": "./dist/storage/index.d.ts",
17
17
  "import": "./dist/storage/index.js",
18
18
  "require": "./dist/storage/index.cjs"
19
+ },
20
+ "./client": {
21
+ "types": "./dist/client/index.d.ts",
22
+ "import": "./dist/client/index.js",
23
+ "require": "./dist/client/index.cjs"
24
+ },
25
+ "./client/react": {
26
+ "types": "./dist/client/react/index.d.ts",
27
+ "import": "./dist/client/react/index.js",
28
+ "require": "./dist/client/react/index.cjs"
19
29
  }
20
30
  },
21
31
  "files": [
@@ -63,6 +73,12 @@
63
73
  "zod": "^3.23.8"
64
74
  },
65
75
  "peerDependenciesMeta": {
76
+ "react": {
77
+ "optional": true
78
+ },
79
+ "react-dom": {
80
+ "optional": true
81
+ },
66
82
  "sharp": {
67
83
  "optional": true
68
84
  },
@@ -72,6 +88,10 @@
72
88
  },
73
89
  "devDependencies": {
74
90
  "@types/bun": "^1.2.23",
91
+ "@types/react": "^19.2.2",
92
+ "@types/react-dom": "^19.2.2",
93
+ "react": "^19.2.0",
94
+ "react-dom": "^19.2.0",
75
95
  "rimraf": "^6.0.1",
76
96
  "sharp": "^0.34.4",
77
97
  "typescript": "^5.9.3",