Files
ResolveSpec/resolvespec-js/dist/index.cjs
Hein dc85008d7f feat(api): add ResolveSpec and WebSocket client implementations
- Introduced ResolveSpecClient for REST API interactions.
- Added WebSocketClient for real-time communication.
- Created types and utility functions for both clients.
- Removed deprecated types and example files.
- Configured TypeScript and Vite for building the library.
2026-02-15 15:17:39 +02:00

2 lines
10 KiB
JavaScript

"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("uuid"),d=new Map;function w(n){const e=n.baseUrl;let t=d.get(e);return t||(t=new g(n),d.set(e,t)),t}class g{constructor(e){this.config=e}buildUrl(e,t,s){let r=`${this.config.baseUrl}/${e}/${t}`;return s&&(r+=`/${s}`),r}baseHeaders(){const e={"Content-Type":"application/json"};return this.config.token&&(e.Authorization=`Bearer ${this.config.token}`),e}async fetchWithError(e,t){const s=await fetch(e,t),r=await s.json();if(!s.ok)throw new Error(r.error?.message||"An error occurred");return r}async getMetadata(e,t){const s=this.buildUrl(e,t);return this.fetchWithError(s,{method:"GET",headers:this.baseHeaders()})}async read(e,t,s,r){const i=typeof s=="number"||typeof s=="string"?String(s):void 0,a=this.buildUrl(e,t,i),c={operation:"read",id:Array.isArray(s)?s:void 0,options:r};return this.fetchWithError(a,{method:"POST",headers:this.baseHeaders(),body:JSON.stringify(c)})}async create(e,t,s,r){const i=this.buildUrl(e,t),a={operation:"create",data:s,options:r};return this.fetchWithError(i,{method:"POST",headers:this.baseHeaders(),body:JSON.stringify(a)})}async update(e,t,s,r,i){const a=typeof r=="number"||typeof r=="string"?String(r):void 0,c=this.buildUrl(e,t,a),o={operation:"update",id:Array.isArray(r)?r:void 0,data:s,options:i};return this.fetchWithError(c,{method:"POST",headers:this.baseHeaders(),body:JSON.stringify(o)})}async delete(e,t,s){const r=this.buildUrl(e,t,String(s)),i={operation:"delete"};return this.fetchWithError(r,{method:"POST",headers:this.baseHeaders(),body:JSON.stringify(i)})}}const f=new Map;function H(n){const e=n.url;let t=f.get(e);return t||(t=new S(n),f.set(e,t)),t}class S{constructor(e){this.ws=null,this.messageHandlers=new Map,this.subscriptions=new Map,this.eventListeners={},this.state="disconnected",this.reconnectAttempts=0,this.reconnectTimer=null,this.heartbeatTimer=null,this.isManualClose=!1,this.config={url:e.url,reconnect:e.reconnect??!0,reconnectInterval:e.reconnectInterval??3e3,maxReconnectAttempts:e.maxReconnectAttempts??10,heartbeatInterval:e.heartbeatInterval??3e4,debug:e.debug??!1}}async connect(){if(this.ws?.readyState===WebSocket.OPEN){this.log("Already connected");return}return this.isManualClose=!1,this.setState("connecting"),new Promise((e,t)=>{try{this.ws=new WebSocket(this.config.url),this.ws.onopen=()=>{this.log("Connected to WebSocket server"),this.setState("connected"),this.reconnectAttempts=0,this.startHeartbeat(),this.emit("connect"),e()},this.ws.onmessage=s=>{this.handleMessage(s.data)},this.ws.onerror=s=>{this.log("WebSocket error:",s);const r=new Error("WebSocket connection error");this.emit("error",r),t(r)},this.ws.onclose=s=>{this.log("WebSocket closed:",s.code,s.reason),this.stopHeartbeat(),this.setState("disconnected"),this.emit("disconnect",s),this.config.reconnect&&!this.isManualClose&&this.reconnectAttempts<this.config.maxReconnectAttempts&&(this.reconnectAttempts++,this.log(`Reconnection attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts}`),this.setState("reconnecting"),this.reconnectTimer=setTimeout(()=>{this.connect().catch(r=>{this.log("Reconnection failed:",r)})},this.config.reconnectInterval))}}catch(s){t(s)}})}disconnect(){this.isManualClose=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stopHeartbeat(),this.ws&&(this.setState("disconnecting"),this.ws.close(),this.ws=null),this.setState("disconnected"),this.messageHandlers.clear()}async request(e,t,s){this.ensureConnected();const r=l.v4(),i={id:r,type:"request",operation:e,entity:t,schema:s?.schema,record_id:s?.record_id,data:s?.data,options:s?.options};return new Promise((a,c)=>{this.messageHandlers.set(r,o=>{o.success?a(o.data):c(new Error(o.error?.message||"Request failed"))}),this.send(i),setTimeout(()=>{this.messageHandlers.has(r)&&(this.messageHandlers.delete(r),c(new Error("Request timeout")))},3e4)})}async read(e,t){return this.request("read",e,{schema:t?.schema,record_id:t?.record_id,options:{filters:t?.filters,columns:t?.columns,sort:t?.sort,preload:t?.preload,limit:t?.limit,offset:t?.offset}})}async create(e,t,s){return this.request("create",e,{schema:s?.schema,data:t})}async update(e,t,s,r){return this.request("update",e,{schema:r?.schema,record_id:t,data:s})}async delete(e,t,s){await this.request("delete",e,{schema:s?.schema,record_id:t})}async meta(e,t){return this.request("meta",e,{schema:t?.schema})}async subscribe(e,t,s){this.ensureConnected();const r=l.v4(),i={id:r,type:"subscription",operation:"subscribe",entity:e,schema:s?.schema,options:{filters:s?.filters}};return new Promise((a,c)=>{this.messageHandlers.set(r,o=>{if(o.success&&o.data?.subscription_id){const h=o.data.subscription_id;this.subscriptions.set(h,{id:h,entity:e,schema:s?.schema,options:{filters:s?.filters},callback:t}),this.log(`Subscribed to ${e} with ID: ${h}`),a(h)}else c(new Error(o.error?.message||"Subscription failed"))}),this.send(i),setTimeout(()=>{this.messageHandlers.has(r)&&(this.messageHandlers.delete(r),c(new Error("Subscription timeout")))},1e4)})}async unsubscribe(e){this.ensureConnected();const t=l.v4(),s={id:t,type:"subscription",operation:"unsubscribe",subscription_id:e};return new Promise((r,i)=>{this.messageHandlers.set(t,a=>{a.success?(this.subscriptions.delete(e),this.log(`Unsubscribed from ${e}`),r()):i(new Error(a.error?.message||"Unsubscribe failed"))}),this.send(s),setTimeout(()=>{this.messageHandlers.has(t)&&(this.messageHandlers.delete(t),i(new Error("Unsubscribe timeout")))},1e4)})}getSubscriptions(){return Array.from(this.subscriptions.values())}getState(){return this.state}isConnected(){return this.ws?.readyState===WebSocket.OPEN}on(e,t){this.eventListeners[e]=t}off(e){delete this.eventListeners[e]}handleMessage(e){try{const t=JSON.parse(e);switch(this.log("Received message:",t),this.emit("message",t),t.type){case"response":this.handleResponse(t);break;case"notification":this.handleNotification(t);break;case"pong":break;default:this.log("Unknown message type:",t.type)}}catch(t){this.log("Error parsing message:",t)}}handleResponse(e){const t=this.messageHandlers.get(e.id);t&&(t(e),this.messageHandlers.delete(e.id))}handleNotification(e){const t=this.subscriptions.get(e.subscription_id);t?.callback&&t.callback(e)}send(e){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("WebSocket is not connected");const t=JSON.stringify(e);this.log("Sending message:",e),this.ws.send(t)}startHeartbeat(){this.heartbeatTimer||(this.heartbeatTimer=setInterval(()=>{if(this.isConnected()){const e={id:l.v4(),type:"ping"};this.send(e)}},this.config.heartbeatInterval))}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}setState(e){this.state!==e&&(this.state=e,this.emit("stateChange",e))}ensureConnected(){if(!this.isConnected())throw new Error("WebSocket is not connected. Call connect() first.")}emit(e,...t){const s=this.eventListeners[e];s&&s(...t)}log(...e){this.config.debug&&console.log("[WebSocketClient]",...e)}}function C(n){return typeof btoa=="function"?"ZIP_"+btoa(n):"ZIP_"+Buffer.from(n,"utf-8").toString("base64")}function y(n){let e=n;return e.startsWith("ZIP_")?(e=e.slice(4).replace(/[\n\r ]/g,""),e=m(e)):e.startsWith("__")&&(e=e.slice(2).replace(/[\n\r ]/g,""),e=m(e)),(e.startsWith("ZIP_")||e.startsWith("__"))&&(e=y(e)),e}function m(n){return typeof atob=="function"?atob(n):Buffer.from(n,"base64").toString("utf-8")}function u(n){const e={};if(n.columns?.length&&(e["X-Select-Fields"]=n.columns.join(",")),n.omit_columns?.length&&(e["X-Not-Select-Fields"]=n.omit_columns.join(",")),n.filters?.length)for(const t of n.filters){const s=t.logic_operator??"AND",r=v(t.operator),i=k(t);t.operator==="eq"&&s==="AND"?e[`X-FieldFilter-${t.column}`]=i:s==="OR"?e[`X-SearchOr-${r}-${t.column}`]=i:e[`X-SearchOp-${r}-${t.column}`]=i}if(n.sort?.length){const t=n.sort.map(s=>s.direction.toUpperCase()==="DESC"?`-${s.column}`:`+${s.column}`);e["X-Sort"]=t.join(",")}if(n.limit!==void 0&&(e["X-Limit"]=String(n.limit)),n.offset!==void 0&&(e["X-Offset"]=String(n.offset)),n.cursor_forward&&(e["X-Cursor-Forward"]=n.cursor_forward),n.cursor_backward&&(e["X-Cursor-Backward"]=n.cursor_backward),n.preload?.length){const t=n.preload.map(s=>s.columns?.length?`${s.relation}:${s.columns.join(",")}`:s.relation);e["X-Preload"]=t.join("|")}if(n.fetch_row_number&&(e["X-Fetch-RowNumber"]=n.fetch_row_number),n.computedColumns?.length)for(const t of n.computedColumns)e[`X-CQL-SEL-${t.name}`]=t.expression;if(n.customOperators?.length){const t=n.customOperators.map(s=>s.sql);e["X-Custom-SQL-W"]=t.join(" AND ")}return e}function v(n){switch(n){case"eq":return"equals";case"neq":return"notequals";case"gt":return"greaterthan";case"gte":return"greaterthanorequal";case"lt":return"lessthan";case"lte":return"lessthanorequal";case"like":case"ilike":case"contains":return"contains";case"startswith":return"beginswith";case"endswith":return"endswith";case"in":return"in";case"between":return"between";case"between_inclusive":return"betweeninclusive";case"is_null":return"empty";case"is_not_null":return"notempty";default:return n}}function k(n){return n.value===null||n.value===void 0?"":Array.isArray(n.value)?n.value.join(","):String(n.value)}const b=new Map;function E(n){const e=n.baseUrl;let t=b.get(e);return t||(t=new p(n),b.set(e,t)),t}class p{constructor(e){this.config=e}buildUrl(e,t,s){let r=`${this.config.baseUrl}/${e}/${t}`;return s&&(r+=`/${s}`),r}baseHeaders(){const e={"Content-Type":"application/json"};return this.config.token&&(e.Authorization=`Bearer ${this.config.token}`),e}async fetchWithError(e,t){const s=await fetch(e,t),r=await s.json();if(!s.ok)throw new Error(r.error?.message||"An error occurred");return r}async read(e,t,s,r){const i=this.buildUrl(e,t,s),a=r?u(r):{};return this.fetchWithError(i,{method:"GET",headers:{...this.baseHeaders(),...a}})}async create(e,t,s,r){const i=this.buildUrl(e,t),a=r?u(r):{};return this.fetchWithError(i,{method:"POST",headers:{...this.baseHeaders(),...a},body:JSON.stringify(s)})}async update(e,t,s,r,i){const a=this.buildUrl(e,t,s),c=i?u(i):{};return this.fetchWithError(a,{method:"PUT",headers:{...this.baseHeaders(),...c},body:JSON.stringify(r)})}async delete(e,t,s){const r=this.buildUrl(e,t,s);return this.fetchWithError(r,{method:"DELETE",headers:this.baseHeaders()})}}exports.HeaderSpecClient=p;exports.ResolveSpecClient=g;exports.WebSocketClient=S;exports.buildHeaders=u;exports.decodeHeaderValue=y;exports.encodeHeaderValue=C;exports.getHeaderSpecClient=E;exports.getResolveSpecClient=w;exports.getWebSocketClient=H;