@live-state/sync 0.0.1-alpha.2 → 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/chunk-NIWX45UD.js +1 -0
- package/dist/client.d.ts +3 -333
- package/dist/client.js +1 -1
- package/dist/fetch-client.d.ts +17 -0
- package/dist/fetch-client.js +1 -0
- package/dist/index-NDRWVwih.d.ts +343 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1 -1
- package/dist/server.cjs +2 -1
- package/dist/server.d.cts +35 -21
- package/dist/server.d.ts +35 -21
- package/dist/server.js +2 -1
- package/package.json +11 -1
package/dist/server.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z, ZodTypeAny } from 'zod';
|
|
2
2
|
import { LiveObjectAny, Schema, MaterializedLiveType, WhereClause } from './index.cjs';
|
|
3
3
|
import { PostgresPool } from 'kysely';
|
|
4
|
-
import
|
|
4
|
+
import { Application } from 'express-ws';
|
|
5
5
|
|
|
6
6
|
declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
7
7
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -9,17 +9,17 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
9
9
|
resource: z.ZodString;
|
|
10
10
|
}, {
|
|
11
11
|
procedure: z.ZodString;
|
|
12
|
-
payload: z.ZodAny
|
|
12
|
+
payload: z.ZodOptional<z.ZodAny>;
|
|
13
13
|
}>, "strip", z.ZodTypeAny, {
|
|
14
|
+
procedure: string;
|
|
14
15
|
type: "MUTATE";
|
|
15
16
|
resource: string;
|
|
16
|
-
procedure: string;
|
|
17
17
|
id?: string | undefined;
|
|
18
18
|
payload?: any;
|
|
19
19
|
}, {
|
|
20
|
+
procedure: string;
|
|
20
21
|
type: "MUTATE";
|
|
21
22
|
resource: string;
|
|
22
|
-
procedure: string;
|
|
23
23
|
id?: string | undefined;
|
|
24
24
|
payload?: any;
|
|
25
25
|
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
@@ -60,6 +60,7 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
60
60
|
}>>;
|
|
61
61
|
}>, "strip", z.ZodTypeAny, {
|
|
62
62
|
type: "MUTATE";
|
|
63
|
+
resourceId: string;
|
|
63
64
|
resource: string;
|
|
64
65
|
payload: Record<string, {
|
|
65
66
|
value: string | number | boolean | Date;
|
|
@@ -67,10 +68,10 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
67
68
|
timestamp?: string | undefined;
|
|
68
69
|
} | undefined;
|
|
69
70
|
}>;
|
|
70
|
-
resourceId: string;
|
|
71
71
|
id?: string | undefined;
|
|
72
72
|
}, {
|
|
73
73
|
type: "MUTATE";
|
|
74
|
+
resourceId: string;
|
|
74
75
|
resource: string;
|
|
75
76
|
payload: Record<string, {
|
|
76
77
|
value: string | number | boolean | Date;
|
|
@@ -78,7 +79,6 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
78
79
|
timestamp?: string | undefined;
|
|
79
80
|
} | undefined;
|
|
80
81
|
}>;
|
|
81
|
-
resourceId: string;
|
|
82
82
|
id?: string | undefined;
|
|
83
83
|
}>]>;
|
|
84
84
|
type RawMutationRequest = z.infer<typeof mutationSchema>;
|
|
@@ -104,7 +104,7 @@ type MutationResult<TShape extends LiveObjectAny> = {
|
|
|
104
104
|
acceptedValues: Record<string, any> | null;
|
|
105
105
|
};
|
|
106
106
|
type RequestHandler<TInput, TResult, TSchema extends Schema<any> = Schema<any>> = (opts: {
|
|
107
|
-
req:
|
|
107
|
+
req: ParsedRequest<TInput>;
|
|
108
108
|
db: Storage;
|
|
109
109
|
schema: TSchema;
|
|
110
110
|
}) => Promise<TResult>;
|
|
@@ -125,16 +125,23 @@ declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends M
|
|
|
125
125
|
private handleFind;
|
|
126
126
|
private handleSet;
|
|
127
127
|
handleRequest(opts: {
|
|
128
|
-
req:
|
|
128
|
+
req: ParsedRequest;
|
|
129
129
|
db: Storage;
|
|
130
130
|
schema: Schema<any>;
|
|
131
131
|
}): Promise<any>;
|
|
132
|
-
use(
|
|
132
|
+
use(...middlewares: TMiddleware[]): this;
|
|
133
133
|
withMutations<T extends Record<string, Mutation<any, RequestHandler<any, any>>>>(mutationFactory: (opts: {
|
|
134
134
|
mutation: typeof mutationCreator;
|
|
135
135
|
}) => T): Route<TResourceSchema, TMiddleware, T>;
|
|
136
136
|
}
|
|
137
|
-
declare
|
|
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;
|
|
138
145
|
type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>>;
|
|
139
146
|
|
|
140
147
|
declare abstract class Storage {
|
|
@@ -162,14 +169,14 @@ declare class SQLStorage extends Storage {
|
|
|
162
169
|
private applyWhere;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
};
|
|
168
|
-
declare const webSocketAdapter: (server: Server<AnyRouter>) => (ws: WebSocket, request: any) => void;
|
|
172
|
+
declare const expressAdapter: (app: Application, server: Server<AnyRouter>, options?: {
|
|
173
|
+
basePath?: string;
|
|
174
|
+
}) => void;
|
|
169
175
|
|
|
170
|
-
type
|
|
176
|
+
type ParsedRequest<TInput = any> = {
|
|
171
177
|
headers: Record<string, string>;
|
|
172
178
|
cookies: Record<string, string>;
|
|
179
|
+
query: Record<string, string>;
|
|
173
180
|
resourceName: string;
|
|
174
181
|
procedure?: string;
|
|
175
182
|
context: Record<string, any>;
|
|
@@ -178,11 +185,14 @@ type Request<TInput = any> = {
|
|
|
178
185
|
resourceId?: string;
|
|
179
186
|
input?: TInput;
|
|
180
187
|
};
|
|
181
|
-
type
|
|
188
|
+
type ContextProvider = (req: Pick<ParsedRequest, "headers" | "cookies" | "query"> & {
|
|
189
|
+
transport: "HTTP" | "WEBSOCKET";
|
|
190
|
+
}) => Record<string, any>;
|
|
191
|
+
type RequestType = ParsedRequest["type"];
|
|
182
192
|
type MutationHandler = (mutation: RawMutationRequest) => void;
|
|
183
|
-
type NextFunction<T> = (req:
|
|
184
|
-
type Middleware<T> = (opts: {
|
|
185
|
-
req:
|
|
193
|
+
type NextFunction<T> = (req: ParsedRequest) => Promise<T> | T;
|
|
194
|
+
type Middleware<T = any> = (opts: {
|
|
195
|
+
req: ParsedRequest;
|
|
186
196
|
next: NextFunction<T>;
|
|
187
197
|
}) => ReturnType<NextFunction<T>>;
|
|
188
198
|
declare class Server<TRouter extends AnyRouter> {
|
|
@@ -190,19 +200,23 @@ declare class Server<TRouter extends AnyRouter> {
|
|
|
190
200
|
readonly storage: Storage;
|
|
191
201
|
readonly schema: Schema<any>;
|
|
192
202
|
readonly middlewares: Set<Middleware<any>>;
|
|
203
|
+
contextProvider?: ContextProvider;
|
|
193
204
|
private mutationSubscriptions;
|
|
194
205
|
private constructor();
|
|
195
206
|
static create<TRouter extends AnyRouter>(opts: {
|
|
196
207
|
router: TRouter;
|
|
197
208
|
storage: Storage;
|
|
198
209
|
schema: Schema<any>;
|
|
210
|
+
middlewares?: Middleware<any>[];
|
|
211
|
+
contextProvider?: ContextProvider;
|
|
199
212
|
}): Server<TRouter>;
|
|
200
213
|
subscribeToMutations(handler: MutationHandler): () => void;
|
|
201
214
|
handleRequest(opts: {
|
|
202
|
-
req:
|
|
215
|
+
req: ParsedRequest;
|
|
203
216
|
}): Promise<any>;
|
|
204
217
|
use(middleware: Middleware<any>): this;
|
|
218
|
+
context(contextProvider: ContextProvider): this;
|
|
205
219
|
}
|
|
206
220
|
declare const server: typeof Server.create;
|
|
207
221
|
|
|
208
|
-
export { type AnyRoute, type AnyRouter, InMemoryStorage, type Middleware, type Mutation, type MutationHandler, type MutationResult, type NextFunction, type
|
|
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 };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z, ZodTypeAny } from 'zod';
|
|
2
2
|
import { LiveObjectAny, Schema, MaterializedLiveType, WhereClause } from './index.js';
|
|
3
3
|
import { PostgresPool } from 'kysely';
|
|
4
|
-
import
|
|
4
|
+
import { Application } from 'express-ws';
|
|
5
5
|
|
|
6
6
|
declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
7
7
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -9,17 +9,17 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
9
9
|
resource: z.ZodString;
|
|
10
10
|
}, {
|
|
11
11
|
procedure: z.ZodString;
|
|
12
|
-
payload: z.ZodAny
|
|
12
|
+
payload: z.ZodOptional<z.ZodAny>;
|
|
13
13
|
}>, "strip", z.ZodTypeAny, {
|
|
14
|
+
procedure: string;
|
|
14
15
|
type: "MUTATE";
|
|
15
16
|
resource: string;
|
|
16
|
-
procedure: string;
|
|
17
17
|
id?: string | undefined;
|
|
18
18
|
payload?: any;
|
|
19
19
|
}, {
|
|
20
|
+
procedure: string;
|
|
20
21
|
type: "MUTATE";
|
|
21
22
|
resource: string;
|
|
22
|
-
procedure: string;
|
|
23
23
|
id?: string | undefined;
|
|
24
24
|
payload?: any;
|
|
25
25
|
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
@@ -60,6 +60,7 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
60
60
|
}>>;
|
|
61
61
|
}>, "strip", z.ZodTypeAny, {
|
|
62
62
|
type: "MUTATE";
|
|
63
|
+
resourceId: string;
|
|
63
64
|
resource: string;
|
|
64
65
|
payload: Record<string, {
|
|
65
66
|
value: string | number | boolean | Date;
|
|
@@ -67,10 +68,10 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
67
68
|
timestamp?: string | undefined;
|
|
68
69
|
} | undefined;
|
|
69
70
|
}>;
|
|
70
|
-
resourceId: string;
|
|
71
71
|
id?: string | undefined;
|
|
72
72
|
}, {
|
|
73
73
|
type: "MUTATE";
|
|
74
|
+
resourceId: string;
|
|
74
75
|
resource: string;
|
|
75
76
|
payload: Record<string, {
|
|
76
77
|
value: string | number | boolean | Date;
|
|
@@ -78,7 +79,6 @@ declare const mutationSchema: z.ZodUnion<[z.ZodObject<z.objectUtil.extendShape<{
|
|
|
78
79
|
timestamp?: string | undefined;
|
|
79
80
|
} | undefined;
|
|
80
81
|
}>;
|
|
81
|
-
resourceId: string;
|
|
82
82
|
id?: string | undefined;
|
|
83
83
|
}>]>;
|
|
84
84
|
type RawMutationRequest = z.infer<typeof mutationSchema>;
|
|
@@ -104,7 +104,7 @@ type MutationResult<TShape extends LiveObjectAny> = {
|
|
|
104
104
|
acceptedValues: Record<string, any> | null;
|
|
105
105
|
};
|
|
106
106
|
type RequestHandler<TInput, TResult, TSchema extends Schema<any> = Schema<any>> = (opts: {
|
|
107
|
-
req:
|
|
107
|
+
req: ParsedRequest<TInput>;
|
|
108
108
|
db: Storage;
|
|
109
109
|
schema: TSchema;
|
|
110
110
|
}) => Promise<TResult>;
|
|
@@ -125,16 +125,23 @@ declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends M
|
|
|
125
125
|
private handleFind;
|
|
126
126
|
private handleSet;
|
|
127
127
|
handleRequest(opts: {
|
|
128
|
-
req:
|
|
128
|
+
req: ParsedRequest;
|
|
129
129
|
db: Storage;
|
|
130
130
|
schema: Schema<any>;
|
|
131
131
|
}): Promise<any>;
|
|
132
|
-
use(
|
|
132
|
+
use(...middlewares: TMiddleware[]): this;
|
|
133
133
|
withMutations<T extends Record<string, Mutation<any, RequestHandler<any, any>>>>(mutationFactory: (opts: {
|
|
134
134
|
mutation: typeof mutationCreator;
|
|
135
135
|
}) => T): Route<TResourceSchema, TMiddleware, T>;
|
|
136
136
|
}
|
|
137
|
-
declare
|
|
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;
|
|
138
145
|
type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>>;
|
|
139
146
|
|
|
140
147
|
declare abstract class Storage {
|
|
@@ -162,14 +169,14 @@ declare class SQLStorage extends Storage {
|
|
|
162
169
|
private applyWhere;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
};
|
|
168
|
-
declare const webSocketAdapter: (server: Server<AnyRouter>) => (ws: WebSocket, request: any) => void;
|
|
172
|
+
declare const expressAdapter: (app: Application, server: Server<AnyRouter>, options?: {
|
|
173
|
+
basePath?: string;
|
|
174
|
+
}) => void;
|
|
169
175
|
|
|
170
|
-
type
|
|
176
|
+
type ParsedRequest<TInput = any> = {
|
|
171
177
|
headers: Record<string, string>;
|
|
172
178
|
cookies: Record<string, string>;
|
|
179
|
+
query: Record<string, string>;
|
|
173
180
|
resourceName: string;
|
|
174
181
|
procedure?: string;
|
|
175
182
|
context: Record<string, any>;
|
|
@@ -178,11 +185,14 @@ type Request<TInput = any> = {
|
|
|
178
185
|
resourceId?: string;
|
|
179
186
|
input?: TInput;
|
|
180
187
|
};
|
|
181
|
-
type
|
|
188
|
+
type ContextProvider = (req: Pick<ParsedRequest, "headers" | "cookies" | "query"> & {
|
|
189
|
+
transport: "HTTP" | "WEBSOCKET";
|
|
190
|
+
}) => Record<string, any>;
|
|
191
|
+
type RequestType = ParsedRequest["type"];
|
|
182
192
|
type MutationHandler = (mutation: RawMutationRequest) => void;
|
|
183
|
-
type NextFunction<T> = (req:
|
|
184
|
-
type Middleware<T> = (opts: {
|
|
185
|
-
req:
|
|
193
|
+
type NextFunction<T> = (req: ParsedRequest) => Promise<T> | T;
|
|
194
|
+
type Middleware<T = any> = (opts: {
|
|
195
|
+
req: ParsedRequest;
|
|
186
196
|
next: NextFunction<T>;
|
|
187
197
|
}) => ReturnType<NextFunction<T>>;
|
|
188
198
|
declare class Server<TRouter extends AnyRouter> {
|
|
@@ -190,19 +200,23 @@ declare class Server<TRouter extends AnyRouter> {
|
|
|
190
200
|
readonly storage: Storage;
|
|
191
201
|
readonly schema: Schema<any>;
|
|
192
202
|
readonly middlewares: Set<Middleware<any>>;
|
|
203
|
+
contextProvider?: ContextProvider;
|
|
193
204
|
private mutationSubscriptions;
|
|
194
205
|
private constructor();
|
|
195
206
|
static create<TRouter extends AnyRouter>(opts: {
|
|
196
207
|
router: TRouter;
|
|
197
208
|
storage: Storage;
|
|
198
209
|
schema: Schema<any>;
|
|
210
|
+
middlewares?: Middleware<any>[];
|
|
211
|
+
contextProvider?: ContextProvider;
|
|
199
212
|
}): Server<TRouter>;
|
|
200
213
|
subscribeToMutations(handler: MutationHandler): () => void;
|
|
201
214
|
handleRequest(opts: {
|
|
202
|
-
req:
|
|
215
|
+
req: ParsedRequest;
|
|
203
216
|
}): Promise<any>;
|
|
204
217
|
use(middleware: Middleware<any>): this;
|
|
218
|
+
context(contextProvider: ContextProvider): this;
|
|
205
219
|
}
|
|
206
220
|
declare const server: typeof Server.create;
|
|
207
221
|
|
|
208
|
-
export { type AnyRoute, type AnyRouter, InMemoryStorage, type Middleware, type Mutation, type MutationHandler, type MutationResult, type NextFunction, type
|
|
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 };
|
package/dist/server.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import {a,b}from'./chunk-EK7ODJWE.js';import {z}from'zod';import {Kysely,PostgresDialect}from'kysely';import S from'node:crypto';var P=a(M=>{Object.defineProperty(M,"__esModule",{value:true});M.parse=ne;M.serialize=ie;var Y=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,J=/^[\u0021-\u003A\u003C-\u007E]*$/,X=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,ee=/^[\u0020-\u003A\u003D-\u007E]*$/,te=Object.prototype.toString,re=(()=>{let r=function(){};return r.prototype=Object.create(null),r})();function ne(r,e){let t=new re,n=r.length;if(n<2)return t;let i=(e==null?void 0:e.decode)||ae,a=0;do{let c=r.indexOf("=",a);if(c===-1)break;let u=r.indexOf(";",a),o=u===-1?n:u;if(c>o){a=r.lastIndexOf(";",c-1)+1;continue}let s=C(r,a,c),p=z(r,c,s),m=r.slice(s,p);if(t[m]===void 0){let b=C(r,c+1,o),y=z(r,o,b),f=i(r.slice(b,y));t[m]=f;}a=o+1;}while(a<n);return t}function C(r,e,t){do{let n=r.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function z(r,e,t){for(;e>t;){let n=r.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function ie(r,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!Y.test(r))throw new TypeError(`argument name is invalid: ${r}`);let i=n(e);if(!J.test(i))throw new TypeError(`argument val is invalid: ${e}`);let a=r+"="+i;if(!t)return a;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);a+="; Max-Age="+t.maxAge;}if(t.domain){if(!X.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);a+="; Domain="+t.domain;}if(t.path){if(!ee.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);a+="; Path="+t.path;}if(t.expires){if(!oe(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);a+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(a+="; HttpOnly"),t.secure&&(a+="; Secure"),t.partitioned&&(a+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":a+="; Priority=Low";break;case "medium":a+="; Priority=Medium";break;case "high":a+="; 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":a+="; SameSite=Strict";break;case "lax":a+="; SameSite=Lax";break;case "none":a+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return a}function ae(r){if(r.indexOf("%")===-1)return r;try{return decodeURIComponent(r)}catch{return r}}function oe(r){return te.call(r)==="[object Date]"}});var w=class r{routes;constructor(e){this.routes=e.routes;}static create(e){return new r(e)}},Se=r=>w.create({...r}),W=r=>({handler:e=>({inputValidator:r??z.undefined(),handler:e})}),v=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 i=await t.findById(e.resourceName,e.resourceId),[a,c]=n[this.resourceName].mergeMutation("set",e.input,i);if(!c)throw new Error("Mutation rejected");return {data:await t.upsert(e.resourceName,e.resourceId,a),acceptedValues:c}};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 i=this.customMutations[n.procedure].inputValidator.parse(n.input);return n.input=i,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,i)=>a=>i({req:a,next:n}),async n=>t(n))(e.req)}use(e){return this.middlewares.add(e),this}withMutations(e){return new r(this.resourceName,e({mutation:W}))}},we=()=>r=>new v(r.name);var R=class{},O=class extends R{storage={};async updateSchema(e){this.storage=Object.entries(e).reduce((t,[n,i])=>(t[i.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}},j=class extends R{db;schema;constructor(e){super(),this.db=new Kysely({dialect:new PostgresDialect({pool:e})});}async updateSchema(e){this.schema=e;let t=await this.db.introspection.getTables();for(let[n,i]of Object.entries(e)){let a=t.find(o=>o.name===n);a||await this.db.schema.createTable(n).ifNotExists().execute();let c=`${n}_meta`,u=t.find(o=>o.name===c);u||await this.db.schema.createTable(c).ifNotExists().execute();for(let[o,s]of Object.entries(i.fields)){let p=a==null?void 0:a.columns.find(y=>y.name===o),m=s.getStorageFieldType();p?p.dataType!==m.type&&console.error("Column type mismatch:",o,"expected to have type:",m.type,"but has type:",p.dataType):(await this.db.schema.alterTable(n).addColumn(o,m.type,y=>{let f=y;return m.unique&&(f=f.unique()),m.nullable||(f=f.notNull()),m.references&&(f=f.references(m.references)),m.primary&&(f=f.primaryKey()),f}).execute().catch(y=>{throw console.error("Error adding column",o,y),y}),m.index&&await this.db.schema.createIndex(`${n}_${o}_index`).on(n).column(o).execute().catch(y=>{})),(u==null?void 0:u.columns.find(y=>y.name===o))||await this.db.schema.alterTable(c).addColumn(o,"varchar",y=>{let f=y;return m.primary&&(f=f.primaryKey().references(`${n}.${o}`)),f}).execute();}}}async findById(e,t){let n=await this.db.selectFrom(e).where("id","=",t).selectAll(e).executeTakeFirst(),i=await this.db.selectFrom(`${e}_meta`).where("id","=",t).selectAll(`${e}_meta`).executeTakeFirst();if(!(!n||!i))return this.convertToMaterializedLiveType(n,i)}async find(e,t){let i=await this.applyWhere(e,this.db.selectFrom(e).selectAll(e),t).execute(),a=Object.fromEntries(i.map(o=>{let{id:s,...p}=o;return [s,p]}));if(Object.keys(a).length===0)return {};let c=Object.fromEntries((await this.db.selectFrom(`${e}_meta`).selectAll().where("id","in",Object.keys(a)).execute()).map(o=>{let{id:s,...p}=o;return [s,p]}));return Object.entries(a).reduce((o,[s,p])=>(c[s]&&(o[s]=this.convertToMaterializedLiveType(p,c[s])),o),{})}async upsert(e,t,n){return await this.db.transaction().execute(async i=>{let a=!!await i.selectFrom(e).select("id").where("id","=",t).executeTakeFirst(),c={},u={};for(let[o,s]of Object.entries(n.value))c[o]=s.value,u[o]=s._meta.timestamp;a?await Promise.all([i.updateTable(e).set(c).where("id","=",t).execute(),i.updateTable(`${e}_meta`).set(u).where("id","=",t).execute()]):await Promise.all([i.insertInto(e).values({...c,id:t}).execute(),i.insertInto(`${e}_meta`).values({...u,id:t}).execute()]);}),n}convertToMaterializedLiveType(e,t){return {value:Object.fromEntries(Object.entries(e).flatMap(([n,i])=>t?[[n,{value:i,_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 i=this.schema[e];if(!i)throw new Error("Resource not found");for(let[a,c]of Object.entries(n))if(i.fields[a])t=t.where(`${e}.${a}`,"=",c);else if(i.relations[a]){let u=i.relations[a],o=u.entity.name,s=u.type==="one"?"id":u.foreignColumn,p=u.type==="one"?u.relationalColumn:"id";t=t.leftJoin(o,`${o}.${s}`,`${e}.${p}`),t=this.applyWhere(o,t,c);}return t}};var Z=b(P(),1);z.object({type:z.literal("QUERY"),resource:z.string(),where:z.record(z.any()).optional(),include:z.record(z.any()).optional()});var 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((r,e)=>{r.id&&e.addIssue({code:z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),U=z.object({id:z.string().optional(),type:z.literal("MUTATE"),resource:z.string()}),E=U.extend({procedure:z.string(),payload:z.any()}),A=U.extend({resourceId:z.string(),payload:I});z.union([E,A]);var h=z.string(),se=z.object({id:h,type:z.literal("SUBSCRIBE"),resource:z.string()}),ce=z.object({id:h,type:z.literal("SYNC"),lastSyncedAt:z.string().optional(),resources:z.string().array().optional(),where:z.record(z.any()).optional()}),D=A.extend({id:h}),ue=E.extend({id:h}),de=z.union([ue,D]),V=z.union([se,ce,de]),le=z.object({id:h,type:z.literal("SYNC"),resource:z.string(),data:z.record(I)}),pe=z.object({id:h,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),me=z.object({id:h,type:z.literal("REPLY"),data:z.any()});z.union([le,pe,me,D]);var k="0123456789ABCDEFGHJKMNPQRSTVWXYZ",x=32;var ye=16,_=10,$=0xffffffffffff;var g;(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";})(g||(g={}));var T=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function fe(r){let e=Math.floor(r()*x);return e===x&&(e=x-1),k.charAt(e)}function he(r){var n;let e=ge(),t=e&&(e.crypto||e.msCrypto)||(typeof S<"u"?S:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let i=new Uint8Array(1);return t.getRandomValues(i),i[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=S)!=null&&n.randomBytes)return ()=>S.randomBytes(1).readUInt8()/255;throw new T(g.PRNGDetectFailure,"Failed to find a reliable PRNG")}function ge(){return xe()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Te(r,e){let t="";for(;r>0;r--)t=fe(e)+t;return t}function be(r,e=_){if(isNaN(r))throw new T(g.EncodeTimeValueMalformed,`Time must be a number: ${r}`);if(r>$)throw new T(g.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${$}: ${r}`);if(r<0)throw new T(g.EncodeTimeNegative,`Time must be positive: ${r}`);if(Number.isInteger(r)===false)throw new T(g.EncodeTimeValueMalformed,`Time must be an integer: ${r}`);let t,n="";for(let i=e;i>0;i--)t=r%x,n=k.charAt(t)+n,r=(r-t)/x;return n}function xe(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function F(r,e){let t=he(),n=Date.now();return be(n,_)+Te(ye,t)}var L=()=>F().toLowerCase();var Ge=r=>{let e={},t={};return r.subscribeToMutations(n=>{let i=n;!i.resourceId||!i.payload||(console.log("Mutation propagated:",i),Object.entries(t[i.resource]??{}).forEach(([a,c])=>{var u;(u=e[a])==null||u.send(JSON.stringify({...i,id:i.id??L()}));}));}),(n,i)=>{let a=o=>{n.send(JSON.stringify(o));},c=L(),u={headers:i.headers,cookies:typeof i.headers.cookie=="string"?Z.default.parse(i.headers.cookie):{}};e[c]=n,console.log("Client connected:",c),n.on("message",async o=>{try{console.log("Message received from the client:",o);let s=V.parse(JSON.parse(o.toString()));if(s.type==="SUBSCRIBE"){let{resource:p}=s;t[p]||(t[p]={}),t[p][c]={};}else if(s.type==="SYNC"){let{resources:p}=s,m=p??Object.keys(r.schema);console.log("Syncing resources:",m),await Promise.all(m.map(async b=>{let y=await r.handleRequest({req:{...u,type:"QUERY",resourceName:b,context:{}}});if(!y||!y.data)throw new Error("Invalid resource");a({id:s.id,type:"SYNC",resource:b,data:Object.fromEntries(Object.entries(y.data??{}).map(([f,q])=>[f,q.value]))});}));}else if(s.type==="MUTATE"){let{resource:p}=s;console.log("Received mutation from client:",s);try{let m=await r.handleRequest({req:{...u,type:"MUTATE",resourceName:p,input:s.payload,context:{messageId:s.id},resourceId:s.resourceId,procedure:s.procedure}});s.procedure&&a({id:s.id,type:"REPLY",data:m});}catch(m){a({id:s.id,type:"REJECT",resource:p,message:m.message}),console.error("Error parsing mutation from the client:",m);}}}catch(s){console.error("Error handling message from the client:",s);}}),n.on("close",()=>{console.log("Connection closed",c),delete e[c];});}};var N=class r{router;storage;schema;middlewares=new Set;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 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,i)=>a=>i({req:a,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}},Qe=N.create;export{O as InMemoryStorage,v as Route,w as Router,j as SQLStorage,N as Server,R as Storage,we as routeFactory,Se as router,Qe as server,Ge as webSocketAdapter};
|
|
1
|
+
import {a,b}from'./chunk-EK7ODJWE.js';import he,{parse}from'qs';import {z as z$1}from'zod';import I from'node:crypto';import {Kysely,PostgresDialect}from'kysely';var P=a(E=>{Object.defineProperty(E,"__esModule",{value:true});E.parse=le;E.serialize=pe;var oe=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,ie=/^[\u0021-\u003A\u003C-\u007E]*$/,se=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,ce=/^[\u0020-\u003A\u003D-\u007E]*$/,ue=Object.prototype.toString,de=(()=>{let r=function(){};return r.prototype=Object.create(null),r})();function le(r,e){let t=new de,n=r.length;if(n<2)return t;let a=(e==null?void 0:e.decode)||me,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=V(r,o,i),m=_(r,i,h),l=r.slice(h,m);if(t[l]===void 0){let p=V(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 V(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 pe(r,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!oe.test(r))throw new TypeError(`argument name is invalid: ${r}`);let a=n(e);if(!ie.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(!se.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);o+="; Domain="+t.domain;}if(t.path){if(!ce.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);o+="; Path="+t.path;}if(t.expires){if(!ye(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 me(r){if(r.indexOf("%")===-1)return r;try{return decodeURIComponent(r)}catch{return r}}function ye(r){return ue.call(r)==="[object Date]"}});var Z=b(P(),1);var $=z$1.object({type:z$1.literal("QUERY"),resource:z$1.string(),where:z$1.record(z$1.any()).optional(),include:z$1.record(z$1.any()).optional()}),L=z$1.record(z$1.object({value:z$1.string().or(z$1.number()).or(z$1.boolean()).or(z$1.date()),_meta:z$1.object({timestamp:z$1.string().optional()}).optional()})).superRefine((r,e)=>{r.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),q=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string()}),S=q.extend({procedure:z$1.string(),payload:z$1.any().optional()}),M=q.extend({resourceId:z$1.string(),payload:L});z$1.union([S,M]);var F=$.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});z$1.union([j,N]);var H=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?Z.default.parse(n.cookie):{}},o=new URL(e.url),i=o.pathname.split("/"),u=o.searchParams,s=he.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}=F.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 J=b(P(),1);var T=z$1.string(),ge=z$1.object({id:T,type:z$1.literal("SUBSCRIBE"),resource:z$1.string()}),Te=z$1.object({id:T,type:z$1.literal("SYNC"),lastSyncedAt:z$1.string().optional(),resources:z$1.string().array().optional(),where:z$1.record(z$1.any()).optional()}),G=M.extend({id:T}),Re=S.extend({id:T}),xe=z$1.union([Re,G]),B=z$1.union([ge,Te,xe]),be=z$1.object({id:T,type:z$1.literal("SYNC"),resource:z$1.string(),data:z$1.record(L)}),we=z$1.object({id:T,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),Se=z$1.object({id:T,type:z$1.literal("REPLY"),data:z$1.any()});z$1.union([be,we,Se,G]);var W="0123456789ABCDEFGHJKMNPQRSTVWXYZ",v=32;var Me=16,K=10,Q=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 ve(r){let e=Math.floor(r()*v);return e===v&&(e=v-1),W.charAt(e)}function Ee(r){var n;let e=Ie(),t=e&&(e.crypto||e.msCrypto)||(typeof I<"u"?I: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)!=null&&n.randomBytes)return ()=>I.randomBytes(1).readUInt8()/255;throw new x(R.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Ie(){return Le()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Ae(r,e){let t="";for(;r>0;r--)t=ve(e)+t;return t}function Pe(r,e=K){if(isNaN(r))throw new x(R.EncodeTimeValueMalformed,`Time must be a number: ${r}`);if(r>Q)throw new x(R.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${Q}: ${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=W.charAt(t)+n,r=(r-t)/v;return n}function Le(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function Y(r,e){let t=Ee(),n=Date.now();return Pe(n,K)+Ae(Me,t)}var O=()=>Y().toLowerCase();var X=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"?J.default.parse(a.headers.cookie):{}},s=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=B.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,ne])=>[w,ne.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 ee(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 pt=(r,e,t)=>{r.ws(`${(t==null?void 0:t.basePath)??""}/ws`,X(e)),r.use(`${(t==null?void 0:t.basePath)??""}/`,(n,a)=>{H(e)(ee(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)}},ht=r=>C.create({...r}),Oe=r=>({handler:e=>({inputValidator:r??z$1.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:Oe}))}},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}},gt=k.create;var A=class{},te=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}},re=class extends A{db;schema;constructor(e){super(),this.db=new Kysely({dialect:new 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}},St=D.create;
|
|
2
|
+
export{te as InMemoryStorage,z as Route,k as RouteFactory,C as Router,re as SQLStorage,D as Server,A as Storage,pt as expressAdapter,gt as routeFactory,ht as router,St as server};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-state/sync",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,9 +21,13 @@
|
|
|
21
21
|
],
|
|
22
22
|
"type": "module",
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@types/express": "^4.17.21",
|
|
25
|
+
"@types/express-ws": "^3.0.5",
|
|
24
26
|
"@types/node": "^20.11.24",
|
|
27
|
+
"@types/qs": "^6.14.0",
|
|
25
28
|
"@types/ws": "^8.5.13",
|
|
26
29
|
"cookie": "^1.0.2",
|
|
30
|
+
"express": "^4.21.2",
|
|
27
31
|
"react": "18.0.0",
|
|
28
32
|
"tsup": "^8.0.2",
|
|
29
33
|
"typescript": "5.5.4",
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
},
|
|
33
37
|
"dependencies": {
|
|
34
38
|
"kysely": "^0.28.2",
|
|
39
|
+
"qs": "^6.14.0",
|
|
35
40
|
"ws": "^8.18.0",
|
|
36
41
|
"zod": "^3.24.1"
|
|
37
42
|
},
|
|
@@ -50,6 +55,11 @@
|
|
|
50
55
|
"types": "./src/client/index.ts",
|
|
51
56
|
"import": "./dist/client.js",
|
|
52
57
|
"require": "./dist/client.js"
|
|
58
|
+
},
|
|
59
|
+
"./client/fetch": {
|
|
60
|
+
"types": "./src/client/fetch-client.ts",
|
|
61
|
+
"import": "./dist/fetch-client.js",
|
|
62
|
+
"require": "./dist/fetch-client.js"
|
|
53
63
|
}
|
|
54
64
|
},
|
|
55
65
|
"peerDependencies": {
|