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