fauxbase 0.1.2 → 0.5.0

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.cjs CHANGED
@@ -38,6 +38,29 @@ var ForbiddenError = class extends FauxbaseError {
38
38
  this.name = "ForbiddenError";
39
39
  }
40
40
  };
41
+ var NetworkError = class extends FauxbaseError {
42
+ constructor(message = "Network request failed") {
43
+ super(message, "NETWORK");
44
+ this.name = "NetworkError";
45
+ }
46
+ };
47
+ var TimeoutError = class extends FauxbaseError {
48
+ constructor(message = "Request timed out") {
49
+ super(message, "TIMEOUT");
50
+ this.name = "TimeoutError";
51
+ }
52
+ };
53
+ var HttpError = class extends FauxbaseError {
54
+ status;
55
+ constructor(message, status, details) {
56
+ super(message, "HTTP", details);
57
+ this.name = "HttpError";
58
+ this.status = status;
59
+ }
60
+ toJSON() {
61
+ return { ...super.toJSON(), status: this.status };
62
+ }
63
+ };
41
64
 
42
65
  // src/registry.ts
43
66
  var fieldRegistry = /* @__PURE__ */ new Map();
@@ -159,11 +182,18 @@ function afterUpdate() {
159
182
  var Service = class {
160
183
  driver;
161
184
  resourceName;
185
+ client;
186
+ /** @internal */
187
+ _eventBus;
162
188
  /** @internal — called by createClient to wire the service */
163
189
  _init(driver, resourceName) {
164
190
  this.driver = driver;
165
191
  this.resourceName = resourceName;
166
192
  }
193
+ /** @internal — called by createClient to give services access to the client */
194
+ _setClient(client) {
195
+ this.client = client;
196
+ }
167
197
  async list(query = {}) {
168
198
  return this.driver.list(this.resourceName, query);
169
199
  }
@@ -175,27 +205,56 @@ var Service = class {
175
205
  await this.runHooks("beforeCreate", data, allItems);
176
206
  const result = await this.driver.create(this.resourceName, data);
177
207
  await this.runHooks("afterCreate", result.data);
208
+ this.emitEvent("created", { data: result.data, id: result.data.id });
178
209
  return result;
179
210
  }
180
211
  async update(id, data) {
181
212
  await this.runHooks("beforeUpdate", id, data);
182
213
  const result = await this.driver.update(this.resourceName, id, data);
183
214
  await this.runHooks("afterUpdate", result.data);
215
+ this.emitEvent("updated", { data: result.data, id });
184
216
  return result;
185
217
  }
186
218
  async delete(id) {
187
- return this.driver.delete(this.resourceName, id);
219
+ const result = await this.driver.delete(this.resourceName, id);
220
+ this.emitEvent("deleted", { data: result.data, id });
221
+ return result;
188
222
  }
189
223
  async count(filter) {
190
224
  return this.driver.count(this.resourceName, filter);
191
225
  }
192
226
  get bulk() {
227
+ const self = this;
193
228
  return {
194
- create: (items) => this.driver.bulkCreate(this.resourceName, items),
195
- update: (updates) => this.driver.bulkUpdate(this.resourceName, updates),
196
- delete: (ids) => this.driver.bulkDelete(this.resourceName, ids)
229
+ async create(items) {
230
+ const result = await self.driver.bulkCreate(self.resourceName, items);
231
+ self.emitEvent("bulkCreated", { data: result.data });
232
+ return result;
233
+ },
234
+ async update(updates) {
235
+ const result = await self.driver.bulkUpdate(self.resourceName, updates);
236
+ self.emitEvent("bulkUpdated", { data: result.data, ids: updates.map((u) => u.id) });
237
+ return result;
238
+ },
239
+ async delete(ids) {
240
+ const result = await self.driver.bulkDelete(self.resourceName, ids);
241
+ self.emitEvent("bulkDeleted", { ids });
242
+ return result;
243
+ }
197
244
  };
198
245
  }
246
+ emitEvent(action, extra) {
247
+ if (!this._eventBus) return;
248
+ this._eventBus.emit({
249
+ action,
250
+ resource: this.resourceName,
251
+ data: extra.data,
252
+ id: extra.id,
253
+ ids: extra.ids,
254
+ timestamp: Date.now(),
255
+ source: "local"
256
+ });
257
+ }
199
258
  async runHooks(hookType, ...args) {
200
259
  const methods = getHooks(this.constructor, hookType);
201
260
  for (const methodName of methods) {
@@ -204,6 +263,173 @@ var Service = class {
204
263
  }
205
264
  };
206
265
 
266
+ // src/auth.ts
267
+ var AuthService = class extends Service {
268
+ authState = null;
269
+ saveState = null;
270
+ httpDriver = null;
271
+ /** @internal — called by createClient to wire persistence */
272
+ _initAuth(loadState, saveState) {
273
+ this.saveState = saveState;
274
+ this.authState = loadState();
275
+ }
276
+ /** @internal — called by createClient when using HttpDriver */
277
+ _setHttpMode(driver) {
278
+ this.httpDriver = driver;
279
+ }
280
+ async login(credentials) {
281
+ if (this.httpDriver) {
282
+ return this.httpLogin(credentials);
283
+ }
284
+ return this.localLogin(credentials);
285
+ }
286
+ async register(data) {
287
+ if (this.httpDriver) {
288
+ return this.httpRegister(data);
289
+ }
290
+ return this.localRegister(data);
291
+ }
292
+ logout() {
293
+ this.authState = null;
294
+ this.persistState();
295
+ }
296
+ get currentUser() {
297
+ return this.authState ? { id: this.authState.userId, email: this.authState.email } : null;
298
+ }
299
+ get isLoggedIn() {
300
+ return this.authState !== null;
301
+ }
302
+ get token() {
303
+ return this.authState?.token ?? null;
304
+ }
305
+ hasRole(role) {
306
+ return this.authState?.role === role;
307
+ }
308
+ getAuthContext() {
309
+ if (!this.authState) return null;
310
+ return {
311
+ userId: this.authState.userId,
312
+ userName: this.authState.userName
313
+ };
314
+ }
315
+ // --- Local mode (original implementation) ---
316
+ async localLogin(credentials) {
317
+ const { items } = await this.list({ filter: { email: credentials.email } });
318
+ if (items.length === 0) {
319
+ throw new NotFoundError("Invalid email or password");
320
+ }
321
+ const user = items[0];
322
+ if (user.password !== credentials.password) {
323
+ throw new ForbiddenError("Invalid email or password");
324
+ }
325
+ this.authState = {
326
+ userId: user.id,
327
+ email: user.email,
328
+ userName: user.name || user.email,
329
+ role: user.role,
330
+ token: this.generateToken(user)
331
+ };
332
+ this.persistState();
333
+ return user;
334
+ }
335
+ async localRegister(data) {
336
+ const email = data.email;
337
+ if (email) {
338
+ const { items } = await this.list({ filter: { email } });
339
+ if (items.length > 0) {
340
+ throw new ConflictError("Email already registered");
341
+ }
342
+ }
343
+ const { data: user } = await this.create(data);
344
+ const u = user;
345
+ this.authState = {
346
+ userId: u.id,
347
+ email: u.email,
348
+ userName: u.name || u.email,
349
+ role: u.role,
350
+ token: this.generateToken(u)
351
+ };
352
+ this.persistState();
353
+ return user;
354
+ }
355
+ // --- HTTP mode ---
356
+ async httpLogin(credentials) {
357
+ const preset = this.httpDriver.preset;
358
+ const baseUrl = this.httpDriver.baseUrl;
359
+ const url = `${baseUrl}${preset.auth.loginUrl}`;
360
+ const response = await fetch(url, {
361
+ method: "POST",
362
+ headers: { "Content-Type": "application/json" },
363
+ body: JSON.stringify(credentials)
364
+ });
365
+ if (!response.ok) {
366
+ const body2 = await response.json().catch(() => ({}));
367
+ if (response.status === 401 || response.status === 403) {
368
+ throw new ForbiddenError(body2.message ?? "Invalid email or password");
369
+ }
370
+ if (response.status === 404) {
371
+ throw new NotFoundError(body2.message ?? "Invalid email or password");
372
+ }
373
+ throw new ForbiddenError(body2.message ?? "Login failed");
374
+ }
375
+ const body = await response.json();
376
+ const token = body[preset.auth.tokenField];
377
+ const user = body[preset.auth.userField] ?? body;
378
+ this.authState = {
379
+ userId: user.id,
380
+ email: user.email ?? credentials.email,
381
+ userName: user.name || user.email || credentials.email,
382
+ role: user.role,
383
+ token
384
+ };
385
+ this.persistState();
386
+ return user;
387
+ }
388
+ async httpRegister(data) {
389
+ const preset = this.httpDriver.preset;
390
+ const baseUrl = this.httpDriver.baseUrl;
391
+ const url = `${baseUrl}${preset.auth.registerUrl}`;
392
+ const response = await fetch(url, {
393
+ method: "POST",
394
+ headers: { "Content-Type": "application/json" },
395
+ body: JSON.stringify(data)
396
+ });
397
+ if (!response.ok) {
398
+ const body2 = await response.json().catch(() => ({}));
399
+ if (response.status === 409) {
400
+ throw new ConflictError(body2.message ?? "Email already registered");
401
+ }
402
+ throw new ForbiddenError(body2.message ?? "Registration failed");
403
+ }
404
+ const body = await response.json();
405
+ const token = body[preset.auth.tokenField];
406
+ const user = body[preset.auth.userField] ?? body;
407
+ this.authState = {
408
+ userId: user.id,
409
+ email: user.email ?? data.email,
410
+ userName: user.name || user.email || data.email,
411
+ role: user.role,
412
+ token
413
+ };
414
+ this.persistState();
415
+ return user;
416
+ }
417
+ generateToken(user) {
418
+ return btoa(JSON.stringify({
419
+ userId: user.id,
420
+ email: user.email,
421
+ role: user.role,
422
+ iat: Date.now(),
423
+ exp: Date.now() + 24 * 60 * 60 * 1e3
424
+ }));
425
+ }
426
+ persistState() {
427
+ if (this.saveState) {
428
+ this.saveState(this.authState);
429
+ }
430
+ }
431
+ };
432
+
207
433
  // src/query-engine.ts
208
434
  var OPERATORS = [
209
435
  "startswith",
@@ -392,11 +618,143 @@ var LocalStorageBackend = class {
392
618
  localStorage.setItem(`${LS_META_PREFIX}${key}`, value);
393
619
  }
394
620
  };
621
+ function idbRequest(req) {
622
+ return new Promise((resolve, reject) => {
623
+ req.onsuccess = () => resolve(req.result);
624
+ req.onerror = () => reject(req.error);
625
+ });
626
+ }
627
+ var IDB_DATA_STORE = "data";
628
+ var IDB_META_STORE = "meta";
629
+ var IndexedDBBackend = class {
630
+ cache = new MemoryStorage();
631
+ db = null;
632
+ _ready;
633
+ constructor(dbName) {
634
+ this._ready = this.open(dbName);
635
+ }
636
+ get ready() {
637
+ return this._ready;
638
+ }
639
+ open(dbName) {
640
+ return new Promise((resolve, reject) => {
641
+ const req = indexedDB.open(dbName, 1);
642
+ req.onupgradeneeded = () => {
643
+ const db = req.result;
644
+ if (!db.objectStoreNames.contains(IDB_DATA_STORE)) {
645
+ db.createObjectStore(IDB_DATA_STORE);
646
+ }
647
+ if (!db.objectStoreNames.contains(IDB_META_STORE)) {
648
+ db.createObjectStore(IDB_META_STORE);
649
+ }
650
+ };
651
+ req.onsuccess = async () => {
652
+ this.db = req.result;
653
+ await this.loadAll();
654
+ resolve();
655
+ };
656
+ req.onerror = () => reject(req.error);
657
+ });
658
+ }
659
+ async loadAll() {
660
+ const db = this.db;
661
+ const tx = db.transaction([IDB_DATA_STORE, IDB_META_STORE], "readonly");
662
+ const dataStore = tx.objectStore(IDB_DATA_STORE);
663
+ const metaStore = tx.objectStore(IDB_META_STORE);
664
+ const dataKeys = await idbRequest(dataStore.getAllKeys());
665
+ const dataValues = await idbRequest(dataStore.getAll());
666
+ for (let i = 0; i < dataKeys.length; i++) {
667
+ const compositeKey = dataKeys[i];
668
+ const sepIdx = compositeKey.indexOf(":");
669
+ const resource = compositeKey.substring(0, sepIdx);
670
+ const id = compositeKey.substring(sepIdx + 1);
671
+ this.cache.set(resource, id, dataValues[i]);
672
+ }
673
+ const metaKeys = await idbRequest(metaStore.getAllKeys());
674
+ const metaValues = await idbRequest(metaStore.getAll());
675
+ for (let i = 0; i < metaKeys.length; i++) {
676
+ this.cache.setMeta(metaKeys[i], metaValues[i]);
677
+ }
678
+ }
679
+ writeData(resource, id, data) {
680
+ if (!this.db) return;
681
+ const tx = this.db.transaction(IDB_DATA_STORE, "readwrite");
682
+ tx.objectStore(IDB_DATA_STORE).put(data, `${resource}:${id}`);
683
+ }
684
+ deleteData(resource, id) {
685
+ if (!this.db) return;
686
+ const tx = this.db.transaction(IDB_DATA_STORE, "readwrite");
687
+ tx.objectStore(IDB_DATA_STORE).delete(`${resource}:${id}`);
688
+ }
689
+ writeMeta(key, value) {
690
+ if (!this.db) return;
691
+ const tx = this.db.transaction(IDB_META_STORE, "readwrite");
692
+ tx.objectStore(IDB_META_STORE).put(value, key);
693
+ }
694
+ getAll(resource) {
695
+ return this.cache.getAll(resource);
696
+ }
697
+ getById(resource, id) {
698
+ return this.cache.getById(resource, id);
699
+ }
700
+ set(resource, id, data) {
701
+ this.cache.set(resource, id, data);
702
+ this.writeData(resource, id, data);
703
+ }
704
+ remove(resource, id) {
705
+ this.cache.remove(resource, id);
706
+ this.deleteData(resource, id);
707
+ }
708
+ clear(resource) {
709
+ const items = this.cache.getAll(resource);
710
+ this.cache.clear(resource);
711
+ if (this.db) {
712
+ const tx = this.db.transaction(IDB_DATA_STORE, "readwrite");
713
+ const store = tx.objectStore(IDB_DATA_STORE);
714
+ for (const item of items) {
715
+ store.delete(`${resource}:${item.id}`);
716
+ }
717
+ }
718
+ }
719
+ getMeta(key) {
720
+ return this.cache.getMeta(key);
721
+ }
722
+ setMeta(key, value) {
723
+ this.cache.setMeta(key, value);
724
+ this.writeMeta(key, value);
725
+ }
726
+ };
395
727
  var LocalDriver = class {
396
728
  storage;
397
729
  entityClasses = /* @__PURE__ */ new Map();
730
+ authProvider = null;
731
+ _ready;
732
+ _isReady;
398
733
  constructor(config) {
399
- this.storage = config.persist === "localStorage" ? new LocalStorageBackend() : new MemoryStorage();
734
+ if (config.persist === "indexeddb") {
735
+ const backend = new IndexedDBBackend(config.dbName ?? "fauxbase");
736
+ this.storage = backend;
737
+ this._isReady = false;
738
+ this._ready = backend.ready.then(() => {
739
+ this._isReady = true;
740
+ });
741
+ } else {
742
+ this.storage = config.persist === "localStorage" ? new LocalStorageBackend() : new MemoryStorage();
743
+ this._isReady = true;
744
+ this._ready = Promise.resolve();
745
+ }
746
+ }
747
+ get ready() {
748
+ return this._ready;
749
+ }
750
+ get isReady() {
751
+ return this._isReady;
752
+ }
753
+ setAuthProvider(provider) {
754
+ this.authProvider = provider;
755
+ }
756
+ getStorageBackend() {
757
+ return this.storage;
400
758
  }
401
759
  registerEntity(resource, entityClass) {
402
760
  this.entityClasses.set(resource, entityClass);
@@ -419,13 +777,20 @@ var LocalDriver = class {
419
777
  async create(resource, data) {
420
778
  const entityClass = this.entityClasses.get(resource);
421
779
  const now = (/* @__PURE__ */ new Date()).toISOString();
780
+ const authContext = this.authProvider?.();
422
781
  let record = {
423
782
  ...data,
424
783
  id: data.id || generateUUID(),
425
784
  createdAt: now,
426
785
  updatedAt: now,
427
786
  deletedAt: null,
428
- version: 1
787
+ version: 1,
788
+ ...authContext ? {
789
+ createdById: authContext.userId,
790
+ createdByName: authContext.userName,
791
+ updatedById: authContext.userId,
792
+ updatedByName: authContext.userName
793
+ } : {}
429
794
  };
430
795
  if (entityClass) {
431
796
  record = applyDefaults(record, entityClass);
@@ -444,13 +809,18 @@ var LocalDriver = class {
444
809
  if (entityClass) {
445
810
  validateEntity(data, entityClass, false);
446
811
  }
812
+ const authContext = this.authProvider?.();
447
813
  const record = {
448
814
  ...existing,
449
815
  ...data,
450
816
  id,
451
817
  createdAt: existing.createdAt,
452
818
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
453
- version: (existing.version || 0) + 1
819
+ version: (existing.version || 0) + 1,
820
+ ...authContext ? {
821
+ updatedById: authContext.userId,
822
+ updatedByName: authContext.userName
823
+ } : {}
454
824
  };
455
825
  this.storage.set(resource, id, record);
456
826
  const result = entityClass ? applyComputedFields(record, entityClass) : record;
@@ -462,11 +832,18 @@ var LocalDriver = class {
462
832
  throw new NotFoundError(`${resource} with id "${id}" not found`);
463
833
  }
464
834
  const now = (/* @__PURE__ */ new Date()).toISOString();
835
+ const authContext = this.authProvider?.();
465
836
  const record = {
466
837
  ...existing,
467
838
  deletedAt: now,
468
839
  updatedAt: now,
469
- version: (existing.version || 0) + 1
840
+ version: (existing.version || 0) + 1,
841
+ ...authContext ? {
842
+ deletedById: authContext.userId,
843
+ deletedByName: authContext.userName,
844
+ updatedById: authContext.userId,
845
+ updatedByName: authContext.userName
846
+ } : {}
470
847
  };
471
848
  this.storage.set(resource, id, record);
472
849
  return { data: record };
@@ -529,6 +906,631 @@ var LocalDriver = class {
529
906
  }
530
907
  };
531
908
 
909
+ // src/presets/types.ts
910
+ function definePreset(config) {
911
+ return config;
912
+ }
913
+
914
+ // src/presets/default.ts
915
+ var defaultPreset = definePreset({
916
+ name: "default",
917
+ response: {
918
+ single: (raw) => ({ data: raw.data ?? raw }),
919
+ list: (raw) => ({
920
+ items: raw.items ?? raw.data ?? [],
921
+ meta: raw.meta ?? {}
922
+ }),
923
+ error: (raw) => ({
924
+ error: raw.error ?? raw.message ?? "Unknown error",
925
+ code: raw.code ?? "UNKNOWN",
926
+ details: raw.details
927
+ })
928
+ },
929
+ meta: { page: "page", size: "size", totalItems: "totalItems", totalPages: "totalPages" },
930
+ query: {
931
+ filterStyle: "django",
932
+ pageParam: "page",
933
+ sizeParam: "size",
934
+ sortParam: "sort",
935
+ sortFormat: "field,direction"
936
+ },
937
+ auth: {
938
+ loginUrl: "/auth/login",
939
+ registerUrl: "/auth/register",
940
+ logoutUrl: "/auth/logout",
941
+ tokenField: "token",
942
+ userField: "user",
943
+ headerFormat: "Bearer {token}"
944
+ }
945
+ });
946
+
947
+ // src/presets/spring-boot.ts
948
+ var springBootPreset = definePreset({
949
+ name: "spring-boot",
950
+ response: {
951
+ single: (raw) => ({ data: raw }),
952
+ list: (raw) => ({
953
+ items: raw.content ?? [],
954
+ meta: {
955
+ page: (raw.pageable?.pageNumber ?? 0) + 1,
956
+ size: raw.pageable?.pageSize ?? raw.size ?? 20,
957
+ totalItems: raw.totalElements ?? 0,
958
+ totalPages: raw.totalPages ?? 0
959
+ }
960
+ }),
961
+ error: (raw) => ({
962
+ error: raw.message ?? raw.error ?? "Unknown error",
963
+ code: raw.status?.toString() ?? "UNKNOWN",
964
+ details: raw.errors?.reduce?.((acc, e) => {
965
+ acc[e.field ?? e.code ?? "unknown"] = e.defaultMessage ?? e.message ?? "";
966
+ return acc;
967
+ }, {}) ?? void 0
968
+ })
969
+ },
970
+ meta: { page: "page", size: "size", totalItems: "totalElements", totalPages: "totalPages" },
971
+ query: {
972
+ filterStyle: "dot",
973
+ pageParam: "page",
974
+ sizeParam: "size",
975
+ sortParam: "sort",
976
+ sortFormat: "field,direction",
977
+ pageOffset: -1
978
+ // 0-indexed
979
+ },
980
+ auth: {
981
+ loginUrl: "/api/auth/login",
982
+ registerUrl: "/api/auth/register",
983
+ tokenField: "token",
984
+ userField: "user",
985
+ headerFormat: "Bearer {token}"
986
+ }
987
+ });
988
+
989
+ // src/presets/laravel.ts
990
+ var laravelPreset = definePreset({
991
+ name: "laravel",
992
+ response: {
993
+ single: (raw) => ({ data: raw.data ?? raw }),
994
+ list: (raw) => ({
995
+ items: raw.data ?? [],
996
+ meta: {
997
+ page: raw.meta?.current_page ?? raw.current_page ?? 1,
998
+ size: raw.meta?.per_page ?? raw.per_page ?? 15,
999
+ totalItems: raw.meta?.total ?? raw.total ?? 0,
1000
+ totalPages: raw.meta?.last_page ?? raw.last_page ?? 0
1001
+ }
1002
+ }),
1003
+ error: (raw) => ({
1004
+ error: raw.message ?? "Unknown error",
1005
+ code: raw.status?.toString() ?? "UNKNOWN",
1006
+ details: raw.errors ? Object.entries(raw.errors).reduce((acc, [key, val]) => {
1007
+ acc[key] = Array.isArray(val) ? val[0] : val;
1008
+ return acc;
1009
+ }, {}) : void 0
1010
+ })
1011
+ },
1012
+ meta: { page: "current_page", size: "per_page", totalItems: "total", totalPages: "last_page" },
1013
+ query: {
1014
+ filterStyle: "bracket",
1015
+ pageParam: "page",
1016
+ sizeParam: "per_page",
1017
+ sortParam: "sort",
1018
+ sortFormat: "field,direction"
1019
+ },
1020
+ auth: {
1021
+ loginUrl: "/api/login",
1022
+ registerUrl: "/api/register",
1023
+ logoutUrl: "/api/logout",
1024
+ tokenField: "token",
1025
+ userField: "user",
1026
+ headerFormat: "Bearer {token}"
1027
+ }
1028
+ });
1029
+
1030
+ // src/presets/django.ts
1031
+ var djangoPreset = definePreset({
1032
+ name: "django",
1033
+ response: {
1034
+ single: (raw) => ({ data: raw }),
1035
+ list: (raw) => ({
1036
+ items: raw.results ?? [],
1037
+ meta: {
1038
+ page: 1,
1039
+ // Django REST doesn't always include page number
1040
+ size: raw.results?.length ?? 0,
1041
+ totalItems: raw.count ?? 0,
1042
+ totalPages: raw.count && raw.results?.length ? Math.ceil(raw.count / raw.results.length) : 0
1043
+ }
1044
+ }),
1045
+ error: (raw) => ({
1046
+ error: raw.detail ?? raw.message ?? "Unknown error",
1047
+ code: raw.status_code?.toString() ?? "UNKNOWN",
1048
+ details: typeof raw === "object" && !raw.detail ? Object.entries(raw).reduce((acc, [key, val]) => {
1049
+ if (key !== "status_code") {
1050
+ acc[key] = Array.isArray(val) ? val[0] : String(val);
1051
+ }
1052
+ return acc;
1053
+ }, {}) : void 0
1054
+ })
1055
+ },
1056
+ meta: { page: "page", size: "page_size", totalItems: "count", totalPages: "total_pages" },
1057
+ query: {
1058
+ filterStyle: "django",
1059
+ pageParam: "page",
1060
+ sizeParam: "page_size",
1061
+ sortParam: "ordering",
1062
+ sortFormat: "field,direction"
1063
+ },
1064
+ auth: {
1065
+ loginUrl: "/api/auth/login/",
1066
+ registerUrl: "/api/auth/register/",
1067
+ logoutUrl: "/api/auth/logout/",
1068
+ tokenField: "token",
1069
+ userField: "user",
1070
+ headerFormat: "Token {token}"
1071
+ }
1072
+ });
1073
+
1074
+ // src/presets/nestjs.ts
1075
+ var nestjsPreset = definePreset({
1076
+ name: "nestjs",
1077
+ response: {
1078
+ single: (raw) => ({ data: raw.data ?? raw }),
1079
+ list: (raw) => ({
1080
+ items: raw.data ?? raw.items ?? [],
1081
+ meta: raw.meta ?? {}
1082
+ }),
1083
+ error: (raw) => ({
1084
+ error: raw.message ?? "Unknown error",
1085
+ code: raw.error ?? raw.statusCode?.toString() ?? "UNKNOWN",
1086
+ details: raw.message && Array.isArray(raw.message) ? raw.message.reduce((acc, msg, i) => {
1087
+ acc[`field_${i}`] = msg;
1088
+ return acc;
1089
+ }, {}) : void 0
1090
+ })
1091
+ },
1092
+ meta: { page: "page", size: "limit", totalItems: "totalItems", totalPages: "totalPages" },
1093
+ query: {
1094
+ filterStyle: "nestjs",
1095
+ pageParam: "page",
1096
+ sizeParam: "limit",
1097
+ sortParam: "sort",
1098
+ sortFormat: "field:direction"
1099
+ },
1100
+ auth: {
1101
+ loginUrl: "/auth/login",
1102
+ registerUrl: "/auth/register",
1103
+ tokenField: "access_token",
1104
+ userField: "user",
1105
+ headerFormat: "Bearer {token}"
1106
+ }
1107
+ });
1108
+
1109
+ // src/presets/express.ts
1110
+ var expressPreset = definePreset({
1111
+ name: "express",
1112
+ response: {
1113
+ single: (raw) => ({ data: raw.data ?? raw }),
1114
+ list: (raw) => ({
1115
+ items: raw.data ?? raw.items ?? [],
1116
+ meta: raw.meta ?? {}
1117
+ }),
1118
+ error: (raw) => ({
1119
+ error: raw.error ?? raw.message ?? "Unknown error",
1120
+ code: raw.code ?? "UNKNOWN",
1121
+ details: raw.details
1122
+ })
1123
+ },
1124
+ meta: { page: "page", size: "size", totalItems: "totalItems", totalPages: "totalPages" },
1125
+ query: {
1126
+ filterStyle: "django",
1127
+ pageParam: "page",
1128
+ sizeParam: "size",
1129
+ sortParam: "sort",
1130
+ sortFormat: "field,direction"
1131
+ },
1132
+ auth: {
1133
+ loginUrl: "/api/auth/login",
1134
+ registerUrl: "/api/auth/register",
1135
+ logoutUrl: "/api/auth/logout",
1136
+ tokenField: "token",
1137
+ userField: "user",
1138
+ headerFormat: "Bearer {token}"
1139
+ }
1140
+ });
1141
+
1142
+ // src/presets/index.ts
1143
+ var presetRegistry = /* @__PURE__ */ new Map([
1144
+ ["default", defaultPreset],
1145
+ ["spring-boot", springBootPreset],
1146
+ ["laravel", laravelPreset],
1147
+ ["django", djangoPreset],
1148
+ ["nestjs", nestjsPreset],
1149
+ ["express", expressPreset]
1150
+ ]);
1151
+ function getPreset(name) {
1152
+ const preset = presetRegistry.get(name);
1153
+ if (!preset) {
1154
+ throw new Error(`Unknown preset: "${name}". Available: ${Array.from(presetRegistry.keys()).join(", ")}`);
1155
+ }
1156
+ return preset;
1157
+ }
1158
+
1159
+ // src/drivers/query-serializer.ts
1160
+ function serializeQuery(query, config) {
1161
+ const params = new URLSearchParams();
1162
+ if (query.filter) {
1163
+ serializeFilters(params, query.filter, config.filterStyle);
1164
+ }
1165
+ if (query.sort && config.sortParam) {
1166
+ const direction = query.sort.direction;
1167
+ if (config.sortParam === "ordering") {
1168
+ params.set(config.sortParam, direction === "desc" ? `-${query.sort.field}` : query.sort.field);
1169
+ } else if (config.sortFormat === "field:direction") {
1170
+ params.set(config.sortParam, `${query.sort.field}:${direction}`);
1171
+ } else {
1172
+ params.set(config.sortParam, `${query.sort.field},${direction}`);
1173
+ }
1174
+ }
1175
+ if (query.page !== void 0) {
1176
+ const pageOffset = config.pageOffset ?? 0;
1177
+ params.set(config.pageParam, String(query.page + pageOffset));
1178
+ }
1179
+ if (query.size !== void 0) {
1180
+ params.set(config.sizeParam, String(query.size));
1181
+ }
1182
+ return params;
1183
+ }
1184
+ function serializeFilters(params, filter, style) {
1185
+ for (const [key, value] of Object.entries(filter)) {
1186
+ if (value === void 0) continue;
1187
+ const serialized = typeof value === "object" && !Array.isArray(value) ? JSON.stringify(value) : String(value);
1188
+ switch (style) {
1189
+ case "django":
1190
+ params.set(key, serialized);
1191
+ break;
1192
+ case "dot":
1193
+ params.set(key.replace(/__/g, "."), serialized);
1194
+ break;
1195
+ case "bracket": {
1196
+ const bracketKey = key.replace(/__/g, "_");
1197
+ params.set(`filter[${bracketKey}]`, serialized);
1198
+ break;
1199
+ }
1200
+ case "nestjs": {
1201
+ const parts = key.split("__");
1202
+ if (parts.length === 2) {
1203
+ params.set(`filter.${parts[0]}.$${parts[1]}`, serialized);
1204
+ } else {
1205
+ params.set(`filter.${key}`, serialized);
1206
+ }
1207
+ break;
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+
1213
+ // src/drivers/http.ts
1214
+ var HttpDriver = class {
1215
+ baseUrl;
1216
+ preset;
1217
+ timeout;
1218
+ maxRetries;
1219
+ baseDelay;
1220
+ defaultHeaders;
1221
+ endpoints = /* @__PURE__ */ new Map();
1222
+ authProvider = null;
1223
+ constructor(config) {
1224
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
1225
+ this.preset = typeof config.preset === "string" ? getPreset(config.preset ?? "default") : config.preset ?? getPreset("default");
1226
+ this.timeout = config.timeout ?? 3e4;
1227
+ this.maxRetries = config.retry?.maxRetries ?? 3;
1228
+ this.baseDelay = config.retry?.baseDelay ?? 300;
1229
+ this.defaultHeaders = config.headers ?? {};
1230
+ }
1231
+ setAuthProvider(provider) {
1232
+ this.authProvider = provider;
1233
+ }
1234
+ registerEndpoint(resource, endpoint) {
1235
+ this.endpoints.set(resource, endpoint);
1236
+ }
1237
+ getEndpoint(resource) {
1238
+ return this.endpoints.get(resource) ?? `/${resource}`;
1239
+ }
1240
+ buildUrl(resource, id) {
1241
+ const endpoint = this.getEndpoint(resource);
1242
+ const base = `${this.baseUrl}${endpoint}`;
1243
+ return id ? `${base}/${id}` : base;
1244
+ }
1245
+ buildHeaders() {
1246
+ const headers = {
1247
+ "Content-Type": "application/json",
1248
+ ...this.defaultHeaders
1249
+ };
1250
+ const auth = this.authProvider?.();
1251
+ if (auth?.token) {
1252
+ headers["Authorization"] = this.preset.auth.headerFormat.replace("{token}", auth.token);
1253
+ }
1254
+ return headers;
1255
+ }
1256
+ async request(url, options = {}, retryCount = 0) {
1257
+ const controller = new AbortController();
1258
+ const timer = setTimeout(() => controller.abort(), this.timeout);
1259
+ try {
1260
+ const response = await fetch(url, {
1261
+ ...options,
1262
+ headers: { ...this.buildHeaders(), ...options.headers ?? {} },
1263
+ signal: controller.signal
1264
+ });
1265
+ clearTimeout(timer);
1266
+ if (!response.ok) {
1267
+ if (response.status >= 500 && retryCount < this.maxRetries) {
1268
+ const delay = this.baseDelay * Math.pow(2, retryCount);
1269
+ await new Promise((r) => setTimeout(r, delay));
1270
+ return this.request(url, options, retryCount + 1);
1271
+ }
1272
+ const body = await response.json().catch(() => ({}));
1273
+ this.throwMappedError(response.status, body);
1274
+ }
1275
+ if (response.status === 204) {
1276
+ return {};
1277
+ }
1278
+ return response.json();
1279
+ } catch (err) {
1280
+ clearTimeout(timer);
1281
+ if (err instanceof FauxbaseError) throw err;
1282
+ if (err.name === "AbortError") {
1283
+ throw new TimeoutError(`Request timed out after ${this.timeout}ms`);
1284
+ }
1285
+ throw new NetworkError(err.message ?? "Network request failed");
1286
+ }
1287
+ }
1288
+ throwMappedError(status, body) {
1289
+ const parsed = this.preset.response.error(body);
1290
+ switch (true) {
1291
+ case (status === 400 || status === 422):
1292
+ throw new ValidationError(parsed.error, parsed.details);
1293
+ case (status === 401 || status === 403):
1294
+ throw new ForbiddenError(parsed.error);
1295
+ case status === 404:
1296
+ throw new NotFoundError(parsed.error);
1297
+ case status === 409:
1298
+ throw new ConflictError(parsed.error);
1299
+ default:
1300
+ throw new HttpError(parsed.error, status, parsed.details);
1301
+ }
1302
+ }
1303
+ async list(resource, query) {
1304
+ const url = this.buildUrl(resource);
1305
+ const params = serializeQuery(query, this.preset.query);
1306
+ const queryString = params.toString();
1307
+ const fullUrl = queryString ? `${url}?${queryString}` : url;
1308
+ const raw = await this.request(fullUrl);
1309
+ const parsed = this.preset.response.list(raw);
1310
+ return {
1311
+ items: parsed.items,
1312
+ meta: {
1313
+ page: parsed.meta[this.preset.meta.page] ?? parsed.meta.page ?? query.page ?? 1,
1314
+ size: parsed.meta[this.preset.meta.size] ?? parsed.meta.size ?? query.size ?? 20,
1315
+ totalItems: parsed.meta[this.preset.meta.totalItems] ?? parsed.meta.totalItems ?? 0,
1316
+ totalPages: parsed.meta[this.preset.meta.totalPages] ?? parsed.meta.totalPages ?? 0
1317
+ }
1318
+ };
1319
+ }
1320
+ async get(resource, id) {
1321
+ const url = this.buildUrl(resource, id);
1322
+ const raw = await this.request(url);
1323
+ return this.preset.response.single(raw);
1324
+ }
1325
+ async create(resource, data) {
1326
+ const url = this.buildUrl(resource);
1327
+ const raw = await this.request(url, {
1328
+ method: "POST",
1329
+ body: JSON.stringify(data)
1330
+ });
1331
+ return this.preset.response.single(raw);
1332
+ }
1333
+ async update(resource, id, data) {
1334
+ const url = this.buildUrl(resource, id);
1335
+ const raw = await this.request(url, {
1336
+ method: "PATCH",
1337
+ body: JSON.stringify(data)
1338
+ });
1339
+ return this.preset.response.single(raw);
1340
+ }
1341
+ async delete(resource, id) {
1342
+ const url = this.buildUrl(resource, id);
1343
+ const raw = await this.request(url, {
1344
+ method: "DELETE"
1345
+ });
1346
+ return this.preset.response.single(raw);
1347
+ }
1348
+ async count(resource, filter) {
1349
+ const url = `${this.buildUrl(resource)}/count`;
1350
+ const params = filter ? serializeQuery({ filter }, this.preset.query) : new URLSearchParams();
1351
+ const queryString = params.toString();
1352
+ const fullUrl = queryString ? `${url}?${queryString}` : url;
1353
+ const raw = await this.request(fullUrl);
1354
+ return raw.count ?? raw.data?.count ?? 0;
1355
+ }
1356
+ async bulkCreate(resource, data) {
1357
+ const url = `${this.buildUrl(resource)}/bulk`;
1358
+ const raw = await this.request(url, {
1359
+ method: "POST",
1360
+ body: JSON.stringify(data)
1361
+ });
1362
+ const parsed = this.preset.response.single(raw);
1363
+ return { data: Array.isArray(parsed.data) ? parsed.data : [parsed.data] };
1364
+ }
1365
+ async bulkUpdate(resource, updates) {
1366
+ const url = `${this.buildUrl(resource)}/bulk`;
1367
+ const raw = await this.request(url, {
1368
+ method: "PATCH",
1369
+ body: JSON.stringify(updates)
1370
+ });
1371
+ const parsed = this.preset.response.single(raw);
1372
+ return { data: Array.isArray(parsed.data) ? parsed.data : [parsed.data] };
1373
+ }
1374
+ async bulkDelete(resource, ids) {
1375
+ const url = `${this.buildUrl(resource)}/bulk`;
1376
+ const raw = await this.request(url, {
1377
+ method: "DELETE",
1378
+ body: JSON.stringify({ ids })
1379
+ });
1380
+ return { data: { count: raw.count ?? raw.data?.count ?? ids.length } };
1381
+ }
1382
+ // Seed methods are no-ops for HTTP — backend owns data
1383
+ seed() {
1384
+ }
1385
+ getSeedVersion() {
1386
+ return null;
1387
+ }
1388
+ setSeedVersion() {
1389
+ }
1390
+ clear() {
1391
+ }
1392
+ };
1393
+
1394
+ // src/events/event-bus.ts
1395
+ var EventBus = class {
1396
+ listeners = /* @__PURE__ */ new Map();
1397
+ anyListeners = /* @__PURE__ */ new Set();
1398
+ on(resource, handler) {
1399
+ if (!this.listeners.has(resource)) {
1400
+ this.listeners.set(resource, /* @__PURE__ */ new Set());
1401
+ }
1402
+ this.listeners.get(resource).add(handler);
1403
+ return () => {
1404
+ this.listeners.get(resource)?.delete(handler);
1405
+ };
1406
+ }
1407
+ onAny(handler) {
1408
+ this.anyListeners.add(handler);
1409
+ return () => {
1410
+ this.anyListeners.delete(handler);
1411
+ };
1412
+ }
1413
+ emit(event) {
1414
+ const resourceListeners = this.listeners.get(event.resource);
1415
+ if (resourceListeners) {
1416
+ for (const handler of resourceListeners) {
1417
+ handler(event);
1418
+ }
1419
+ }
1420
+ for (const handler of this.anyListeners) {
1421
+ handler(event);
1422
+ }
1423
+ }
1424
+ destroy() {
1425
+ this.listeners.clear();
1426
+ this.anyListeners.clear();
1427
+ }
1428
+ };
1429
+
1430
+ // src/events/sse-source.ts
1431
+ var SSESource = class {
1432
+ constructor(config, eventBus) {
1433
+ this.config = config;
1434
+ this.eventBus = eventBus;
1435
+ }
1436
+ eventSource = null;
1437
+ connect() {
1438
+ this.eventSource = new EventSource(this.config.url, {
1439
+ withCredentials: this.config.withCredentials
1440
+ });
1441
+ for (const [eventType, resource] of Object.entries(this.config.eventMap)) {
1442
+ this.eventSource.addEventListener(eventType, (e) => {
1443
+ const parsed = this.parseEvent(e, resource);
1444
+ if (parsed) {
1445
+ this.eventBus.emit(parsed);
1446
+ }
1447
+ });
1448
+ }
1449
+ }
1450
+ disconnect() {
1451
+ if (this.eventSource) {
1452
+ this.eventSource.close();
1453
+ this.eventSource = null;
1454
+ }
1455
+ }
1456
+ parseEvent(e, resource) {
1457
+ try {
1458
+ const raw = JSON.parse(e.data);
1459
+ return {
1460
+ action: raw.action,
1461
+ resource,
1462
+ data: raw.data,
1463
+ id: raw.id,
1464
+ ids: raw.ids,
1465
+ timestamp: raw.timestamp ?? Date.now(),
1466
+ source: "remote"
1467
+ };
1468
+ } catch {
1469
+ return null;
1470
+ }
1471
+ }
1472
+ };
1473
+
1474
+ // src/events/stomp-source.ts
1475
+ var STOMPSource = class {
1476
+ constructor(config, eventBus) {
1477
+ this.config = config;
1478
+ this.eventBus = eventBus;
1479
+ }
1480
+ client = null;
1481
+ connect() {
1482
+ this.connectAsync();
1483
+ }
1484
+ async connectAsync() {
1485
+ let StompJs;
1486
+ try {
1487
+ const moduleName = "@stomp/stompjs";
1488
+ StompJs = await Function("m", "return import(m)")(moduleName);
1489
+ } catch {
1490
+ throw new Error(
1491
+ "STOMP source requires @stomp/stompjs. Install it: npm install @stomp/stompjs"
1492
+ );
1493
+ }
1494
+ this.client = new StompJs.Client({
1495
+ brokerURL: this.config.brokerUrl,
1496
+ connectHeaders: this.config.connectHeaders,
1497
+ onConnect: () => {
1498
+ for (const [destination, resource] of Object.entries(this.config.subscriptions)) {
1499
+ this.client.subscribe(destination, (message) => {
1500
+ const parsed = this.parseMessage(message, resource);
1501
+ if (parsed) {
1502
+ this.eventBus.emit(parsed);
1503
+ }
1504
+ });
1505
+ }
1506
+ }
1507
+ });
1508
+ this.client.activate();
1509
+ }
1510
+ disconnect() {
1511
+ if (this.client) {
1512
+ this.client.deactivate();
1513
+ this.client = null;
1514
+ }
1515
+ }
1516
+ parseMessage(message, resource) {
1517
+ try {
1518
+ const raw = JSON.parse(message.body);
1519
+ return {
1520
+ action: raw.action,
1521
+ resource,
1522
+ data: raw.data,
1523
+ id: raw.id,
1524
+ ids: raw.ids,
1525
+ timestamp: raw.timestamp ?? Date.now(),
1526
+ source: "remote"
1527
+ };
1528
+ } catch {
1529
+ return null;
1530
+ }
1531
+ }
1532
+ };
1533
+
532
1534
  // src/seed.ts
533
1535
  function seed(entityClass, data) {
534
1536
  const entityName = entityClass.name.toLowerCase();
@@ -553,19 +1555,130 @@ function simpleHash(str) {
553
1555
  // src/client.ts
554
1556
  function createClient(config) {
555
1557
  const driverConfig = config.driver ?? { type: "local" };
556
- const driver = createDriver(driverConfig);
1558
+ const defaultDriver = createDriver(driverConfig);
557
1559
  const client = {};
1560
+ const overrideDrivers = /* @__PURE__ */ new Map();
1561
+ if (config.overrides) {
1562
+ for (const [name, override] of Object.entries(config.overrides)) {
1563
+ overrideDrivers.set(name, createDriver(override.driver));
1564
+ }
1565
+ }
558
1566
  for (const [name, ServiceClass] of Object.entries(config.services)) {
559
1567
  const instance = new ServiceClass();
1568
+ const driver = overrideDrivers.get(name) ?? defaultDriver;
560
1569
  instance._init(driver, name);
561
1570
  if (driver instanceof LocalDriver) {
562
1571
  driver.registerEntity(name, instance.entity);
563
1572
  }
1573
+ if (driver instanceof HttpDriver) {
1574
+ driver.registerEndpoint(name, instance.endpoint);
1575
+ }
564
1576
  client[name] = instance;
565
1577
  }
566
- if (config.seeds && driver instanceof LocalDriver) {
567
- applySeedsIfNeeded(driver, config.seeds);
1578
+ if (config.auth) {
1579
+ const AuthClass = config.auth;
1580
+ const authInstance = new AuthClass();
1581
+ const resourceName = authInstance.entity.name.toLowerCase();
1582
+ if (defaultDriver instanceof LocalDriver) {
1583
+ authInstance._init(defaultDriver, resourceName);
1584
+ defaultDriver.registerEntity(resourceName, authInstance.entity);
1585
+ const storage = defaultDriver.getStorageBackend();
1586
+ authInstance._initAuth(
1587
+ () => {
1588
+ const raw = storage.getMeta("_authState");
1589
+ return raw ? JSON.parse(raw) : null;
1590
+ },
1591
+ (state) => {
1592
+ if (state) {
1593
+ storage.setMeta("_authState", JSON.stringify(state));
1594
+ } else {
1595
+ storage.setMeta("_authState", "");
1596
+ }
1597
+ }
1598
+ );
1599
+ defaultDriver.setAuthProvider(() => authInstance.getAuthContext());
1600
+ } else if (defaultDriver instanceof HttpDriver) {
1601
+ authInstance._init(defaultDriver, resourceName);
1602
+ defaultDriver.registerEndpoint(resourceName, authInstance.endpoint);
1603
+ let memoryAuthState = null;
1604
+ authInstance._initAuth(
1605
+ () => memoryAuthState,
1606
+ (state) => {
1607
+ memoryAuthState = state;
1608
+ }
1609
+ );
1610
+ authInstance._setHttpMode(defaultDriver);
1611
+ defaultDriver.setAuthProvider(() => {
1612
+ const token = authInstance.token;
1613
+ return token ? { token } : null;
1614
+ });
1615
+ }
1616
+ client.auth = authInstance;
1617
+ for (const driver of overrideDrivers.values()) {
1618
+ if (driver instanceof HttpDriver) {
1619
+ driver.setAuthProvider(() => {
1620
+ const token = client.auth?.token;
1621
+ return token ? { token } : null;
1622
+ });
1623
+ }
1624
+ }
568
1625
  }
1626
+ for (const key of Object.keys(client)) {
1627
+ const svc = client[key];
1628
+ if (svc && typeof svc._setClient === "function") {
1629
+ svc._setClient(client);
1630
+ }
1631
+ }
1632
+ let eventSource = null;
1633
+ if (config.events) {
1634
+ const eventBus = new EventBus();
1635
+ client._eventBus = eventBus;
1636
+ for (const [name, ServiceClass] of Object.entries(config.services)) {
1637
+ const svc = client[name];
1638
+ svc._eventBus = eventBus;
1639
+ }
1640
+ const eventsConfig = config.events === true ? {} : config.events;
1641
+ if (eventsConfig.handlers) {
1642
+ for (const [resource, handler] of Object.entries(eventsConfig.handlers)) {
1643
+ eventBus.on(resource, handler);
1644
+ }
1645
+ }
1646
+ if (eventsConfig.source) {
1647
+ if (eventsConfig.source.type === "sse") {
1648
+ eventSource = new SSESource(eventsConfig.source, eventBus);
1649
+ } else if (eventsConfig.source.type === "stomp") {
1650
+ eventSource = new STOMPSource(eventsConfig.source, eventBus);
1651
+ }
1652
+ eventSource?.connect();
1653
+ }
1654
+ client.disconnect = () => {
1655
+ eventSource?.disconnect();
1656
+ eventBus.destroy();
1657
+ };
1658
+ }
1659
+ let readyPromise;
1660
+ if (defaultDriver instanceof LocalDriver) {
1661
+ if (defaultDriver.isReady) {
1662
+ if (config.seeds) {
1663
+ applySeedsIfNeeded(defaultDriver, config.seeds);
1664
+ }
1665
+ readyPromise = Promise.resolve();
1666
+ } else {
1667
+ readyPromise = defaultDriver.ready.then(() => {
1668
+ if (config.seeds) {
1669
+ applySeedsIfNeeded(defaultDriver, config.seeds);
1670
+ }
1671
+ });
1672
+ }
1673
+ } else {
1674
+ readyPromise = Promise.resolve();
1675
+ }
1676
+ Object.defineProperty(client, "ready", {
1677
+ value: readyPromise,
1678
+ writable: false,
1679
+ enumerable: false,
1680
+ configurable: false
1681
+ });
569
1682
  return client;
570
1683
  }
571
1684
  function createDriver(config) {
@@ -573,7 +1686,7 @@ function createDriver(config) {
573
1686
  case "local":
574
1687
  return new LocalDriver(config);
575
1688
  case "http":
576
- throw new Error("HttpDriver not implemented yet");
1689
+ return new HttpDriver(config);
577
1690
  default:
578
1691
  throw new Error(`Unknown driver type: ${config.type}`);
579
1692
  }
@@ -588,12 +1701,19 @@ function applySeedsIfNeeded(driver, seeds) {
588
1701
  driver.setSeedVersion(newVersion);
589
1702
  }
590
1703
 
1704
+ exports.AuthService = AuthService;
591
1705
  exports.ConflictError = ConflictError;
592
1706
  exports.Entity = Entity;
1707
+ exports.EventBus = EventBus;
593
1708
  exports.FauxbaseError = FauxbaseError;
594
1709
  exports.ForbiddenError = ForbiddenError;
1710
+ exports.HttpDriver = HttpDriver;
1711
+ exports.HttpError = HttpError;
1712
+ exports.LocalDriver = LocalDriver;
1713
+ exports.NetworkError = NetworkError;
595
1714
  exports.NotFoundError = NotFoundError;
596
1715
  exports.Service = Service;
1716
+ exports.TimeoutError = TimeoutError;
597
1717
  exports.ValidationError = ValidationError;
598
1718
  exports.afterCreate = afterCreate;
599
1719
  exports.afterUpdate = afterUpdate;
@@ -601,8 +1721,16 @@ exports.beforeCreate = beforeCreate;
601
1721
  exports.beforeUpdate = beforeUpdate;
602
1722
  exports.computed = computed;
603
1723
  exports.createClient = createClient;
1724
+ exports.defaultPreset = defaultPreset;
1725
+ exports.definePreset = definePreset;
1726
+ exports.djangoPreset = djangoPreset;
1727
+ exports.expressPreset = expressPreset;
604
1728
  exports.field = field;
1729
+ exports.getPreset = getPreset;
1730
+ exports.laravelPreset = laravelPreset;
1731
+ exports.nestjsPreset = nestjsPreset;
605
1732
  exports.relation = relation;
606
1733
  exports.seed = seed;
1734
+ exports.springBootPreset = springBootPreset;
607
1735
  //# sourceMappingURL=index.cjs.map
608
1736
  //# sourceMappingURL=index.cjs.map