@live-state/sync 0.0.1-alpha.1 → 0.0.1-alpha.3

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/index.d.ts CHANGED
@@ -1,2 +1,209 @@
1
- export { C as ClientMessage, t as InferIndex, I as InferLiveObject, c as InferLiveObjectWithRelationalIds, r as InferLiveType, j as LiveNumber, e as LiveObject, L as LiveObjectAny, d as LiveObjectMutationInput, k as LiveString, p as LiveType, q as LiveTypeAny, l as LiveTypeMeta, g as MaterializedLiveObject, M as MaterializedLiveType, m as MutationType, R as Relation, S as Schema, b as ServerMessage, f as createRelations, h as createSchema, i as inferValue, n as number, o as object, s as string } from './index-sSVirsfN.js';
2
- import 'zod';
1
+ type LiveTypeMeta = {};
2
+ type MutationType = "set";
3
+ type StorageFieldType = {
4
+ type: string;
5
+ nullable: boolean;
6
+ default?: any;
7
+ unique?: boolean;
8
+ index?: boolean;
9
+ primary?: boolean;
10
+ references?: string;
11
+ };
12
+ declare abstract class LiveType<Value = any, Meta extends LiveTypeMeta = LiveTypeMeta, EncodeInput = Partial<Value> | Value, DecodeInput = {
13
+ value: Value;
14
+ _meta: keyof Meta extends never ? never : Meta;
15
+ }> {
16
+ readonly _value: Value;
17
+ readonly _meta: Meta;
18
+ readonly _encodeInput: EncodeInput;
19
+ readonly _decodeInput: DecodeInput;
20
+ abstract encodeMutation(mutationType: MutationType, input: EncodeInput, timestamp: string): DecodeInput;
21
+ /**
22
+ * Merges the materialized shape with the encoded mutation
23
+ * @param mutationType The type of mutation
24
+ * @param encodedMutation The encoded mutation
25
+ * @param materializedShape The materialized shape
26
+ * @returns A tuple of the new materialized shape and the accepted diff
27
+ */
28
+ abstract mergeMutation(mutationType: MutationType, encodedMutation: DecodeInput, materializedShape?: MaterializedLiveType<LiveType<Value, Meta>>): [MaterializedLiveType<LiveType<Value, Meta>>, DecodeInput | null];
29
+ abstract getStorageFieldType(): StorageFieldType;
30
+ }
31
+ type LiveTypeAny = LiveType<any, LiveTypeMeta, any, any>;
32
+ type InferLiveType<T extends LiveTypeAny> = T["_value"] extends Record<string, LiveTypeAny> ? {
33
+ [K in keyof T["_value"]]: InferLiveType<T["_value"][K]>;
34
+ } : T["_value"];
35
+ type InferIndex<T extends LiveTypeAny> = string;
36
+
37
+ declare class OptionalLiveType<T extends LiveTypeAny> extends LiveType<T["_value"] | undefined, T["_meta"], T["_encodeInput"], T["_decodeInput"]> {
38
+ readonly inner: T;
39
+ constructor(inner: T);
40
+ encodeMutation(mutationType: MutationType, input: T["_value"] | undefined, timestamp: string): T["_decodeInput"];
41
+ mergeMutation(mutationType: MutationType, encodedMutation: T["_decodeInput"], materializedShape?: MaterializedLiveType<LiveType<T["_value"] | undefined, T["_meta"], T["_value"] | Partial<T["_value"] | undefined>, T["_decodeInput"]>> | undefined): [
42
+ MaterializedLiveType<LiveType<T["_value"] | undefined, T["_meta"], T["_value"] | Partial<T["_value"] | undefined>, T["_decodeInput"]>>,
43
+ T["_decodeInput"] | null
44
+ ];
45
+ getStorageFieldType(): StorageFieldType;
46
+ }
47
+ type LiveAtomicTypeMeta = {
48
+ timestamp: string;
49
+ } & LiveTypeMeta;
50
+ declare class LiveAtomicType<Value> extends LiveType<Value, LiveAtomicTypeMeta, Value, {
51
+ value: Value;
52
+ _meta: LiveAtomicTypeMeta;
53
+ }> {
54
+ readonly storageType: string;
55
+ readonly convertFunc?: (value: any) => Value;
56
+ readonly isIndex: boolean;
57
+ readonly isUnique: boolean;
58
+ readonly defaultValue?: Value;
59
+ readonly foreignReference?: string;
60
+ readonly isPrimary: boolean;
61
+ constructor(storageType: string, convertFunc?: (value: any) => Value, index?: boolean, unique?: boolean, defaultValue?: Value, references?: string, primary?: boolean);
62
+ encodeMutation(mutationType: MutationType, input: Value, timestamp: string): {
63
+ value: Value;
64
+ _meta: LiveAtomicTypeMeta;
65
+ };
66
+ mergeMutation(mutationType: MutationType, encodedMutation: {
67
+ value: Value;
68
+ _meta: LiveAtomicTypeMeta;
69
+ }, materializedShape?: MaterializedLiveType<LiveType<Value, LiveAtomicTypeMeta, Value | Partial<Value>, {
70
+ value: Value;
71
+ _meta: LiveAtomicTypeMeta;
72
+ }>>): [
73
+ MaterializedLiveType<LiveType<Value, LiveAtomicTypeMeta, Value | Partial<Value>, {
74
+ value: Value;
75
+ _meta: LiveAtomicTypeMeta;
76
+ }>>,
77
+ {
78
+ value: Value;
79
+ _meta: LiveAtomicTypeMeta;
80
+ } | null
81
+ ];
82
+ getStorageFieldType(): StorageFieldType;
83
+ unique(): LiveAtomicType<Value>;
84
+ index(): LiveAtomicType<Value>;
85
+ default(value: Value): LiveAtomicType<Value>;
86
+ primary(): LiveAtomicType<Value>;
87
+ optional(): OptionalLiveType<this>;
88
+ }
89
+ declare class LiveNumber extends LiveAtomicType<number> {
90
+ private constructor();
91
+ static create(): LiveNumber;
92
+ }
93
+ declare const number: typeof LiveNumber.create;
94
+ declare class LiveString extends LiveAtomicType<string> {
95
+ private constructor();
96
+ static create(): LiveString;
97
+ static createId(): LiveAtomicType<string>;
98
+ static createReference(foreignField: `${string}.${string}`): LiveString;
99
+ }
100
+ declare const string: typeof LiveString.create;
101
+ declare const id: typeof LiveString.createId;
102
+ declare const reference: typeof LiveString.createReference;
103
+ declare class LiveBoolean extends LiveAtomicType<boolean> {
104
+ private constructor();
105
+ static create(): LiveBoolean;
106
+ }
107
+ declare const boolean: typeof LiveBoolean.create;
108
+ declare class LiveTimestamp extends LiveAtomicType<Date> {
109
+ private constructor();
110
+ static create(): LiveTimestamp;
111
+ }
112
+ declare const timestamp: typeof LiveTimestamp.create;
113
+
114
+ type InferLiveObjectWithoutRelations<T extends LiveObjectAny> = {
115
+ [K in keyof T["fields"]]: InferLiveType<T["fields"][K]>;
116
+ };
117
+ type InferLiveObject<T extends LiveObjectAny> = InferLiveObjectWithoutRelations<T> & {
118
+ [K in keyof T["relations"]]: T["relations"][K]["type"] extends "one" ? InferLiveObject<T["relations"][K]["entity"]> : InferLiveObject<T["relations"][K]["entity"]>[];
119
+ };
120
+ type InferRelationalColumns<T extends Record<string, RelationAny>> = {
121
+ [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;
122
+ };
123
+ type InferLiveObjectWithRelationalIds<T extends LiveObjectAny> = keyof T["relations"] extends string ? InferLiveObjectWithoutRelations<T> & InferRelationalColumns<T["relations"]> : InferLiveObjectWithoutRelations<T>;
124
+ type LiveObjectMutationInput<TSchema extends LiveObjectAny> = Partial<InferLiveObjectWithRelationalIds<TSchema>>;
125
+ 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>>> {
126
+ readonly name: TName;
127
+ readonly fields: TSchema;
128
+ readonly relations: TRelations;
129
+ constructor(name: TName, fields: TSchema, relations?: TRelations);
130
+ encodeMutation(_mutationType: MutationType, input: LiveObjectMutationInput<this>, timestamp: string): Record<string, any>;
131
+ mergeMutation(mutationType: MutationType, encodedMutations: Record<string, MaterializedLiveType<LiveTypeAny>>, materializedShape?: MaterializedLiveType<this> | undefined): [MaterializedLiveType<this>, Record<string, any> | null];
132
+ setRelations<TRelations extends Record<string, RelationAny>>(relations: TRelations): LiveObject<this["name"], this["fields"], TRelations>;
133
+ getStorageFieldType(): StorageFieldType;
134
+ static create<TName extends string, TSchema extends Record<string, LiveTypeAny>>(name: TName, schema: TSchema): LiveObject<TName, TSchema, never>;
135
+ }
136
+ declare const object: typeof LiveObject.create;
137
+ type LiveObjectAny = LiveObject<string, Record<string, LiveTypeAny>, any>;
138
+ 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>, {
139
+ timestamp: string;
140
+ } & LiveTypeMeta> {
141
+ readonly entity: TEntity;
142
+ readonly type: TType;
143
+ readonly required: TRequired;
144
+ readonly relationalColumn?: TRelationalColumn;
145
+ readonly foreignColumn?: TForeignColumn;
146
+ readonly sourceEntity: TSourceEntity;
147
+ private constructor();
148
+ encodeMutation(mutationType: MutationType, input: string, timestamp: string): {
149
+ value: string;
150
+ _meta: {
151
+ timestamp: string;
152
+ };
153
+ };
154
+ mergeMutation(mutationType: MutationType, encodedMutation: {
155
+ value: string;
156
+ _meta: {
157
+ timestamp: string;
158
+ };
159
+ }, materializedShape?: MaterializedLiveType<LiveString> | undefined): [
160
+ MaterializedLiveType<LiveString>,
161
+ {
162
+ value: string;
163
+ _meta: {
164
+ timestamp: string;
165
+ };
166
+ } | null
167
+ ];
168
+ getStorageFieldType(): StorageFieldType;
169
+ 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>;
170
+ 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>;
171
+ }
172
+ type RelationAny = Relation<LiveObjectAny, LiveObjectAny, any, any, any, any>;
173
+ declare const createRelations: <TSourceObject extends LiveObjectAny, TRelations extends Record<string, RelationAny>>(liveObject: TSourceObject, factory: (connectors: {
174
+ one: ReturnType<typeof Relation.createOneFactory<TSourceObject>>;
175
+ many: ReturnType<typeof Relation.createManyFactory<TSourceObject>>;
176
+ }) => TRelations) => RelationsDecl<TSourceObject["name"], TRelations>;
177
+ type MaterializedLiveType<T extends LiveTypeAny> = {
178
+ value: T["_value"] extends Record<string, LiveTypeAny> ? {
179
+ [K in keyof T["_value"]]: MaterializedLiveType<T["_value"][K]>;
180
+ } : T["_value"];
181
+ _meta: T["_meta"];
182
+ };
183
+ declare const inferValue: <T extends LiveTypeAny>(type?: MaterializedLiveType<T>) => InferLiveType<T> | undefined;
184
+ type ExtractObjectValues<T> = T[keyof T];
185
+ type RelationsDecl<TObjectName extends string = string, TRelations extends Record<string, RelationAny> = Record<string, RelationAny>> = {
186
+ $type: "relations";
187
+ objectName: TObjectName;
188
+ relations: TRelations;
189
+ };
190
+ type ParseRelationsFromSchema<TRawSchema extends RawSchema, TObjectName extends string> = ExtractObjectValues<{
191
+ [K in keyof TRawSchema]: TRawSchema[K] extends RelationsDecl<infer TObjectName_, any> ? TObjectName_ extends TObjectName ? {
192
+ [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"]>;
193
+ } : never : never;
194
+ }>;
195
+ type ParseObjectFromSchema<TRawSchema extends RawSchema, TObjectName extends string> = ExtractObjectValues<{
196
+ [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;
197
+ }>;
198
+ type RawSchema = Record<string, LiveObjectAny | RelationsDecl>;
199
+ type Schema<TRawSchema extends RawSchema> = {
200
+ [K in keyof TRawSchema as TRawSchema[K] extends LiveObjectAny ? TRawSchema[K]["name"] : never]: TRawSchema[K] extends LiveObjectAny ? ParseObjectFromSchema<TRawSchema, TRawSchema[K]["name"]> : never;
201
+ };
202
+ declare const createSchema: <TRawSchema extends RawSchema>(schema: TRawSchema) => Schema<TRawSchema>;
203
+ type WhereClause<T extends LiveObjectAny> = {
204
+ [K in keyof T["fields"]]?: InferLiveType<T["fields"][K]>;
205
+ } & {
206
+ [K in keyof T["relations"]]?: WhereClause<T["relations"][K]["entity"]>;
207
+ };
208
+
209
+ export { type InferIndex, type InferLiveObject, type InferLiveObjectWithRelationalIds, type InferLiveType, LiveBoolean, LiveNumber, LiveObject, type LiveObjectAny, type LiveObjectMutationInput, LiveString, LiveTimestamp, LiveType, type LiveTypeAny, type LiveTypeMeta, type MaterializedLiveType, type MutationType, Relation, type Schema, type StorageFieldType, type WhereClause, boolean, createRelations, createSchema, id, inferValue, number, object, reference, string, timestamp };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var o=class{_value;_meta;_encodeInput;_decodeInput};var T=class extends o{encodeMutation(n,t,e){throw new Error("Method not implemented.")}mergeMutation(n,t,e){throw new Error("Method not implemented.")}},s=class extends o{constructor(){super(),this.optional=this.optional.bind(this);}optional(){return new T}},y=class a extends s{encodeMutation(n,t,e){return {value:t,_meta:{timestamp:e}}}mergeMutation(n,t,e){return e&&e._meta.timestamp.localeCompare(t._meta.timestamp)>=0?[e,null]:[{value:Number(t.value),_meta:t._meta},t]}static create(){return new a}},M=y.create,c=class a extends s{encodeMutation(n,t,e){return {value:t,_meta:{timestamp:e}}}mergeMutation(n,t,e){return e&&e._meta.timestamp.localeCompare(t._meta.timestamp)>=0?[e,null]:[t,t]}static create(){return new a}},h=c.create;var u=class a extends o{name;fields;relations;constructor(n,t,e){super(),this.name=n,this.fields=t,this.relations=e??{};}encodeMutation(n,t,e){return Object.fromEntries(Object.entries(t).map(([r,i])=>[r,(this.fields[r]??this.relations[r]).encodeMutation("set",i,e)]))}mergeMutation(n,t,e){let r={};return [{value:{...(e==null?void 0:e.value)??{},...Object.fromEntries(Object.entries(t).map(([i,d])=>{let[v,m]=(this.fields[i]??this.relations[i]).mergeMutation(n,d,e==null?void 0:e.value[i]);return m&&(r[i]=m),[i,v]}))}},r]}setRelations(n){return new a(this.name,this.fields,n)}static create(n,t){return new a(n,t)}},A=u.create,l=class a extends o{entity;type;required;relationalColumn;foreignColumn;sourceEntity;constructor(n,t,e,r,i){super(),this.entity=n,this.type=t,this.required=i??false,this.relationalColumn=e,this.foreignColumn=r;}encodeMutation(n,t,e){if(n!=="set")throw new Error("Mutation type not implemented.");if(this.type==="many")throw new Error("Many not implemented.");return {value:t,_meta:{timestamp:e}}}mergeMutation(n,t,e){if(this.type==="many")throw new Error("Many not implemented.");return e&&e._meta.timestamp.localeCompare(t._meta.timestamp)>=0?[e,null]:[t,t]}static createOneFactory(){return (n,t,e)=>new a(n,"one",t,void 0,e??false)}static createManyFactory(){return (n,t,e)=>new a(n,"many",void 0,t,e??false)}},K=(a,n)=>({$type:"relations",objectName:a.name,relations:n({one:l.createOneFactory(),many:l.createManyFactory()})}),p=a=>Array.isArray(a.value)?a.value.map(n=>p(n)):typeof a.value!="object"?a.value:Object.fromEntries(Object.entries(a.value).map(([n,t])=>[n,p(t)])),E=a=>Object.fromEntries(Object.entries(a).flatMap(([n,t])=>{if(t.$type==="relations")return [];let e=t,r=Object.values(a).find(i=>i.$type==="relations"&&i.objectName===t.name);return r&&(e=e.setRelations(r.relations)),[[e.name,e]]}));export{y as LiveNumber,u as LiveObject,c as LiveString,o as LiveType,l as Relation,K as createRelations,E as createSchema,p as inferValue,M as number,A as object,h as string};
1
+ import'./chunk-EK7ODJWE.js';var o=class{_value;_meta;_encodeInput;_decodeInput};var T=class extends o{inner;constructor(e){super(),this.inner=e;}encodeMutation(e,t,n){return this.inner.encodeMutation(e,t,n)}mergeMutation(e,t,n){return this.inner.mergeMutation(e,t,n)}getStorageFieldType(){return {...this.inner.getStorageFieldType(),nullable:true}}},s=class a extends o{storageType;convertFunc;isIndex;isUnique;defaultValue;foreignReference;isPrimary;constructor(e,t,n,r,i,y,c){super(),this.storageType=e,this.convertFunc=t,this.isIndex=n??false,this.isUnique=r??false,this.defaultValue=i,this.foreignReference=y,this.isPrimary=c??false;}encodeMutation(e,t,n){return {value:t,_meta:{timestamp:n}}}mergeMutation(e,t,n){return n&&n._meta.timestamp.localeCompare(t._meta.timestamp)>=0?[n,null]:[{value:this.convertFunc?this.convertFunc(t.value):t.value,_meta:t._meta},t]}getStorageFieldType(){return {type:this.storageType,nullable:false,index:this.isIndex,unique:this.isUnique,default:this.defaultValue,references:this.foreignReference,primary:this.isPrimary}}unique(){return new a(this.storageType,this.convertFunc,this.isIndex,true,this.defaultValue,this.foreignReference,this.isPrimary)}index(){return new a(this.storageType,this.convertFunc,true,this.isUnique,this.defaultValue,this.foreignReference,this.isPrimary)}default(e){return new a(this.storageType,this.convertFunc,this.isIndex,this.isUnique,e,this.foreignReference,this.isPrimary)}primary(){return new a(this.storageType,this.convertFunc,this.isIndex,this.isUnique,this.defaultValue,this.foreignReference,true)}optional(){return new T(this)}},d=class a extends s{constructor(){super("integer",e=>Number(e));}static create(){return new a}},O=d.create,l=class a extends s{constructor(e){super("varchar",void 0,void 0,void 0,void 0,e);}static create(){return new a}static createId(){return new a().index().unique().primary()}static createReference(e){return new a(e)}},j=l.create,S=l.createId,w=l.createReference,p=class a extends s{constructor(){super("boolean",e=>typeof e=="string"?e.toLowerCase()==="true":!!e);}static create(){return new a}},I=p.create,m=class a extends s{constructor(){super("timestamp",e=>typeof e=="string"?new Date(e):e);}static create(){return new a}},A=m.create;var v=class a extends o{name;fields;relations;constructor(e,t,n){super(),this.name=e,this.fields=t,this.relations=n??{};}encodeMutation(e,t,n){return Object.fromEntries(Object.entries(t).map(([r,i])=>[r,(this.fields[r]??this.relations[r]).encodeMutation("set",i,n)]))}mergeMutation(e,t,n){let r={};return [{value:{...(n==null?void 0:n.value)??{},...Object.fromEntries(Object.entries(t).map(([i,y])=>{let[c,f]=(this.fields[i]??this.relations[i]).mergeMutation(e,y,n==null?void 0:n.value[i]);return f&&(r[i]=f),[i,c]}))}},r]}setRelations(e){return new a(this.name,this.fields,e)}getStorageFieldType(){throw new Error("Method not implemented.")}static create(e,t){return new a(e,t)}},P=v.create,u=class a extends o{entity;type;required;relationalColumn;foreignColumn;sourceEntity;constructor(e,t,n,r,i){super(),this.entity=e,this.type=t,this.required=i??false,this.relationalColumn=n,this.foreignColumn=r;}encodeMutation(e,t,n){if(e!=="set")throw new Error("Mutation type not implemented.");if(this.type==="many")throw new Error("Many not implemented.");return {value:t,_meta:{timestamp:n}}}mergeMutation(e,t,n){if(this.type==="many")throw new Error("Many not implemented.");return n&&n._meta.timestamp.localeCompare(t._meta.timestamp)>=0?[n,null]:[t,t]}getStorageFieldType(){return {type:"varchar",nullable:!this.required,references:`${this.entity.name}.${String(this.foreignColumn??this.relationalColumn??"id")}`}}static createOneFactory(){return (e,t,n)=>new a(e,"one",t,void 0,n??false)}static createManyFactory(){return (e,t,n)=>new a(e,"many",void 0,t,n??false)}},D=(a,e)=>({$type:"relations",objectName:a.name,relations:e({one:u.createOneFactory(),many:u.createManyFactory()})}),h=a=>{if(a)return Array.isArray(a.value)?a.value.map(e=>h(e)):typeof a.value!="object"?a.value:Object.fromEntries(Object.entries(a.value).map(([e,t])=>[e,h(t)]))},k=a=>Object.fromEntries(Object.entries(a).flatMap(([e,t])=>{if(t.$type==="relations")return [];let n=t,r=Object.values(a).find(i=>i.$type==="relations"&&i.objectName===t.name);return r&&(n=n.setRelations(r.relations)),[[n.name,n]]}));export{p as LiveBoolean,d as LiveNumber,v as LiveObject,l as LiveString,m as LiveTimestamp,o as LiveType,u as Relation,I as boolean,D as createRelations,k as createSchema,S as id,h as inferValue,O as number,P as object,w as reference,j as string,A as timestamp};
package/dist/server.cjs CHANGED
@@ -1 +1,2 @@
1
- 'use strict';var nanoid=require('nanoid'),zod=require('zod');var y=class{},S=class extends y{storage={};async updateSchema(e){console.log("Updating schema",e),this.storage=Object.entries(e).reduce((r,[s,i])=>(r[i.name]={},r),{});}async findById(e,r){var s;return (s=this.storage[e])==null?void 0:s[r]}async find(e,r){return this.storage[e]??{}}async upsert(e,r,s){return this.storage[e]??={},this.storage[e][r]=s,s}};var d=zod.z.string().nanoid(),v=zod.z.object({_id:d,type:zod.z.literal("SUBSCRIBE"),resource:zod.z.string()}),q=zod.z.object({_id:d,type:zod.z.literal("SYNC"),lastSyncedAt:zod.z.string().optional(),resources:zod.z.string().array().optional()}),R=zod.z.record(zod.z.object({value:zod.z.string().or(zod.z.number()).or(zod.z.boolean()).or(zod.z.date()),_meta:zod.z.object({timestamp:zod.z.string().optional()}).optional()})).superRefine((a,e)=>{a.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),T=zod.z.object({_id:d,type:zod.z.literal("MUTATE"),resource:zod.z.string(),resourceId:zod.z.string(),payload:R}),b=zod.z.union([v,T,q]),x=zod.z.object({_id:d,type:zod.z.literal("SYNC"),resource:zod.z.string(),data:zod.z.record(R)}),j=zod.z.object({_id:d,type:zod.z.literal("REJECT"),resource:zod.z.string()});zod.z.union([T,x,j]);var _=a=>{let e={},r={};return a.subscribeToMutations(s=>{console.log("Mutation propagated:",s),Object.entries(r[s.resource]??{}).forEach(([i,p])=>{var o;(o=e[i])==null||o.send(JSON.stringify(s));});}),s=>{let i=nanoid.nanoid();e[i]=s,console.log("Client connected:",i),s.on("message",async p=>{try{console.log("Message received from the client:",p);let o=b.parse(JSON.parse(p.toString()));if(o.type==="SUBSCRIBE"){let{resource:n}=o;r[n]||(r[n]={}),r[n][i]={};}else if(o.type==="SYNC"){let{resources:n}=o,c=n??Object.keys(a.schema);console.log("Syncing resources:",c),await Promise.all(c.map(async u=>{let l=await a.handleRequest({req:{type:"FIND",resourceName:u,context:{}}});if(!l||!l.data)throw new Error("Invalid resource");s.send(JSON.stringify({_id:o._id,type:"SYNC",resource:u,data:Object.fromEntries(Object.entries(l.data??{}).map(([f,M])=>[f,M.value]))}));}));}else if(o.type==="MUTATE"){let{resource:n}=o;console.log("Received mutation from client:",o);try{let c=await a.handleRequest({req:{type:"SET",resourceName:n,payload:o.payload,context:{messageId:o._id},resourceId:o.resourceId}}).catch(u=>(console.error("Error handling mutation from the client:",u),null));(!c||!c.acceptedValues||Object.keys(c.acceptedValues).length===0)&&s.send(JSON.stringify({_id:o._id,type:"REJECT",resource:n}));}catch(c){s.send(JSON.stringify({_id:o._id,type:"REJECT",resource:n})),console.error("Error parsing mutation from the client:",c);}}}catch(o){console.error("Error handling message from the client:",o);}}),s.on("close",()=>{console.log("Connection closed",i),delete e[i];});}};var g=class a{routes;constructor(e){this.routes=e.routes;}static create(e){return new a(e)}},V=a=>g.create({...a}),h=class{shape;constructor(e){this.shape=e;}async handleFind(e){return {data:await e.db.find(e.req.resourceName,e.req.where),acceptedValues:null}}async handleSet(e){if(!e.req.payload)throw new Error("Payload is required");if(!e.req.resourceId)throw new Error("ResourceId is required");let r=await e.db.findById(e.req.resourceName,e.req.resourceId),[s,i]=this.shape.mergeMutation("set",e.req.payload,r);if(!i){if(!r)throw new Error("Mutation rejected");return {data:r,acceptedValues:null}}return {data:await e.db.upsert(e.req.resourceName,e.req.resourceId,s),acceptedValues:i}}async handleRequest(e){switch(e.req.type){case "FIND":return this.handleFind(e);case "SET":return this.handleSet(e);default:throw new Error("Invalid request type")}}},Z=()=>a=>new h(a),m=class a{router;storage;schema;mutationSubscriptions=new Set;constructor(e){this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.storage.updateSchema(this.schema);}static create(e){return new a(e)}subscribeToMutations(e){return this.mutationSubscriptions.add(e),()=>{this.mutationSubscriptions.delete(e);}}async handleRequest(e){var s;let r=await((s=this.router.routes[e.req.resourceName])==null?void 0:s.handleRequest({req:e.req,db:this.storage}));return r&&e.req.type==="SET"&&r.acceptedValues&&Object.keys(r.acceptedValues).length>0&&this.mutationSubscriptions.forEach(i=>{i({_id:e.req.context.messageId??nanoid.nanoid(),type:"MUTATE",resource:e.req.resourceName,payload:r.acceptedValues??{},resourceId:e.req.resourceId});}),r}},k=m.create;exports.InMemoryStorage=S;exports.Route=h;exports.Router=g;exports.Server=m;exports.Storage=y;exports.routeFactory=Z;exports.router=V;exports.server=k;exports.webSocketAdapter=_;
1
+ 'use strict';var Se=require('qs'),zod=require('zod'),I=require('crypto'),kysely=require('kysely');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var Se__default=/*#__PURE__*/_interopDefault(Se);var I__default=/*#__PURE__*/_interopDefault(I);var oe=Object.create;var U=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ce=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var de=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var le=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of se(e))!ue.call(r,a)&&a!==t&&U(r,a,{get:()=>e[a],enumerable:!(n=ie(e,a))||n.enumerable});return r};var V=(r,e,t)=>(t=r!=null?oe(ce(r)):{},le(U(t,"default",{value:r,enumerable:true}),r));var P=de(E=>{Object.defineProperty(E,"__esModule",{value:true});E.parse=Te;E.serialize=Re;var pe=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,me=/^[\u0021-\u003A\u003C-\u007E]*$/,ye=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,fe=/^[\u0020-\u003A\u003D-\u007E]*$/,he=Object.prototype.toString,ge=(()=>{let r=function(){};return r.prototype=Object.create(null),r})();function Te(r,e){let t=new ge,n=r.length;if(n<2)return t;let a=(e==null?void 0:e.decode)||xe,o=0;do{let i=r.indexOf("=",o);if(i===-1)break;let u=r.indexOf(";",o),s=u===-1?n:u;if(i>s){o=r.lastIndexOf(";",i-1)+1;continue}let h=_(r,o,i),m=$(r,i,h),l=r.slice(h,m);if(t[l]===void 0){let p=_(r,i+1,s),d=$(r,s,p),c=a(r.slice(p,d));t[l]=c;}o=s+1;}while(o<n);return t}function _(r,e,t){do{let n=r.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function $(r,e,t){for(;e>t;){let n=r.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function Re(r,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!pe.test(r))throw new TypeError(`argument name is invalid: ${r}`);let a=n(e);if(!me.test(a))throw new TypeError(`argument val is invalid: ${e}`);let o=r+"="+a;if(!t)return o;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);o+="; Max-Age="+t.maxAge;}if(t.domain){if(!ye.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);o+="; Domain="+t.domain;}if(t.path){if(!fe.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);o+="; Path="+t.path;}if(t.expires){if(!be(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);o+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(o+="; HttpOnly"),t.secure&&(o+="; Secure"),t.partitioned&&(o+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":o+="; Priority=Low";break;case "medium":o+="; Priority=Medium";break;case "high":o+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${t.priority}`)}if(t.sameSite)switch(typeof t.sameSite=="string"?t.sameSite.toLowerCase():t.sameSite){case true:case "strict":o+="; SameSite=Strict";break;case "lax":o+="; SameSite=Lax";break;case "none":o+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return o}function xe(r){if(r.indexOf("%")===-1)return r;try{return decodeURIComponent(r)}catch{return r}}function be(r){return he.call(r)==="[object Date]"}});var H=V(P());var q=zod.z.object({type:zod.z.literal("QUERY"),resource:zod.z.string(),where:zod.z.record(zod.z.any()).optional(),include:zod.z.record(zod.z.any()).optional()}),L=zod.z.record(zod.z.object({value:zod.z.string().or(zod.z.number()).or(zod.z.boolean()).or(zod.z.date()),_meta:zod.z.object({timestamp:zod.z.string().optional()}).optional()})).superRefine((r,e)=>{r.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),F=zod.z.object({id:zod.z.string().optional(),type:zod.z.literal("MUTATE"),resource:zod.z.string()}),S=F.extend({procedure:zod.z.string(),payload:zod.z.any().optional()}),M=F.extend({resourceId:zod.z.string(),payload:L});zod.z.union([S,M]);var Z=q.omit({type:true,resource:true}),N=S.omit({id:true,type:true,resource:true,procedure:true}),j=M.omit({id:true,type:true,resource:true});zod.z.union([j,N]);var G=r=>async e=>{var t;try{let n=typeof e.headers.getSetCookie=="function"?Object.fromEntries(e.headers):e.headers,a={headers:n,cookies:n.cookie?H.default.parse(n.cookie):{}},o=new URL(e.url),i=o.pathname.split("/"),u=o.searchParams,s=Se__default.default.parse(u.toString()),h=await((t=r.contextProvider)==null?void 0:t.call(r,{transport:"HTTP",headers:a.headers,cookies:a.cookies,query:s}))??{};if(e.method==="GET"){let m=i[i.length-1],{success:l,data:p,error:d}=Z.safeParse(s);if(!l)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:d},{status:400});let c=await r.handleRequest({req:{...a,type:"QUERY",resourceName:m,context:h,where:p.where,query:s}});return !c||!c.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(c.data)}if(e.method==="POST")try{let m=i[i.length-1],l=i[i.length-2],p=e.body?await e.json():{},d;if(m==="set"){let{success:b,data:g,error:w}=j.safeParse(p);if(!b)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:w},{status:400});d=g;}else {let{success:b,data:g,error:w}=N.safeParse(p);if(!b)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:w},{status:400});d=g;}let c=await r.handleRequest({req:{...a,type:"MUTATE",resourceName:l,input:d.payload,context:h,resourceId:d.resourceId,procedure:m!=="set"?m:void 0,query:{}}});return Response.json(c)}catch(m){return console.error("Error parsing mutation from the client:",m),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(n){return console.error("Unexpected error:",n),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}};var X=V(P());var T=zod.z.string(),Me=zod.z.object({id:T,type:zod.z.literal("SUBSCRIBE"),resource:zod.z.string()}),ve=zod.z.object({id:T,type:zod.z.literal("SYNC"),lastSyncedAt:zod.z.string().optional(),resources:zod.z.string().array().optional(),where:zod.z.record(zod.z.any()).optional()}),B=M.extend({id:T}),Ee=S.extend({id:T}),Ie=zod.z.union([Ee,B]),Q=zod.z.union([Me,ve,Ie]),Ae=zod.z.object({id:T,type:zod.z.literal("SYNC"),resource:zod.z.string(),data:zod.z.record(L)}),Pe=zod.z.object({id:T,type:zod.z.literal("REJECT"),resource:zod.z.string(),message:zod.z.string().optional()}),Le=zod.z.object({id:T,type:zod.z.literal("REPLY"),data:zod.z.any()});zod.z.union([Ae,Pe,Le,B]);var K="0123456789ABCDEFGHJKMNPQRSTVWXYZ",v=32;var Ne=16,Y=10,W=0xffffffffffff;var R;(function(r){r.Base32IncorrectEncoding="B32_ENC_INVALID",r.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",r.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",r.EncodeTimeNegative="ENC_TIME_NEG",r.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",r.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",r.PRNGDetectFailure="PRNG_DETECT",r.ULIDInvalid="ULID_INVALID",r.Unexpected="UNEXPECTED",r.UUIDInvalid="UUID_INVALID";})(R||(R={}));var x=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function je(r){let e=Math.floor(r()*v);return e===v&&(e=v-1),K.charAt(e)}function Oe(r){var n;let e=Ce(),t=e&&(e.crypto||e.msCrypto)||(typeof I__default.default<"u"?I__default.default:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let a=new Uint8Array(1);return t.getRandomValues(a),a[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=I__default.default)!=null&&n.randomBytes)return ()=>I__default.default.randomBytes(1).readUInt8()/255;throw new x(R.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Ce(){return De()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function ze(r,e){let t="";for(;r>0;r--)t=je(e)+t;return t}function ke(r,e=Y){if(isNaN(r))throw new x(R.EncodeTimeValueMalformed,`Time must be a number: ${r}`);if(r>W)throw new x(R.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${W}: ${r}`);if(r<0)throw new x(R.EncodeTimeNegative,`Time must be positive: ${r}`);if(Number.isInteger(r)===false)throw new x(R.EncodeTimeValueMalformed,`Time must be an integer: ${r}`);let t,n="";for(let a=e;a>0;a--)t=r%v,n=K.charAt(t)+n,r=(r-t)/v;return n}function De(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function J(r,e){let t=Oe(),n=Date.now();return ke(n,Y)+ze(Ne,t)}var O=()=>J().toLowerCase();var ee=r=>{let e={},t={};return r.subscribeToMutations(n=>{let a=n;!a.resourceId||!a.payload||(console.log("Mutation propagated:",a),Object.entries(t[a.resource]??{}).forEach(([o,i])=>{var u;(u=e[o])==null||u.send(JSON.stringify({...a,id:a.id??O()}));}));}),(n,a)=>{var m;let o=l=>{n.send(JSON.stringify(l));},i=O(),u={headers:a.headers,cookies:typeof a.headers.cookie=="string"?X.default.parse(a.headers.cookie):{}},s=Se.parse(a.url.split("?")[1]),h=(m=r.contextProvider)==null?void 0:m.call(r,{transport:"WEBSOCKET",headers:u.headers,cookies:u.cookies,query:s});e[i]=n,console.log("Client connected:",i),n.on("message",async l=>{try{console.log("Message received from the client:",l);let p=Q.parse(JSON.parse(l.toString()));if(p.type==="SUBSCRIBE"){let{resource:d}=p;t[d]||(t[d]={}),t[d][i]={};}else if(p.type==="SYNC"){let{resources:d}=p,c=d??Object.keys(r.schema);console.log("Syncing resources:",c),await Promise.all(c.map(async b=>{let g=await r.handleRequest({req:{...u,type:"QUERY",resourceName:b,context:await h??{},query:s}});if(!g||!g.data)throw new Error("Invalid resource");o({id:p.id,type:"SYNC",resource:b,data:Object.fromEntries(Object.entries(g.data??{}).map(([w,ae])=>[w,ae.value]))});}));}else if(p.type==="MUTATE"){let{resource:d}=p;console.log("Received mutation from client:",p);try{let c=await r.handleRequest({req:{...u,type:"MUTATE",resourceName:d,input:p.payload,context:{messageId:p.id,...await h??{}},resourceId:p.resourceId,procedure:p.procedure,query:s}});p.procedure&&o({id:p.id,type:"REPLY",data:c});}catch(c){o({id:p.id,type:"REJECT",resource:d,message:c.message}),console.error("Error parsing mutation from the client:",c);}}}catch(p){console.error("Error handling message from the client:",p);}}),n.on("close",()=>{console.log("Connection closed",i),delete e[i];for(let l of Object.values(t))delete l[i];});}};function te(r){let e=`${r.protocol}://${r.hostname}${r.url}`,t=new Headers;return Object.entries(r.headers).forEach(([n,a])=>{a&&t.set(n,Array.isArray(a)?a.join(","):a);}),new Request(e,{method:r.method,headers:t,body:r.body&&r.method!=="GET"?JSON.stringify(r.body):void 0})}var xt=(r,e,t)=>{r.ws(`${(t==null?void 0:t.basePath)??""}/ws`,ee(e)),r.use(`${(t==null?void 0:t.basePath)??""}/`,(n,a)=>{G(e)(te(n)).then(i=>i.json().then(u=>a.status(i.status).send(u)));});};var C=class r{routes;constructor(e){this.routes=e.routes;}static create(e){return new r(e)}},Mt=r=>C.create({...r}),_e=r=>({handler:e=>({inputValidator:r??zod.z.undefined(),handler:e})}),z=class r{_resourceSchema;resourceName;middlewares;customMutations;constructor(e,t){this.resourceName=e,this.middlewares=new Set,this.customMutations=t??{};}handleFind=async({req:e,db:t})=>({data:await t.find(e.resourceName,e.where),acceptedValues:null});handleSet=async({req:e,db:t,schema:n})=>{if(!e.input)throw new Error("Payload is required");if(!e.resourceId)throw new Error("ResourceId is required");let a=await t.findById(e.resourceName,e.resourceId),[o,i]=n[this.resourceName].mergeMutation("set",e.input,a);if(!i)throw new Error("Mutation rejected");return {data:await t.upsert(e.resourceName,e.resourceId,o),acceptedValues:i}};async handleRequest(e){let t=n=>(()=>{if(n.type==="QUERY")return this.handleFind({req:n,db:e.db,schema:e.schema});if(n.type==="MUTATE")if(n.procedure){if(this.customMutations[n.procedure]){let a=this.customMutations[n.procedure].inputValidator.parse(n.input);return n.input=a,this.customMutations[n.procedure].handler({req:n,db:e.db,schema:e.schema})}}else return this.handleSet({req:n,db:e.db,schema:e.schema});throw new Error("Invalid request")})();return await Array.from(this.middlewares.values()).reduceRight((n,a)=>o=>a({req:o,next:n}),async n=>t(n))(e.req)}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new r(this.resourceName,e({mutation:_e}))}},k=class r{middlewares;constructor(e=[]){this.middlewares=e;}createBasicRoute(e){return new z(e.name).use(...this.middlewares)}use(...e){return new r([...this.middlewares,...e])}static create(){return new r}},vt=k.create;var A=class{},re=class extends A{storage={};async updateSchema(e){this.storage=Object.entries(e).reduce((t,[n,a])=>(t[a.name]={},t),{});}async findById(e,t){var n;return (n=this.storage[e])==null?void 0:n[t]}async find(e,t){return this.storage[e]??{}}async upsert(e,t,n){return this.storage[e]??={},this.storage[e][t]=n,n}},ne=class extends A{db;schema;constructor(e){super(),this.db=new kysely.Kysely({dialect:new kysely.PostgresDialect({pool:e})});}async updateSchema(e){this.schema=e;let t=await this.db.introspection.getTables();for(let[n,a]of Object.entries(e)){let o=t.find(s=>s.name===n);o||await this.db.schema.createTable(n).ifNotExists().execute();let i=`${n}_meta`,u=t.find(s=>s.name===i);u||await this.db.schema.createTable(i).ifNotExists().execute();for(let[s,h]of Object.entries(a.fields)){let m=o==null?void 0:o.columns.find(d=>d.name===s),l=h.getStorageFieldType();m?m.dataType!==l.type&&console.error("Column type mismatch:",s,"expected to have type:",l.type,"but has type:",m.dataType):(await this.db.schema.alterTable(n).addColumn(s,l.type,d=>{let c=d;return l.unique&&(c=c.unique()),l.nullable||(c=c.notNull()),l.references&&(c=c.references(l.references)),l.primary&&(c=c.primaryKey()),l.default!==void 0&&(c=c.defaultTo(l.default)),c}).execute().catch(d=>{throw console.error("Error adding column",s,d),d}),l.index&&await this.db.schema.createIndex(`${n}_${s}_index`).on(n).column(s).execute().catch(d=>{})),(u==null?void 0:u.columns.find(d=>d.name===s))||await this.db.schema.alterTable(i).addColumn(s,"varchar",d=>{let c=d;return l.primary&&(c=c.primaryKey().references(`${n}.${s}`)),c}).execute();}}}async findById(e,t){let n=await this.db.selectFrom(e).where("id","=",t).selectAll(e).executeTakeFirst(),a=await this.db.selectFrom(`${e}_meta`).where("id","=",t).selectAll(`${e}_meta`).executeTakeFirst();if(!(!n||!a))return this.convertToMaterializedLiveType(n,a)}async find(e,t){let a=await this.applyWhere(e,this.db.selectFrom(e).selectAll(e),t).execute(),o=Object.fromEntries(a.map(s=>{let{id:h,...m}=s;return [h,m]}));if(Object.keys(o).length===0)return {};let i=Object.fromEntries((await this.db.selectFrom(`${e}_meta`).selectAll().where("id","in",Object.keys(o)).execute()).map(s=>{let{id:h,...m}=s;return [h,m]}));return Object.entries(o).reduce((s,[h,m])=>(i[h]&&(s[h]=this.convertToMaterializedLiveType(m,i[h])),s),{})}async upsert(e,t,n){return await this.db.transaction().execute(async a=>{let o=!!await a.selectFrom(e).select("id").where("id","=",t).executeTakeFirst(),i={},u={};for(let[s,h]of Object.entries(n.value))i[s]=h.value,u[s]=h._meta.timestamp;o?await Promise.all([a.updateTable(e).set(i).where("id","=",t).execute(),a.updateTable(`${e}_meta`).set(u).where("id","=",t).execute()]):await Promise.all([a.insertInto(e).values({...i,id:t}).execute(),a.insertInto(`${e}_meta`).values({...u,id:t}).execute()]);}),n}convertToMaterializedLiveType(e,t){return {value:Object.fromEntries(Object.entries(e).flatMap(([n,a])=>t?[[n,{value:a,_meta:{timestamp:t==null?void 0:t[n]}}]]:[]))}}applyWhere(e,t,n){if(!n)return t;if(!this.schema)throw new Error("Schema not initialized");let a=this.schema[e];if(!a)throw new Error("Resource not found");for(let[o,i]of Object.entries(n))if(a.fields[o])t=t.where(`${e}.${o}`,"=",i);else if(a.relations[o]){let u=a.relations[o],s=u.entity.name,h=u.type==="one"?"id":u.foreignColumn,m=u.type==="one"?u.relationalColumn:"id";t=t.leftJoin(s,`${s}.${h}`,`${e}.${m}`),t=this.applyWhere(s,t,i);}return t}};var D=class r{router;storage;schema;middlewares=new Set;contextProvider;mutationSubscriptions=new Set;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,(t=e.middlewares)==null||t.forEach(n=>this.middlewares.add(n)),this.storage.updateSchema(this.schema),this.contextProvider=e.contextProvider;}static create(e){return new r(e)}subscribeToMutations(e){return this.mutationSubscriptions.add(e),()=>{this.mutationSubscriptions.delete(e);}}async handleRequest(e){if(!this.router.routes[e.req.resourceName])throw new Error("Invalid resource");let t=await Array.from(this.middlewares.values()).reduceRight((n,a)=>o=>a({req:o,next:n}),async n=>this.router.routes[e.req.resourceName].handleRequest({req:n,db:this.storage,schema:this.schema}))(e.req);return t&&e.req.type==="MUTATE"&&t.acceptedValues&&Object.keys(t.acceptedValues).length>0&&this.mutationSubscriptions.forEach(n=>{n({id:e.req.context.messageId,type:"MUTATE",resource:e.req.resourceName,payload:t.acceptedValues??{},resourceId:e.req.resourceId});}),t}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}},Nt=D.create;
2
+ exports.InMemoryStorage=re;exports.Route=z;exports.RouteFactory=k;exports.Router=C;exports.SQLStorage=ne;exports.Server=D;exports.Storage=A;exports.expressAdapter=xt;exports.routeFactory=vt;exports.router=Mt;exports.server=Nt;
package/dist/server.d.cts CHANGED
@@ -1,6 +1,148 @@
1
- import { S as Schema, L as LiveObjectAny, M as MaterializedLiveType, a as MutationMessage } from './index-sSVirsfN.cjs';
2
- import WebSocket from 'ws';
3
- import 'zod';
1
+ import { z, ZodTypeAny } from 'zod';
2
+ import { LiveObjectAny, Schema, MaterializedLiveType, WhereClause } from './index.cjs';
3
+ import { PostgresPool } from 'kysely';
4
+ import { Application } from 'express-ws';
5
+
6
+ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
7
+ id: z.ZodOptional<z.ZodString>;
8
+ type: z.ZodLiteral<"MUTATE">;
9
+ resource: z.ZodString;
10
+ }, {
11
+ procedure: z.ZodString;
12
+ payload: z.ZodOptional<z.ZodAny>;
13
+ }>, "strip", z.ZodTypeAny, {
14
+ procedure: string;
15
+ type: "MUTATE";
16
+ resource: string;
17
+ id?: string | undefined;
18
+ payload?: any;
19
+ }, {
20
+ procedure: string;
21
+ type: "MUTATE";
22
+ resource: string;
23
+ id?: string | undefined;
24
+ payload?: any;
25
+ }>, z.ZodObject<z.objectUtil.extendShape<{
26
+ id: z.ZodOptional<z.ZodString>;
27
+ type: z.ZodLiteral<"MUTATE">;
28
+ resource: z.ZodString;
29
+ }, {
30
+ resourceId: z.ZodString;
31
+ payload: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
32
+ value: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodNumber]>, z.ZodBoolean]>, z.ZodDate]>;
33
+ _meta: z.ZodOptional<z.ZodObject<{
34
+ timestamp: z.ZodOptional<z.ZodString>;
35
+ }, "strip", z.ZodTypeAny, {
36
+ timestamp?: string | undefined;
37
+ }, {
38
+ timestamp?: string | undefined;
39
+ }>>;
40
+ }, "strip", z.ZodTypeAny, {
41
+ value: string | number | boolean | Date;
42
+ _meta?: {
43
+ timestamp?: string | undefined;
44
+ } | undefined;
45
+ }, {
46
+ value: string | number | boolean | Date;
47
+ _meta?: {
48
+ timestamp?: string | undefined;
49
+ } | undefined;
50
+ }>>, Record<string, {
51
+ value: string | number | boolean | Date;
52
+ _meta?: {
53
+ timestamp?: string | undefined;
54
+ } | undefined;
55
+ }>, Record<string, {
56
+ value: string | number | boolean | Date;
57
+ _meta?: {
58
+ timestamp?: string | undefined;
59
+ } | undefined;
60
+ }>>;
61
+ }>, "strip", z.ZodTypeAny, {
62
+ type: "MUTATE";
63
+ resourceId: string;
64
+ resource: string;
65
+ payload: Record<string, {
66
+ value: string | number | boolean | Date;
67
+ _meta?: {
68
+ timestamp?: string | undefined;
69
+ } | undefined;
70
+ }>;
71
+ id?: string | undefined;
72
+ }, {
73
+ type: "MUTATE";
74
+ resourceId: string;
75
+ resource: string;
76
+ payload: Record<string, {
77
+ value: string | number | boolean | Date;
78
+ _meta?: {
79
+ timestamp?: string | undefined;
80
+ } | undefined;
81
+ }>;
82
+ id?: string | undefined;
83
+ }>]>;
84
+ type RawMutationRequest = z.infer<typeof mutationSchema>;
85
+
86
+ type RouteRecord = Record<string, AnyRoute>;
87
+ declare class Router<TRoutes extends RouteRecord> {
88
+ readonly routes: TRoutes;
89
+ private constructor();
90
+ static create<TRoutes extends RouteRecord>(opts: {
91
+ routes: TRoutes;
92
+ }): Router<TRoutes>;
93
+ }
94
+ declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, AnyRoute>>(opts: {
95
+ schema: TSchema;
96
+ routes: TRoutes;
97
+ }) => Router<TRoutes>;
98
+ type AnyRouter = Router<RouteRecord>;
99
+ type QueryResult<TShape extends LiveObjectAny> = {
100
+ data: Record<string, MaterializedLiveType<TShape>>;
101
+ };
102
+ type MutationResult<TShape extends LiveObjectAny> = {
103
+ data: MaterializedLiveType<TShape>;
104
+ acceptedValues: Record<string, any> | null;
105
+ };
106
+ type RequestHandler<TInput, TResult, TSchema extends Schema<any> = Schema<any>> = (opts: {
107
+ req: ParsedRequest<TInput>;
108
+ db: Storage;
109
+ schema: TSchema;
110
+ }) => Promise<TResult>;
111
+ type Mutation<TInputValidator extends ZodTypeAny, // TODO use StandardSchema instead
112
+ THandler extends RequestHandler<z.infer<TInputValidator>, any, any>> = {
113
+ inputValidator: TInputValidator;
114
+ handler: THandler;
115
+ };
116
+ declare const mutationCreator: <TInputValidator extends ZodTypeAny>(validator?: TInputValidator) => {
117
+ handler: <THandler extends RequestHandler<z.infer<TInputValidator>, any, any>>(handler: THandler) => Mutation<TInputValidator, THandler>;
118
+ };
119
+ declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, RequestHandler<any, any>>>> {
120
+ readonly _resourceSchema: TResourceSchema;
121
+ readonly resourceName: TResourceSchema["name"];
122
+ readonly middlewares: Set<TMiddleware>;
123
+ readonly customMutations: TCustomMutations;
124
+ constructor(resourceName: TResourceSchema["name"], customMutations?: TCustomMutations);
125
+ private handleFind;
126
+ private handleSet;
127
+ handleRequest(opts: {
128
+ req: ParsedRequest;
129
+ db: Storage;
130
+ schema: Schema<any>;
131
+ }): Promise<any>;
132
+ use(...middlewares: TMiddleware[]): this;
133
+ withMutations<T extends Record<string, Mutation<any, RequestHandler<any, any>>>>(mutationFactory: (opts: {
134
+ mutation: typeof mutationCreator;
135
+ }) => T): Route<TResourceSchema, TMiddleware, T>;
136
+ }
137
+ declare class RouteFactory {
138
+ private middlewares;
139
+ private constructor();
140
+ createBasicRoute<T extends LiveObjectAny>(shape: T): Route<T, Middleware<any>, Record<string, never>>;
141
+ use(...middlewares: Middleware<any>[]): RouteFactory;
142
+ static create(): RouteFactory;
143
+ }
144
+ declare const routeFactory: typeof RouteFactory.create;
145
+ type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>>;
4
146
 
5
147
  declare abstract class Storage {
6
148
  abstract updateSchema(opts: Schema<any>): Promise<void>;
@@ -15,74 +157,66 @@ declare class InMemoryStorage extends Storage {
15
157
  find<T extends LiveObjectAny>(resourceName: string, where?: Record<string, any>): Promise<Record<string, MaterializedLiveType<T>>>;
16
158
  upsert<T extends LiveObjectAny>(resourceName: string, resourceId: string, value: MaterializedLiveType<T>): Promise<MaterializedLiveType<T>>;
17
159
  }
160
+ declare class SQLStorage extends Storage {
161
+ private db;
162
+ private schema?;
163
+ constructor(pool: PostgresPool);
164
+ updateSchema(opts: Schema<any>): Promise<void>;
165
+ findById<T extends LiveObjectAny>(resourceName: string, id: string): Promise<MaterializedLiveType<T> | undefined>;
166
+ find<T extends LiveObjectAny>(resourceName: string, where?: WhereClause<T>): Promise<Record<string, MaterializedLiveType<T>>>;
167
+ upsert<T extends LiveObjectAny>(resourceName: string, resourceId: string, value: MaterializedLiveType<T>): Promise<MaterializedLiveType<T>>;
168
+ private convertToMaterializedLiveType;
169
+ private applyWhere;
170
+ }
18
171
 
19
- type Subscription = {
20
- filters?: Record<string, any>;
21
- };
22
- declare const webSocketAdapter: (server: Server<AnyRouter>) => (ws: WebSocket) => void;
172
+ declare const expressAdapter: (app: Application, server: Server<AnyRouter>, options?: {
173
+ basePath?: string;
174
+ }) => void;
23
175
 
24
- type RequestBase = {
176
+ type ParsedRequest<TInput = any> = {
177
+ headers: Record<string, string>;
178
+ cookies: Record<string, string>;
179
+ query: Record<string, string>;
25
180
  resourceName: string;
181
+ procedure?: string;
26
182
  context: Record<string, any>;
27
183
  where?: Record<string, any>;
184
+ type: "QUERY" | "MUTATE";
185
+ resourceId?: string;
186
+ input?: TInput;
28
187
  };
29
- type FindRequest = RequestBase & {
30
- type: "FIND";
31
- };
32
- type SetRequest = RequestBase & {
33
- type: "SET";
34
- resourceId: string;
35
- payload: Record<string, any>;
36
- };
37
- type Request = FindRequest | SetRequest;
38
- type RequestType = Request["type"];
39
- type RouteRecord = Record<string, Route<LiveObjectAny>>;
40
- declare class Router<TSchema extends Schema<any>, TRoutes extends RouteRecord> {
41
- readonly routes: TRoutes;
42
- private constructor();
43
- static create<TSchema extends Schema<any>, TRoutes extends RouteRecord>(opts: {
44
- routes: TRoutes;
45
- }): Router<TSchema, TRoutes>;
46
- }
47
- declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<LiveObjectAny>>>(opts: {
48
- schema: TSchema;
49
- routes: TRoutes;
50
- }) => Router<Schema<any>, TRoutes>;
51
- type AnyRouter = Router<Schema<any>, RouteRecord>;
52
- type RouteResult<TShape extends LiveObjectAny> = {
53
- data: MaterializedLiveType<TShape> | Record<string, MaterializedLiveType<TShape>>;
54
- acceptedValues: Record<string, any> | null;
55
- };
56
- declare class Route<TShape extends LiveObjectAny> {
57
- readonly shape: TShape;
58
- constructor(shape: TShape);
59
- private handleFind;
60
- private handleSet;
61
- handleRequest(opts: {
62
- req: Request;
63
- db: Storage;
64
- }): Promise<RouteResult<TShape>>;
65
- }
66
- declare const routeFactory: () => <T extends LiveObjectAny>(shape: T) => Route<T>;
67
- type AnyRoute = Route<LiveObjectAny>;
68
- type ClientId = string;
69
- type MutationHandler = (mutation: MutationMessage) => void;
188
+ type ContextProvider = (req: Pick<ParsedRequest, "headers" | "cookies" | "query"> & {
189
+ transport: "HTTP" | "WEBSOCKET";
190
+ }) => Record<string, any>;
191
+ type RequestType = ParsedRequest["type"];
192
+ type MutationHandler = (mutation: RawMutationRequest) => void;
193
+ type NextFunction<T> = (req: ParsedRequest) => Promise<T> | T;
194
+ type Middleware<T = any> = (opts: {
195
+ req: ParsedRequest;
196
+ next: NextFunction<T>;
197
+ }) => ReturnType<NextFunction<T>>;
70
198
  declare class Server<TRouter extends AnyRouter> {
71
199
  readonly router: TRouter;
72
200
  readonly storage: Storage;
73
201
  readonly schema: Schema<any>;
202
+ readonly middlewares: Set<Middleware<any>>;
203
+ contextProvider?: ContextProvider;
74
204
  private mutationSubscriptions;
75
205
  private constructor();
76
206
  static create<TRouter extends AnyRouter>(opts: {
77
207
  router: TRouter;
78
208
  storage: Storage;
79
209
  schema: Schema<any>;
210
+ middlewares?: Middleware<any>[];
211
+ contextProvider?: ContextProvider;
80
212
  }): Server<TRouter>;
81
213
  subscribeToMutations(handler: MutationHandler): () => void;
82
214
  handleRequest(opts: {
83
- req: Request;
84
- }): Promise<RouteResult<LiveObjectAny>>;
215
+ req: ParsedRequest;
216
+ }): Promise<any>;
217
+ use(middleware: Middleware<any>): this;
218
+ context(contextProvider: ContextProvider): this;
85
219
  }
86
220
  declare const server: typeof Server.create;
87
221
 
88
- export { type AnyRoute, type AnyRouter, type ClientId, type FindRequest, InMemoryStorage, type MutationHandler, type Request, type RequestType, Route, type RouteRecord, Router, Server, type SetRequest, Storage, type Subscription, routeFactory, router, server, webSocketAdapter };
222
+ export { type AnyRoute, type AnyRouter, type ContextProvider, InMemoryStorage, type Middleware, type Mutation, type MutationHandler, type MutationResult, type NextFunction, type ParsedRequest, type QueryResult, type RequestHandler, type RequestType, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };