@live-state/sync 0.0.6 → 0.0.7-canary-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { L as LiveObjectAny, W as WhereClause, S as Simplify, I as InferLiveObjectWithRelationalIds, M as MaterializedLiveType, a as Schema, b as IncludeClause, c as InferLiveObject, d as InferInsert, e as InferUpdate, f as Logger, g as LogLevel } from './index-BtsKDfTE.js';
2
+ import { L as LiveObjectAny, I as IncludeClause, a as InferLiveObject, W as WhereClause, S as Simplify, b as InferInsert, c as InferUpdate, M as MaterializedLiveType, d as Schema, e as LiveCollectionAny, f as InferLiveCollection, g as InferLiveObjectWithRelationalIds, h as Logger, i as LogLevel } from './index-hO1iQ-VU.js';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
4
  import { PostgresPool, Kysely } from 'kysely';
5
5
  import { Application } from 'express-ws';
@@ -34,13 +34,185 @@ declare const defaultMutationSchema: z.ZodObject<{
34
34
  timestamp: z.ZodNullable<z.ZodOptional<z.ZodString>>;
35
35
  }, z.core.$strip>>;
36
36
  }, z.core.$strip>>;
37
+ meta: z.ZodOptional<z.ZodObject<{
38
+ timestamp: z.ZodOptional<z.ZodString>;
39
+ }, z.core.$strip>>;
37
40
  }, z.core.$strip>;
38
41
  type DefaultMutation = Omit<z.infer<typeof defaultMutationSchema>, "resourceId"> & {
39
42
  resourceId: string;
40
43
  };
41
44
 
45
+ type ConditionalPromise<T, P extends boolean> = P extends true ? Promise<T> : T;
42
46
  type PromiseOrSync<T> = T | Promise<T>;
43
47
 
48
+ /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
49
+
50
+ declare abstract class Storage implements DataSource {
51
+ /**
52
+ * @deprecated Use db.[collection].one(id).get() instead
53
+ */
54
+ abstract findOne<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, id: string, options?: {
55
+ include?: TInclude;
56
+ }): Promise<InferLiveObject<T, TInclude> | undefined>;
57
+ /**
58
+ * @deprecated Use db.[collection].where({...}).get() instead
59
+ */
60
+ abstract find<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, options?: {
61
+ where?: WhereClause<T>;
62
+ include?: TInclude;
63
+ limit?: number;
64
+ sort?: {
65
+ key: string;
66
+ direction: "asc" | "desc";
67
+ }[];
68
+ }): Promise<InferLiveObject<T, TInclude>[]>;
69
+ /**
70
+ * @deprecated Use db.[collection].insert({...}) instead
71
+ */
72
+ insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
73
+ /**
74
+ * @deprecated Use db.[collection].update(id, {...}) instead
75
+ */
76
+ update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
77
+ abstract transaction<T>(fn: (opts: {
78
+ trx: Storage;
79
+ commit: () => Promise<void>;
80
+ rollback: () => Promise<void>;
81
+ }) => Promise<T>): Promise<T>;
82
+ }
83
+
84
+ /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
85
+
86
+ declare class Batcher {
87
+ private storage;
88
+ private queue;
89
+ private scheduled;
90
+ constructor(storage: Storage);
91
+ rawFind<T extends LiveObjectAny>({ resource, commonWhere, uniqueWhere, ...rest }: {
92
+ resource: string;
93
+ commonWhere?: Record<string, any>;
94
+ uniqueWhere?: Record<string, any>;
95
+ include?: Record<string, any>;
96
+ limit?: number;
97
+ sort?: {
98
+ key: string;
99
+ direction: "asc" | "desc";
100
+ }[];
101
+ }): Promise<MaterializedLiveType<T>[]>;
102
+ private getBatchKey;
103
+ private processBatch;
104
+ private executeBatchedRequests;
105
+ }
106
+
107
+ interface DataSource {
108
+ get(query: RawQueryRequest, extra?: {
109
+ context?: any;
110
+ batcher?: Batcher;
111
+ }): PromiseOrSync<any[]>;
112
+ }
113
+
114
+ /** biome-ignore-all lint/complexity/noBannedTypes: <explanation> */
115
+
116
+ type InferQueryResult<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean = false> = TSingle extends true ? Simplify<InferLiveObject<TCollection, TInclude>> | undefined : Simplify<InferLiveObject<TCollection, TInclude>>[];
117
+ declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection> = {}, TSingle extends boolean = false, TShouldAwait extends boolean = false> {
118
+ private _collection;
119
+ private _client;
120
+ private _where;
121
+ private _include;
122
+ private _limit?;
123
+ private _single?;
124
+ private _sort?;
125
+ private _shouldAwait?;
126
+ private constructor();
127
+ where(where: WhereClause<TCollection>): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
128
+ include<TNewInclude extends IncludeClause<TCollection>>(include: TNewInclude): QueryBuilder<TCollection, TInclude & TNewInclude, TSingle, TShouldAwait>;
129
+ limit(limit: number): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
130
+ one(id: string): QueryBuilder<TCollection, TInclude, true, TShouldAwait>;
131
+ first(where?: WhereClause<TCollection>): QueryBuilder<TCollection, TInclude, true, TShouldAwait>;
132
+ orderBy(key: keyof TCollection["fields"], direction?: "asc" | "desc"): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
133
+ toJSON(): {
134
+ resource: string;
135
+ where: WhereClause<TCollection>;
136
+ include: TInclude;
137
+ limit: number | undefined;
138
+ sort: {
139
+ key: string;
140
+ direction: "asc" | "desc";
141
+ }[] | undefined;
142
+ };
143
+ buildQueryRequest(): RawQueryRequest;
144
+ get(): ConditionalPromise<InferQueryResult<TCollection, TInclude, TSingle>, TShouldAwait>;
145
+ subscribe(callback: (value: InferQueryResult<TCollection, TInclude, TSingle>) => void): () => void;
146
+ }
147
+
148
+ /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
149
+
150
+ /**
151
+ * A QueryBuilder with added insert() and update() mutation methods for server-side use.
152
+ */
153
+ type ServerCollection<T extends LiveCollectionAny> = QueryBuilder<T, {}, false, true> & {
154
+ /**
155
+ * Insert a new record into this collection.
156
+ */
157
+ insert(value: Simplify<InferInsert<T>>): Promise<InferLiveCollection<T>>;
158
+ /**
159
+ * Update an existing record in this collection.
160
+ */
161
+ update(id: string, value: InferUpdate<T>): Promise<Partial<InferLiveCollection<T>>>;
162
+ };
163
+ /**
164
+ * Server database interface that provides collection properties and deprecated methods.
165
+ * Each collection property (e.g., db.users, db.posts) is a ServerCollection with
166
+ * QueryBuilder methods plus insert/update mutations.
167
+ */
168
+ type ServerDB<TSchema extends Schema<any>> = {
169
+ [K in keyof TSchema]: ServerCollection<TSchema[K]>;
170
+ } & {
171
+ /**
172
+ * @deprecated Use db.[collection].one(id).get() instead
173
+ */
174
+ findOne: Storage['findOne'];
175
+ /**
176
+ * @deprecated Use db.[collection].where({...}).get() instead
177
+ */
178
+ find: Storage['find'];
179
+ /**
180
+ * @deprecated Use db.[collection].insert({...}) instead
181
+ */
182
+ insert: Storage['insert'];
183
+ /**
184
+ * @deprecated Use db.[collection].update(id, {...}) instead
185
+ */
186
+ update: Storage['update'];
187
+ /**
188
+ * Execute operations within a transaction.
189
+ * The transaction wrapper provides a ServerDB interface for the transaction.
190
+ */
191
+ transaction: <T>(fn: (opts: {
192
+ trx: ServerDB<TSchema>;
193
+ commit: () => Promise<void>;
194
+ rollback: () => Promise<void>;
195
+ }) => Promise<T>) => Promise<T>;
196
+ };
197
+ /**
198
+ * Creates a ServerDB proxy that wraps a Storage instance with QueryBuilder-based syntax.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const db = createServerDB(storage, schema);
203
+ *
204
+ * // New syntax
205
+ * const user = await db.users.one(userId).get();
206
+ * const posts = await db.posts.where({ authorId: userId }).limit(10).get();
207
+ * await db.users.insert({ id: '...', name: '...' });
208
+ *
209
+ * // Deprecated syntax (still works)
210
+ * const user = await db.findOne(schema.users, userId);
211
+ * const posts = await db.find(schema.posts, { where: { authorId: userId }, limit: 10 });
212
+ * ```
213
+ */
214
+ declare function createServerDB<TSchema extends Schema<any>>(storage: Storage, schema: TSchema): ServerDB<TSchema>;
215
+
44
216
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
45
217
  /** biome-ignore-all lint/style/noNonNullAssertion: false positive */
46
218
 
@@ -54,7 +226,7 @@ declare class Router<TRoutes extends RouteRecord> {
54
226
  }): Router<TRoutes>;
55
227
  getHooks(resourceName: string): Hooks<any> | undefined;
56
228
  }
57
- declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<any, any, any>>>(opts: {
229
+ declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<any, any, any, any>>>(opts: {
58
230
  schema: TSchema;
59
231
  routes: TRoutes;
60
232
  }) => Router<TRoutes>;
@@ -68,23 +240,54 @@ type MutationResult<TShape extends LiveObjectAny> = {
68
240
  acceptedValues: Record<string, any> | null;
69
241
  };
70
242
  type Mutation<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput> = {
243
+ _type: "mutation";
71
244
  inputValidator: TInputValidator;
72
245
  handler: (opts: {
73
246
  req: MutationRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined>;
74
- db: Storage;
247
+ db: ServerDB<any>;
75
248
  }) => TOutput;
76
249
  };
250
+ interface QueryProcedureRequest<TInput = any> extends BaseRequest {
251
+ type: "CUSTOM_QUERY";
252
+ input: TInput;
253
+ resource: string;
254
+ procedure: string;
255
+ }
256
+ type Query<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput> = {
257
+ _type: "query";
258
+ inputValidator: TInputValidator;
259
+ handler: (opts: {
260
+ req: QueryProcedureRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined>;
261
+ db: ServerDB<any>;
262
+ }) => TOutput;
263
+ };
264
+ type Procedure<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput> = Mutation<TInputValidator, TOutput> | Query<TInputValidator, TOutput>;
265
+ type QueryCreator = {
266
+ (): {
267
+ handler: <TOutput>(handler: (opts: {
268
+ req: QueryProcedureRequest<undefined>;
269
+ db: ServerDB<any>;
270
+ }) => TOutput) => Query<StandardSchemaV1<any, undefined>, TOutput>;
271
+ };
272
+ <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
273
+ handler: <THandler extends (opts: {
274
+ req: QueryProcedureRequest<StandardSchemaV1.InferOutput<TInputValidator>>;
275
+ db: ServerDB<any>;
276
+ }) => any>(handler: THandler) => Query<TInputValidator, ReturnType<THandler>>;
277
+ };
278
+ };
279
+ declare const queryCreator: QueryCreator;
77
280
  type MutationCreator = {
78
281
  (): {
79
282
  handler: <TOutput>(handler: (opts: {
80
283
  req: MutationRequest<undefined>;
81
- db: Storage;
284
+ db: ServerDB<any>;
82
285
  }) => TOutput) => Mutation<StandardSchemaV1<any, undefined>, TOutput>;
83
286
  };
84
287
  <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
85
288
  handler: <THandler extends (opts: {
86
289
  req: MutationRequest<StandardSchemaV1.InferOutput<TInputValidator>>;
87
- db: Storage;
290
+ db: ServerDB<any>;
88
291
  }) => any>(handler: THandler) => Mutation<TInputValidator, ReturnType<THandler>>;
89
292
  };
90
293
  };
@@ -110,7 +313,7 @@ type BeforeInsertHook<TShape extends LiveObjectAny> = (opts: {
110
313
  id: string;
111
314
  };
112
315
  rawValue: MaterializedLiveType<TShape>;
113
- db: Storage;
316
+ db: ServerDB<any>;
114
317
  }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
115
318
  type AfterInsertHook<TShape extends LiveObjectAny> = (opts: {
116
319
  ctx?: Record<string, any>;
@@ -118,7 +321,7 @@ type AfterInsertHook<TShape extends LiveObjectAny> = (opts: {
118
321
  id: string;
119
322
  };
120
323
  rawValue: MaterializedLiveType<TShape>;
121
- db: Storage;
324
+ db: ServerDB<any>;
122
325
  }) => Promise<void> | void;
123
326
  type BeforeUpdateHook<TShape extends LiveObjectAny> = (opts: {
124
327
  ctx?: Record<string, any>;
@@ -130,7 +333,7 @@ type BeforeUpdateHook<TShape extends LiveObjectAny> = (opts: {
130
333
  id: string;
131
334
  };
132
335
  previousRawValue?: MaterializedLiveType<TShape>;
133
- db: Storage;
336
+ db: ServerDB<any>;
134
337
  }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
135
338
  type AfterUpdateHook<TShape extends LiveObjectAny> = (opts: {
136
339
  ctx?: Record<string, any>;
@@ -142,7 +345,7 @@ type AfterUpdateHook<TShape extends LiveObjectAny> = (opts: {
142
345
  id: string;
143
346
  };
144
347
  previousRawValue?: MaterializedLiveType<TShape>;
145
- db: Storage;
348
+ db: ServerDB<any>;
146
349
  }) => Promise<void> | void;
147
350
  type Hooks<TShape extends LiveObjectAny> = {
148
351
  beforeInsert?: BeforeInsertHook<TShape>;
@@ -150,18 +353,26 @@ type Hooks<TShape extends LiveObjectAny> = {
150
353
  beforeUpdate?: BeforeUpdateHook<TShape>;
151
354
  afterUpdate?: AfterUpdateHook<TShape>;
152
355
  };
153
- declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>> {
356
+ declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>, TCustomQueries extends Record<string, Query<any, any>>> {
154
357
  readonly resourceSchema: TResourceSchema;
155
358
  readonly middlewares: Set<TMiddleware>;
156
359
  readonly customMutations: TCustomMutations;
360
+ readonly customQueries: TCustomQueries;
157
361
  readonly authorization?: Authorization<TResourceSchema>;
158
362
  readonly hooks?: Hooks<TResourceSchema>;
159
- constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
363
+ constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, customQueries?: TCustomQueries, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
160
364
  use(...middlewares: TMiddleware[]): this;
365
+ withProcedures<T extends Record<string, Procedure<any, any>>>(procedureFactory: (opts: {
366
+ mutation: typeof mutationCreator;
367
+ query: typeof queryCreator;
368
+ }) => T): Route<TResourceSchema, TMiddleware, { [K in keyof T as T[K] extends Mutation<any, any> ? K : never]: T[K]; } & Record<string, Mutation<any, any>>, { [K_1 in keyof T as T[K_1] extends Query<any, any> ? K_1 : never]: T[K_1]; } & Record<string, Query<any, any>>>;
369
+ /**
370
+ * @deprecated Use `withProcedures` instead
371
+ */
161
372
  withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
162
373
  mutation: typeof mutationCreator;
163
- }) => T): Route<TResourceSchema, TMiddleware, T>;
164
- withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations>;
374
+ }) => T): Route<TResourceSchema, TMiddleware, { [K in keyof T as T[K] extends Mutation<any, any> ? K : never]: T[K]; } & Record<string, Mutation<any, any>>, { [K_1 in keyof T as T[K_1] extends Query<any, any> ? K_1 : never]: T[K_1]; } & Record<string, Query<any, any>>>;
375
+ withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations, TCustomQueries>;
165
376
  getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
166
377
  private handleSet;
167
378
  private wrapInMiddlewares;
@@ -169,66 +380,12 @@ declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends M
169
380
  declare class RouteFactory {
170
381
  private middlewares;
171
382
  private constructor();
172
- collectionRoute<T extends LiveObjectAny>(shape: T, authorization?: Authorization<T>): Route<T, Middleware<any>, Record<string, never>>;
383
+ collectionRoute<T extends LiveObjectAny>(shape: T, authorization?: Authorization<T>): Route<T, Middleware<any>, Record<string, never>, Record<string, never>>;
173
384
  use(...middlewares: Middleware<any>[]): RouteFactory;
174
385
  static create(): RouteFactory;
175
386
  }
176
387
  declare const routeFactory: typeof RouteFactory.create;
177
- type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>>;
178
-
179
- /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
180
-
181
- declare class Batcher {
182
- private storage;
183
- private queue;
184
- private scheduled;
185
- constructor(storage: Storage);
186
- rawFind<T extends LiveObjectAny>({ resource, commonWhere, uniqueWhere, ...rest }: {
187
- resource: string;
188
- commonWhere?: Record<string, any>;
189
- uniqueWhere?: Record<string, any>;
190
- include?: Record<string, any>;
191
- limit?: number;
192
- sort?: {
193
- key: string;
194
- direction: "asc" | "desc";
195
- }[];
196
- }): Promise<MaterializedLiveType<T>[]>;
197
- private getBatchKey;
198
- private processBatch;
199
- private executeBatchedRequests;
200
- }
201
-
202
- interface DataSource {
203
- get(query: RawQueryRequest, extra?: {
204
- context?: any;
205
- batcher?: Batcher;
206
- }): PromiseOrSync<any[]>;
207
- }
208
-
209
- /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
210
-
211
- declare abstract class Storage implements DataSource {
212
- abstract findOne<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, id: string, options?: {
213
- include?: TInclude;
214
- }): Promise<InferLiveObject<T, TInclude> | undefined>;
215
- abstract find<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, options?: {
216
- where?: WhereClause<T>;
217
- include?: TInclude;
218
- limit?: number;
219
- sort?: {
220
- key: string;
221
- direction: "asc" | "desc";
222
- }[];
223
- }): Promise<InferLiveObject<T, TInclude>[]>;
224
- insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
225
- update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
226
- abstract transaction<T>(fn: (opts: {
227
- trx: Storage;
228
- commit: () => Promise<void>;
229
- rollback: () => Promise<void>;
230
- }) => Promise<T>): Promise<T>;
231
- }
388
+ type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>, Record<string, any>>;
232
389
 
233
390
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
234
391
 
@@ -301,7 +458,7 @@ interface MutationRequest<TInput = any> extends BaseRequest {
301
458
  resourceId?: string;
302
459
  procedure: string;
303
460
  }
304
- type Request = QueryRequest | MutationRequest;
461
+ type Request = QueryRequest | MutationRequest | QueryProcedureRequest;
305
462
  type ContextProvider = (req: Omit<BaseRequest, "context"> & {
306
463
  transport: "HTTP" | "WEBSOCKET";
307
464
  }) => Record<string, any>;
@@ -333,10 +490,14 @@ declare class Server<TRouter extends AnyRouter> {
333
490
  handleMutation(opts: {
334
491
  req: MutationRequest;
335
492
  }): Promise<any>;
493
+ handleCustomQuery(opts: {
494
+ req: QueryProcedureRequest;
495
+ subscription?: (mutation: DefaultMutation) => void;
496
+ }): Promise<any>;
336
497
  use(middleware: Middleware<any>): this;
337
498
  context(contextProvider: ContextProvider): this;
338
499
  private wrapInMiddlewares;
339
500
  }
340
501
  declare const server: typeof Server.create;
341
502
 
342
- export { type AfterInsertHook, type AfterUpdateHook, type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };
503
+ export { type AfterInsertHook, type AfterUpdateHook, type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type Procedure, type Query, type QueryProcedureRequest, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, type ServerCollection, type ServerDB, Storage, createServerDB, expressAdapter, routeFactory, router, server };