@live-state/sync 0.0.1-alpha.1

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,283 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type LiveTypeMeta = {};
4
+ type MutationType = "set";
5
+ declare abstract class LiveType<Value = any, Meta extends LiveTypeMeta = LiveTypeMeta, EncodeInput = Partial<Value> | Value, DecodeInput = {
6
+ value: Value;
7
+ _meta: keyof Meta extends never ? never : Meta;
8
+ }> {
9
+ readonly _value: Value;
10
+ readonly _meta: Meta;
11
+ readonly _encodeInput: EncodeInput;
12
+ readonly _decodeInput: DecodeInput;
13
+ abstract encodeMutation(mutationType: MutationType, input: EncodeInput, timestamp: string): DecodeInput;
14
+ /**
15
+ * Merges the materialized shape with the encoded mutation
16
+ * @param mutationType The type of mutation
17
+ * @param encodedMutation The encoded mutation
18
+ * @param materializedShape The materialized shape
19
+ * @returns A tuple of the new materialized shape and the accepted diff
20
+ */
21
+ abstract mergeMutation(mutationType: MutationType, encodedMutation: DecodeInput, materializedShape?: MaterializedLiveType<LiveType<Value, Meta>>): [MaterializedLiveType<LiveType<Value, Meta>>, DecodeInput | null];
22
+ }
23
+ type LiveTypeAny = LiveType<any, LiveTypeMeta, any, any>;
24
+ type InferLiveType<T extends LiveTypeAny> = T["_value"] extends Record<string, LiveTypeAny> ? {
25
+ [K in keyof T["_value"]]: InferLiveType<T["_value"][K]>;
26
+ } : T["_value"];
27
+ type InferIndex<T extends LiveTypeAny> = string;
28
+
29
+ declare class OptionalLiveType<T extends LiveTypeAny> extends LiveType<T["_value"] | undefined, T["_meta"], T["_encodeInput"], T["_decodeInput"]> {
30
+ encodeMutation(mutationType: MutationType, input: T["_value"] | undefined, timestamp: string): string;
31
+ mergeMutation(mutationType: MutationType, encodedMutation: T["_decodeInput"], materializedShape?: MaterializedLiveType<LiveType<T["_value"] | undefined, T["_meta"], T["_value"] | Partial<T["_value"] | undefined>, T["_decodeInput"]>> | undefined): [
32
+ MaterializedLiveType<LiveType<T["_value"] | undefined, T["_meta"], T["_value"] | Partial<T["_value"] | undefined>, T["_decodeInput"]>>,
33
+ T["_decodeInput"] | null
34
+ ];
35
+ }
36
+ type LiveAtomicTypeMeta = {
37
+ timestamp: string;
38
+ } & LiveTypeMeta;
39
+ declare abstract class LiveAtomicType<Value = any, Meta extends LiveAtomicTypeMeta = LiveAtomicTypeMeta, EncodeInput = Partial<Value> | Value> extends LiveType<Value, Meta, EncodeInput> {
40
+ constructor();
41
+ optional(): OptionalLiveType<this>;
42
+ }
43
+ declare class LiveString extends LiveAtomicType<string> {
44
+ encodeMutation(mutationType: MutationType, input: Partial<string>, timestamp: string): {
45
+ value: string;
46
+ _meta: {
47
+ timestamp: string;
48
+ };
49
+ };
50
+ mergeMutation(mutationType: MutationType, encodedMutation: {
51
+ value: string;
52
+ _meta: {
53
+ timestamp: string;
54
+ };
55
+ }, materializedShape?: MaterializedLiveType<LiveString>): [
56
+ MaterializedLiveType<LiveString>,
57
+ {
58
+ value: string;
59
+ _meta: {
60
+ timestamp: string;
61
+ };
62
+ } | null
63
+ ];
64
+ static create(): LiveString;
65
+ }
66
+
67
+ type InferLiveObjectWithoutRelations<T extends LiveObjectAny> = {
68
+ [K in keyof T["fields"]]: InferLiveType<T["fields"][K]>;
69
+ };
70
+ type InferLiveObject<T extends LiveObjectAny> = InferLiveObjectWithoutRelations<T> & {
71
+ [K in keyof T["relations"]]: T["relations"][K]["type"] extends "one" ? InferLiveObject<T["relations"][K]["entity"]> : InferLiveObject<T["relations"][K]["entity"]>[];
72
+ };
73
+ type InferRelationalColumns<T extends Record<string, RelationAny>> = {
74
+ [K in keyof T as T[K] extends Relation<any, any, any, infer ColumnName, any, any> ? ColumnName extends string ? ColumnName : never : never]: T[K]["type"] extends "one" ? T[K] extends Relation<infer Entity, any, any, any, any, any> ? T[K]["required"] extends true ? InferIndex<Entity> : InferIndex<Entity> | undefined : never : never;
75
+ };
76
+ type InferLiveObjectWithRelationalIds<T extends LiveObjectAny> = keyof T["relations"] extends string ? InferLiveObjectWithoutRelations<T> & InferRelationalColumns<T["relations"]> : InferLiveObjectWithoutRelations<T>;
77
+ type LiveObjectMutationInput<TSchema extends LiveObjectAny> = InferLiveObjectWithRelationalIds<TSchema>;
78
+ declare class LiveObject<TName extends string, TSchema extends Record<string, LiveTypeAny>, TRelations extends Record<string, RelationAny>> extends LiveType<TSchema, LiveTypeMeta, LiveObjectMutationInput<any>, Record<string, MaterializedLiveType<LiveTypeAny>>> {
79
+ readonly name: TName;
80
+ readonly fields: TSchema;
81
+ readonly relations: TRelations;
82
+ constructor(name: TName, fields: TSchema, relations?: TRelations);
83
+ encodeMutation(_mutationType: MutationType, input: LiveObjectMutationInput<this>, timestamp: string): Record<string, any>;
84
+ mergeMutation(mutationType: MutationType, encodedMutations: Record<string, MaterializedLiveType<LiveTypeAny>>, materializedShape?: MaterializedLiveType<this> | undefined): [MaterializedLiveType<this>, Record<string, any> | null];
85
+ setRelations<TRelations extends Record<string, RelationAny>>(relations: TRelations): LiveObject<this["name"], this["fields"], TRelations>;
86
+ static create<TName extends string, TSchema extends Record<string, LiveTypeAny>>(name: TName, schema: TSchema): LiveObject<TName, TSchema, never>;
87
+ }
88
+ type LiveObjectAny = LiveObject<string, Record<string, LiveTypeAny>, any>;
89
+ declare class Relation<TEntity extends LiveObjectAny, TSourceEntity extends LiveObjectAny, TType extends "one" | "many", TRelationalColumn extends keyof TSourceEntity["fields"], TForeignColumn extends keyof TEntity["fields"], TRequired extends boolean> extends LiveType<InferIndex<TEntity>, {
90
+ timestamp: string;
91
+ } & LiveTypeMeta> {
92
+ readonly entity: TEntity;
93
+ readonly type: TType;
94
+ readonly required: TRequired;
95
+ readonly relationalColumn?: TRelationalColumn;
96
+ readonly foreignColumn?: TForeignColumn;
97
+ readonly sourceEntity: TSourceEntity;
98
+ private constructor();
99
+ encodeMutation(mutationType: MutationType, input: string, timestamp: string): {
100
+ value: string;
101
+ _meta: {
102
+ timestamp: string;
103
+ };
104
+ };
105
+ mergeMutation(mutationType: MutationType, encodedMutation: {
106
+ value: string;
107
+ _meta: {
108
+ timestamp: string;
109
+ };
110
+ }, materializedShape?: MaterializedLiveType<LiveString> | undefined): [
111
+ MaterializedLiveType<LiveString>,
112
+ {
113
+ value: string;
114
+ _meta: {
115
+ timestamp: string;
116
+ };
117
+ } | null
118
+ ];
119
+ static createOneFactory<TOriginEntity extends LiveObjectAny>(): <TEntity extends LiveObjectAny, TColumn extends keyof TOriginEntity["fields"], TRequired extends boolean = false>(entity: TEntity, column: TColumn, required?: TRequired) => Relation<TEntity, TOriginEntity, "one", TColumn, never, TRequired>;
120
+ static createManyFactory<TOriginEntity extends LiveObjectAny>(): <TEntity extends LiveObjectAny, TColumn extends keyof TEntity["fields"], TRequired extends boolean = false>(entity: TEntity, foreignColumn: TColumn, required?: TRequired) => Relation<TEntity, TOriginEntity, "many", never, TColumn, TRequired>;
121
+ }
122
+ type RelationAny = Relation<LiveObjectAny, LiveObjectAny, any, any, any, any>;
123
+ type MaterializedLiveType<T extends LiveTypeAny> = keyof T["_meta"] extends never ? {
124
+ value: T["_value"] extends Record<string, LiveTypeAny> ? {
125
+ [K in keyof T["_value"]]: MaterializedLiveType<T["_value"][K]>;
126
+ } : T["_value"];
127
+ } : {
128
+ value: T["_value"] extends Record<string, LiveTypeAny> ? {
129
+ [K in keyof T["_value"]]: MaterializedLiveType<T["_value"][K]>;
130
+ } : T["_value"];
131
+ _meta: T["_meta"];
132
+ };
133
+ type MaterializedLiveObject<T extends LiveObjectAny> = MaterializedLiveType<T> & {
134
+ [K in keyof T["relations"]]: InferIndex<T["relations"][K]["entity"]>;
135
+ };
136
+ type ExtractObjectValues<T> = T[keyof T];
137
+ type RelationsDecl<TObjectName extends string = string, TRelations extends Record<string, RelationAny> = Record<string, RelationAny>> = {
138
+ $type: "relations";
139
+ objectName: TObjectName;
140
+ relations: TRelations;
141
+ };
142
+ type ParseRelationsFromSchema<TRawSchema extends RawSchema, TObjectName extends string> = ExtractObjectValues<{
143
+ [K in keyof TRawSchema]: TRawSchema[K] extends RelationsDecl<infer TObjectName_, any> ? TObjectName_ extends TObjectName ? {
144
+ [K2 in keyof TRawSchema[K]["relations"]]: Relation<ParseObjectFromSchema<TRawSchema, TRawSchema[K]["relations"][K2]["entity"]["name"]>, TRawSchema[K]["relations"][K2]["sourceEntity"], TRawSchema[K]["relations"][K2]["type"], Exclude<TRawSchema[K]["relations"][K2]["relationalColumn"], undefined>, Exclude<TRawSchema[K]["relations"][K2]["foreignColumn"], undefined>, TRawSchema[K]["relations"][K2]["required"]>;
145
+ } : never : never;
146
+ }>;
147
+ type ParseObjectFromSchema<TRawSchema extends RawSchema, TObjectName extends string> = ExtractObjectValues<{
148
+ [K in keyof TRawSchema]: TRawSchema[K] extends LiveObjectAny ? TRawSchema[K]["name"] extends TObjectName ? LiveObject<TRawSchema[K]["name"], TRawSchema[K]["fields"], ParseRelationsFromSchema<TRawSchema, TRawSchema[K]["name"]>> : never : never;
149
+ }>;
150
+ type RawSchema = Record<string, LiveObjectAny | RelationsDecl>;
151
+ type Schema<TRawSchema extends RawSchema> = {
152
+ [K in keyof TRawSchema as TRawSchema[K] extends LiveObjectAny ? TRawSchema[K]["name"] : never]: TRawSchema[K] extends LiveObjectAny ? ParseObjectFromSchema<TRawSchema, TRawSchema[K]["name"]> : never;
153
+ };
154
+
155
+ declare abstract class Storage {
156
+ abstract updateSchema(opts: Schema<any>): Promise<void>;
157
+ abstract findById<T extends LiveObjectAny>(resourceName: string, id: string): Promise<MaterializedLiveType<T> | undefined>;
158
+ abstract find<T extends LiveObjectAny>(resourceName: string, where?: Record<string, any>): Promise<Record<string, MaterializedLiveType<T>>>;
159
+ abstract upsert<T extends LiveObjectAny>(resourceName: string, resourceId: string, value: MaterializedLiveType<T>): Promise<MaterializedLiveType<T>>;
160
+ }
161
+
162
+ type RequestBase = {
163
+ resourceName: string;
164
+ context: Record<string, any>;
165
+ where?: Record<string, any>;
166
+ };
167
+ type FindRequest = RequestBase & {
168
+ type: "FIND";
169
+ };
170
+ type SetRequest = RequestBase & {
171
+ type: "SET";
172
+ resourceId: string;
173
+ payload: Record<string, any>;
174
+ };
175
+ type Request = FindRequest | SetRequest;
176
+ type RouteRecord = Record<string, Route<LiveObjectAny>>;
177
+ declare class Router<TSchema extends Schema<any>, TRoutes extends RouteRecord> {
178
+ readonly routes: TRoutes;
179
+ private constructor();
180
+ static create<TSchema extends Schema<any>, TRoutes extends RouteRecord>(opts: {
181
+ routes: TRoutes;
182
+ }): Router<TSchema, TRoutes>;
183
+ }
184
+ type AnyRouter = Router<Schema<any>, RouteRecord>;
185
+ type RouteResult<TShape extends LiveObjectAny> = {
186
+ data: MaterializedLiveType<TShape> | Record<string, MaterializedLiveType<TShape>>;
187
+ acceptedValues: Record<string, any> | null;
188
+ };
189
+ declare class Route<TShape extends LiveObjectAny> {
190
+ readonly shape: TShape;
191
+ constructor(shape: TShape);
192
+ private handleFind;
193
+ private handleSet;
194
+ handleRequest(opts: {
195
+ req: Request;
196
+ db: Storage;
197
+ }): Promise<RouteResult<TShape>>;
198
+ }
199
+
200
+ type Simplify<T> = T extends Record<string, any> ? {
201
+ [K in keyof T]: Simplify<T[K]>;
202
+ } : T;
203
+
204
+ type Observable<T> = {
205
+ [K in keyof T]: Observable<T[K]>;
206
+ } & {
207
+ get: () => T;
208
+ subscribe: (callback: (value: T) => void) => () => void;
209
+ subscribeToRemote: () => () => void;
210
+ };
211
+
212
+ type WebSocketClientEventMap = WebSocketEventMap & {
213
+ connectionChange: {
214
+ open: boolean;
215
+ };
216
+ };
217
+ declare class WebSocketClient {
218
+ private ws;
219
+ private url;
220
+ private autoConnect;
221
+ private autoReconnect;
222
+ private reconnectTimeout;
223
+ private reconnectLimit?;
224
+ private reconnectAttempts;
225
+ private eventListeners;
226
+ private reconnectTimer;
227
+ private intentionallyDisconnected;
228
+ constructor(options: {
229
+ url: string;
230
+ autoConnect?: boolean;
231
+ autoReconnect?: boolean;
232
+ reconnectTimeout?: number;
233
+ reconnectLimit?: number;
234
+ });
235
+ connected(): boolean;
236
+ connect(): void;
237
+ disconnect(): void;
238
+ addEventListener<K extends keyof WebSocketClientEventMap>(event: K, callback: (event: WebSocketClientEventMap[K]) => void): void;
239
+ removeEventListener<K extends keyof WebSocketClientEventMap>(event: K, callback: (event: WebSocketClientEventMap[K]) => void): void;
240
+ send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
241
+ private handleOpen;
242
+ private handleClose;
243
+ private handleError;
244
+ private handleMessage;
245
+ private scheduleReconnect;
246
+ private dispatchEvent;
247
+ }
248
+
249
+ declare const useLiveQuery: <T extends Observable<U>, U>(observable: T, opts?: {
250
+ subscribeToRemote?: boolean;
251
+ }) => ReturnType<T["get"]>;
252
+ declare const SubscriptionProvider: ({ children, client, }: {
253
+ children: React.ReactNode;
254
+ client: Client<AnyRouter>["client"];
255
+ }) => react_jsx_runtime.JSX.Element;
256
+
257
+ type RawObjPool<TRouter extends AnyRouter> = Record<keyof TRouter["routes"], Record<string, MaterializedLiveObject<TRouter["routes"][keyof TRouter["routes"]]["shape"]>> | undefined>;
258
+ type ClientState<TRouter extends AnyRouter> = {
259
+ [K in keyof TRouter["routes"]]: Record<InferIndex<TRouter["routes"][K]["shape"]>, InferLiveObject<TRouter["routes"][K]["shape"]>> | undefined;
260
+ };
261
+ type Client<TRouter extends AnyRouter> = {
262
+ /**
263
+ * @internal
264
+ */
265
+ _router: TRouter;
266
+ client: {
267
+ ws: WebSocketClient;
268
+ subscribeToRemote: (resourceType?: string[]) => () => void;
269
+ };
270
+ store: Observable<ClientState<TRouter>> & {
271
+ [K in keyof TRouter["routes"]]: {
272
+ insert: (input: Simplify<LiveObjectMutationInput<TRouter["routes"][K]["shape"]>>["value"]) => void;
273
+ update: (id: string, value: Omit<Simplify<LiveObjectMutationInput<TRouter["routes"][K]["shape"]>>["value"], "id">) => void;
274
+ };
275
+ };
276
+ };
277
+ type ClientOptions = {
278
+ url: string;
279
+ schema: Schema<any>;
280
+ };
281
+ declare const createClient: <TRouter extends AnyRouter>(opts: ClientOptions) => Client<TRouter>;
282
+
283
+ export { type Client, type ClientOptions, type ClientState, type RawObjPool, SubscriptionProvider, createClient, useLiveQuery };
package/dist/client.js ADDED
@@ -0,0 +1 @@
1
+ import {nanoid}from'nanoid';import {z}from'zod';import {useState,useEffect}from'react';import {jsx,Fragment}from'react/jsx-runtime';var v=z.string().nanoid(),K=z.object({_id:v,type:z.literal("SUBSCRIBE"),resource:z.string()}),k=z.object({_id:v,type:z.literal("SYNC"),lastSyncedAt:z.string().optional(),resources:z.string().array().optional()}),I=z.record(z.object({value:z.string().or(z.number()).or(z.boolean()).or(z.date()),_meta:z.object({timestamp:z.string().optional()}).optional()})).superRefine((o,e)=>{o.id&&e.addIssue({code:z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),A=z.object({_id:v,type:z.literal("MUTATE"),resource:z.string(),resourceId:z.string(),payload:I});z.union([K,A,k]);var P=z.object({_id:v,type:z.literal("SYNC"),resource:z.string(),data:z.record(I)}),N=z.object({_id:v,type:z.literal("REJECT"),resource:z.string()}),C=z.union([A,P,N]);var b=o=>Array.isArray(o.value)?o.value.map(e=>b(e)):typeof o.value!="object"?o.value:Object.fromEntries(Object.entries(o.value).map(([e,t])=>[e,b(t)]));var R=class{nodes;constructor(){this.nodes=new Map;}createNode(e,t,n){if(this.nodes.has(e))throw new Error(`Node with id ${e} already exists`);let i={id:e,type:t,referencedBy:new Map(n.map(r=>[r,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,i),i}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t,n){let i=this.nodes.get(e),r=this.nodes.get(t);if(!i)throw new Error(`Source node with id ${e} does not exist`);if(!r)throw new Error(`Target node with id ${t} does not exist`);i.references.set(n,t);let s=r.referencedBy.get(n);s&&s instanceof Set?s.add(e):r.referencedBy.set(n,e),this.notifySubscribers(t);}removeLink(e,t){let n=this.nodes.get(e);if(!n)throw new Error(`Node with id ${e} does not exist`);let i=n.references.get(t);if(!i)return;n.references.delete(t);let r=this.nodes.get(i);if(!r)return;let s=r.referencedBy.get(t);s&&(s instanceof Set?s.delete(e):r.referencedBy.delete(t),this.notifySubscribers(i)),this.notifySubscribers(e);}subscribe(e,t){let n=this.nodes.get(e);if(!n)throw new Error(`Node with id ${e} does not exist`);return n.subscriptions.add(t),()=>{n.subscriptions.delete(t);}}removeNode(e){let t=this.nodes.get(e);t&&(Array.from(t.referencedBy.entries()).forEach(([n,i])=>{(i instanceof Set?Array.from(i.values()):[i]).forEach(s=>{let c=this.nodes.get(s);!c||!c.references.get(n)||(c.references.delete(n),this.notifySubscribers(s));});}),this.nodes.delete(e));}updateNode(e,t){let n=this.nodes.get(e);if(!n)throw new Error(`Node with id ${e} does not exist`);t(n),this.notifySubscribers(e);}notifySubscribers(e){let t=this.nodes.get(e);t&&Array.from(t.subscriptions).forEach(n=>{try{n(e);}catch(i){console.error(`Error in node subscription for node ${e}:`,i);}});}getAllNodes(){return Array.from(this.nodes.values())}};var x=(o,e,t=[])=>new Proxy(o,{get:(n,i)=>{var l,p;if(i==="__isProxy__")return true;let r=(l=e.get)==null?void 0:l.call(e,n,[...t,i]);if(r!==void 0)return r;let s=n,c=i;return (p=s[c])!=null&&p.__isProxy__||(s[c]=x(typeof s[c]=="object"?s[c]:Object.create(null),e,[...t,i])),s[c]}});var M=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}connect(){this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING)||(this.intentionallyDisconnected=false,this.ws=new WebSocket(this.url),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this)));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}removeEventListener(e,t){this.eventListeners.has(e)&&this.eventListeners.get(e).delete(t);}send(e){if(this.ws&&this.ws.readyState===WebSocket.OPEN)this.ws.send(e);else throw new Error("WebSocket is not open")}handleOpen(e){this.reconnectAttempts=0,this.dispatchEvent("open",e),this.dispatchEvent("connectionChange",{open:true});}handleClose(e){this.dispatchEvent("close",e),this.dispatchEvent("connectionChange",{open:false}),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect();}handleError(e){this.dispatchEvent("error",e);}handleMessage(e){this.dispatchEvent("message",e);}scheduleReconnect(){this.reconnectLimit&&this.reconnectAttempts>=this.reconnectLimit||(this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect();},this.reconnectTimeout));}dispatchEvent(e,t){this.eventListeners.has(e)&&this.eventListeners.get(e).forEach(n=>{n(t);});}};var pe=(o,e)=>{let[t,n]=useState(()=>o.get());return useEffect(()=>{if(e!=null&&e.subscribeToRemote)return o.subscribeToRemote()},[e==null?void 0:e.subscribeToRemote]),useEffect(()=>o.subscribe(()=>{let i=o.get();n(i);}),[]),t},ye=({children:o,client:e})=>(useEffect(()=>{e.subscribeToRemote();},[]),jsx(Fragment,{children:o}));var _=class{_router;url;ws;schema;rawObjPool={};optimisticMutationStack={};optimisticObjGraph=new R;optimisticRawObjPool={};resourceTypeSubscriptions={};routeSubscriptions={};constructor(e){this.url=e.url,this.schema=e.schema,this.ws=new M({url:e.url,autoConnect:true,autoReconnect:true,reconnectTimeout:5e3}),this.ws.addEventListener("message",t=>{this.handleServerMessage(t.data);}),this.ws.addEventListener("connectionChange",t=>{t.open&&(this.sendWsMessage({_id:nanoid(),type:"SYNC"}),Object.entries(this.routeSubscriptions).forEach(([n,i])=>{i>0&&this.sendWsMessage({_id:nanoid(),type:"SUBSCRIBE",resource:n});}),Object.values(this.optimisticMutationStack).forEach(n=>{n.forEach(i=>this.sendWsMessage(i));}));});}get(e){if(e.length===0)throw new Error("Path must not be empty");if(e.length===1)return Object.fromEntries(Object.entries(this.optimisticRawObjPool[e[0]]??{}).map(([n,i])=>[n,b(i)]));let t=this.getFullObject(e[0],e[1]);if(!t)throw new Error("Object of type "+e[0]+" not found with id "+e[1]);return b(t)}handleServerMessage(e){try{console.log("Message received from the server:",e);let t=C.parse(JSON.parse(e));if(console.log("Parsed message:",t),t.type==="MUTATE"){let{resource:n}=t;try{this.addMutation(n,t);}catch(i){console.error("Error parsing mutation from the server:",i);}}else if(t.type==="SYNC"){let{resource:n,data:i}=t;console.log("Syncing resource:",i,t),Object.entries(i).forEach(([r,s])=>{this.addMutation(n,{_id:r,type:"MUTATE",resource:n,resourceId:r,payload:s});});}else t.type;}catch(t){console.error("Error parsing message from the server:",t);}}subscribeToRemote(e){return this.routeSubscriptions[e]=(this.routeSubscriptions[e]??0)+1,this.sendWsMessage({_id:nanoid(),type:"SUBSCRIBE",resource:e}),()=>{this.routeSubscriptions[e]-=1,this.routeSubscriptions[e];}}subscribeToSlice(e,t){if(e.length===1)return this.resourceTypeSubscriptions[e[0]]||(this.resourceTypeSubscriptions[e[0]]=new Set),this.resourceTypeSubscriptions[e[0]].add(t),()=>{this.resourceTypeSubscriptions[e[0]].delete(t);};if(e.length===2){if(!this.optimisticObjGraph.getNode(e[1]))throw new Error("Node not found");return this.optimisticObjGraph.subscribe(e[1],t)}throw new Error("Not implemented")}mutate(e,t,n){let i={_id:nanoid(),type:"MUTATE",resource:e,payload:this.schema[e].encodeMutation("set",n,new Date().toISOString()),resourceId:t};this.addMutation(e,i,true),this.sendWsMessage(i);}sendWsMessage(e){this.ws&&this.ws.connected()&&this.ws.send(JSON.stringify(e));}addMutation(e,t,n=false){var c,l,p,f;let i=this.schema[e];if(console.log("Adding mutation",t),!i)throw new Error("Schema not found");n?(this.optimisticMutationStack[e]||(this.optimisticMutationStack[e]=[]),this.optimisticMutationStack[e].push(t)):this.optimisticMutationStack[e]&&(this.optimisticMutationStack[e]=this.optimisticMutationStack[e].filter(u=>u._id!==t._id)),this.optimisticObjGraph.getNode(t.resourceId)||this.optimisticObjGraph.createNode(t.resourceId,e,Object.values(i.relations).flatMap(u=>u.type==="many"?[u.foreignColumn]:[]));let r=((c=this.optimisticRawObjPool[e])==null?void 0:c[t.resourceId])??((l=this.rawObjPool[e])==null?void 0:l[t.resourceId]);n||(this.rawObjPool[e]??={},this.rawObjPool[e][t.resourceId]={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}}),this.optimisticRawObjPool[e]??={};let s=(this.optimisticMutationStack[e]??[]).reduce((u,d)=>d.resourceId!==d.resourceId?u:this.schema[e].mergeMutation("set",d.payload,u)[0],(p=this.rawObjPool[e])==null?void 0:p[t.resourceId]);if(s&&(this.optimisticRawObjPool[e][t.resourceId]={value:{...s.value,id:{value:t.resourceId}}}),Object.keys(i.relations).length>0){let u=Object.fromEntries(Object.entries(i.relations).flatMap(([d,T])=>T.type==="one"?[[T.relationalColumn,d]]:[]));Object.entries(t.payload).forEach(([d,T])=>{if(!u[d])return;let[,y]=i.relations[u[d]].mergeMutation("set",T,r==null?void 0:r.value[d]);y&&this.optimisticObjGraph.createLink(t.resourceId,y.value,d);});}(f=this.resourceTypeSubscriptions[e])==null||f.forEach(u=>u()),this.optimisticObjGraph.notifySubscribers(t.resourceId);}getFullObject(e,t){var r;let n=this.optimisticObjGraph.getNode(t);if(!n)return;let i=(r=this.optimisticRawObjPool[e])==null?void 0:r[t];if(i)return {value:{...i.value,...Object.fromEntries(Array.from(n.referencedBy.entries()).map(([s,c])=>{var T;let l=c instanceof Set,p=l?Array.from(c.values()).flatMap(y=>{let h=this.optimisticObjGraph.getNode(y);return h?[h]:[]}):this.optimisticObjGraph.getNode(c);if(!p)return [s,void 0];let[f,u]=Object.entries(this.schema[e].relations).find(y=>y[1].relationalColumn===s||y[1].foreignColumn===s)??[],d=u==null?void 0:u.entity.name;return !d||!u?[s,l?[]:void 0]:[f,{value:l?p.map(y=>{var h;return (h=this.optimisticRawObjPool[d])==null?void 0:h[y.id]}):(T=this.optimisticRawObjPool[d])==null?void 0:T[p.id]}]}))}}}},Ke=o=>{let e=new _(o);return {_router:e._router,client:{ws:e.ws,subscribeToRemote:t=>{let n=[];for(let i of t??Object.keys(e.schema))n.push(e.subscribeToRemote(i));return ()=>{n.forEach(i=>i());}}},store:x({},{get:(t,n)=>{let i=n.slice(0,-1),r=n[n.length-1];if(r==="get")return ()=>e.get(i);if(r==="subscribe")return s=>e.subscribeToSlice(i,s);if(r==="subscribeToRemote")return e.subscribeToRemote.bind(e,i[0]);if(i.length===1){if(r==="insert")return s=>{let{id:c,...l}=s;e.mutate(i[0],c,l);};if(r==="update")return (s,c)=>{e.mutate(i[0],s,c);}}}})}};export{ye as SubscriptionProvider,Ke as createClient,pe as useLiveQuery};