jazz-tools 0.18.14 → 0.18.16

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.
Files changed (63) hide show
  1. package/.turbo/turbo-build.log +45 -33
  2. package/CHANGELOG.md +23 -0
  3. package/dist/better-auth/database-adapter/index.d.ts +50 -0
  4. package/dist/better-auth/database-adapter/index.d.ts.map +1 -0
  5. package/dist/better-auth/database-adapter/index.js +920 -0
  6. package/dist/better-auth/database-adapter/index.js.map +1 -0
  7. package/dist/better-auth/database-adapter/repository/account.d.ts +24 -0
  8. package/dist/better-auth/database-adapter/repository/account.d.ts.map +1 -0
  9. package/dist/better-auth/database-adapter/repository/generic.d.ts +45 -0
  10. package/dist/better-auth/database-adapter/repository/generic.d.ts.map +1 -0
  11. package/dist/better-auth/database-adapter/repository/index.d.ts +6 -0
  12. package/dist/better-auth/database-adapter/repository/index.d.ts.map +1 -0
  13. package/dist/better-auth/database-adapter/repository/session.d.ts +29 -0
  14. package/dist/better-auth/database-adapter/repository/session.d.ts.map +1 -0
  15. package/dist/better-auth/database-adapter/repository/user.d.ts +30 -0
  16. package/dist/better-auth/database-adapter/repository/user.d.ts.map +1 -0
  17. package/dist/better-auth/database-adapter/repository/verification.d.ts +18 -0
  18. package/dist/better-auth/database-adapter/repository/verification.d.ts.map +1 -0
  19. package/dist/better-auth/database-adapter/schema.d.ts +27 -0
  20. package/dist/better-auth/database-adapter/schema.d.ts.map +1 -0
  21. package/dist/better-auth/database-adapter/tests/index.test.d.ts +2 -0
  22. package/dist/better-auth/database-adapter/tests/index.test.d.ts.map +1 -0
  23. package/dist/better-auth/database-adapter/tests/repository/account.test.d.ts +2 -0
  24. package/dist/better-auth/database-adapter/tests/repository/account.test.d.ts.map +1 -0
  25. package/dist/better-auth/database-adapter/tests/repository/generic.test.d.ts +2 -0
  26. package/dist/better-auth/database-adapter/tests/repository/generic.test.d.ts.map +1 -0
  27. package/dist/better-auth/database-adapter/tests/repository/session.test.d.ts +2 -0
  28. package/dist/better-auth/database-adapter/tests/repository/session.test.d.ts.map +1 -0
  29. package/dist/better-auth/database-adapter/tests/repository/user.test.d.ts +2 -0
  30. package/dist/better-auth/database-adapter/tests/repository/user.test.d.ts.map +1 -0
  31. package/dist/better-auth/database-adapter/tests/repository/verification.test.d.ts +2 -0
  32. package/dist/better-auth/database-adapter/tests/repository/verification.test.d.ts.map +1 -0
  33. package/dist/better-auth/database-adapter/tests/sync-utils.d.ts +16 -0
  34. package/dist/better-auth/database-adapter/tests/sync-utils.d.ts.map +1 -0
  35. package/dist/better-auth/database-adapter/tests/utils.test.d.ts +2 -0
  36. package/dist/better-auth/database-adapter/tests/utils.test.d.ts.map +1 -0
  37. package/dist/better-auth/database-adapter/utils.d.ts +16 -0
  38. package/dist/better-auth/database-adapter/utils.d.ts.map +1 -0
  39. package/dist/worker/edge-wasm.d.ts +2 -0
  40. package/dist/worker/edge-wasm.d.ts.map +1 -0
  41. package/dist/worker/edge-wasm.js +5 -0
  42. package/dist/worker/edge-wasm.js.map +1 -0
  43. package/jazz-tools-0.18.6.tgz +0 -0
  44. package/package.json +15 -5
  45. package/src/better-auth/database-adapter/index.ts +228 -0
  46. package/src/better-auth/database-adapter/repository/account.ts +131 -0
  47. package/src/better-auth/database-adapter/repository/generic.ts +297 -0
  48. package/src/better-auth/database-adapter/repository/index.ts +5 -0
  49. package/src/better-auth/database-adapter/repository/session.ts +190 -0
  50. package/src/better-auth/database-adapter/repository/user.ts +158 -0
  51. package/src/better-auth/database-adapter/repository/verification.ts +37 -0
  52. package/src/better-auth/database-adapter/schema.ts +222 -0
  53. package/src/better-auth/database-adapter/tests/index.test.ts +690 -0
  54. package/src/better-auth/database-adapter/tests/repository/account.test.ts +149 -0
  55. package/src/better-auth/database-adapter/tests/repository/generic.test.ts +183 -0
  56. package/src/better-auth/database-adapter/tests/repository/session.test.ts +419 -0
  57. package/src/better-auth/database-adapter/tests/repository/user.test.ts +673 -0
  58. package/src/better-auth/database-adapter/tests/repository/verification.test.ts +101 -0
  59. package/src/better-auth/database-adapter/tests/sync-utils.ts +127 -0
  60. package/src/better-auth/database-adapter/tests/utils.test.ts +787 -0
  61. package/src/better-auth/database-adapter/utils.ts +178 -0
  62. package/src/worker/edge-wasm.ts +5 -0
  63. package/tsup.config.ts +8 -0
@@ -0,0 +1,920 @@
1
+ // src/better-auth/database-adapter/index.ts
2
+ import { createAdapter } from "better-auth/adapters";
3
+ import { startWorker } from "jazz-tools/worker";
4
+
5
+ // src/better-auth/database-adapter/utils.ts
6
+ function filterListByWhere(data, where) {
7
+ if (!Array.isArray(data)) {
8
+ throw new Error("Expected data to be an array");
9
+ }
10
+ if (where === void 0) {
11
+ return data;
12
+ }
13
+ if (!Array.isArray(where)) {
14
+ throw new Error("Expected where to be an array");
15
+ }
16
+ function evaluateCondition(item, condition) {
17
+ const { field, operator, value } = condition;
18
+ const itemValue = field === "id" ? item.$jazz.id : item[field];
19
+ switch (operator) {
20
+ case "eq":
21
+ return itemValue === value;
22
+ case "ne":
23
+ return itemValue !== value;
24
+ case "lt":
25
+ return value !== null && itemValue < value;
26
+ case "lte":
27
+ return value !== null && itemValue <= value;
28
+ case "gt":
29
+ return value !== null && itemValue > value;
30
+ case "gte":
31
+ return value !== null && itemValue >= value;
32
+ case "in":
33
+ return Array.isArray(value) ? value.includes(itemValue) : false;
34
+ case "contains":
35
+ return typeof itemValue === "string" && typeof value === "string" ? itemValue.includes(value) : false;
36
+ case "starts_with":
37
+ return typeof itemValue === "string" && typeof value === "string" ? itemValue.startsWith(value) : false;
38
+ case "ends_with":
39
+ return typeof itemValue === "string" && typeof value === "string" ? itemValue.endsWith(value) : false;
40
+ default:
41
+ throw new Error(`Unsupported operator: ${operator}`);
42
+ }
43
+ }
44
+ return data.filter((item) => {
45
+ let result = true;
46
+ for (let i = 0; i < where.length; i++) {
47
+ const condition = where[i];
48
+ const matches = evaluateCondition(item, condition);
49
+ if (i === 0) {
50
+ result = matches;
51
+ } else {
52
+ const connector = condition.connector || "AND";
53
+ if (connector === "AND") {
54
+ result = result && matches;
55
+ } else if (connector === "OR") {
56
+ result = result || matches;
57
+ } else {
58
+ throw new Error(`Unsupported connector: ${connector}`);
59
+ }
60
+ }
61
+ }
62
+ return result;
63
+ });
64
+ }
65
+ function sortListByField(data, sort) {
66
+ if (!sort) {
67
+ return data;
68
+ }
69
+ const { field, direction } = sort;
70
+ data.sort((a, b) => {
71
+ if (a === null || b === null) {
72
+ return 0;
73
+ }
74
+ if (typeof a[field] === "string" && typeof b[field] === "string") {
75
+ return direction === "asc" ? a[field].localeCompare(b[field]) : b[field].localeCompare(a[field]);
76
+ }
77
+ return direction === "asc" ? a[field] - b[field] : b[field] - a[field];
78
+ });
79
+ return data;
80
+ }
81
+ function paginateList(data, limit, offset) {
82
+ if (offset === void 0 && limit === void 0) {
83
+ return data;
84
+ }
85
+ if (limit === 0) {
86
+ return [];
87
+ }
88
+ let start = offset ?? 0;
89
+ if (start < 0) {
90
+ start = 0;
91
+ }
92
+ const end = limit ? start + limit : void 0;
93
+ return data.slice(start, end);
94
+ }
95
+ function isWhereByField(field, where) {
96
+ return where.field === field && where.operator === "eq" && where.connector === "AND";
97
+ }
98
+ function isWhereBySingleField(field, where) {
99
+ if (where === void 0 || where.length !== 1) {
100
+ return false;
101
+ }
102
+ const [cond] = where;
103
+ if (!cond) {
104
+ return false;
105
+ }
106
+ return isWhereByField(field, cond);
107
+ }
108
+ function containWhereByField(field, where) {
109
+ if (where === void 0) {
110
+ return false;
111
+ }
112
+ return where.some((cond) => isWhereByField(field, cond));
113
+ }
114
+ function extractWhereByField(field, where) {
115
+ if (where === void 0) {
116
+ return [void 0, []];
117
+ }
118
+ return [
119
+ where.find((cond) => isWhereByField(field, cond)),
120
+ where.filter((cond) => !isWhereByField(field, cond))
121
+ ];
122
+ }
123
+
124
+ // src/better-auth/database-adapter/repository/generic.ts
125
+ var JazzRepository = class {
126
+ constructor(databaseSchema, databaseRoot, worker, betterAuthSchema = {}, ensureSync = false) {
127
+ this.coValuesTracker = void 0;
128
+ this.databaseSchema = databaseSchema;
129
+ this.databaseRoot = databaseRoot;
130
+ this.worker = worker;
131
+ this.owner = databaseRoot.group;
132
+ this.betterAuthSchema = betterAuthSchema;
133
+ if (ensureSync)
134
+ this.coValuesTracker = worker.$jazz.raw.core.node.syncManager.trackDirtyCoValues();
135
+ }
136
+ ensureSync() {
137
+ if (!this.coValuesTracker)
138
+ throw new Error("Repository wasn't initialized with ensureSync option");
139
+ return Promise.all(
140
+ Array.from(
141
+ this.coValuesTracker.done(),
142
+ (id) => this.worker.$jazz.raw.core.node.syncManager.waitForSync(id)
143
+ )
144
+ );
145
+ }
146
+ async create(model, data, uniqueId) {
147
+ const schema = this.getSchema(model);
148
+ const resolved = await this.databaseRoot.$jazz.ensureLoaded({
149
+ resolve: {
150
+ tables: {
151
+ [model]: true
152
+ }
153
+ }
154
+ });
155
+ const list = resolved.tables?.[model];
156
+ if (!uniqueId) {
157
+ const node2 = schema.create(data, {
158
+ owner: list.$jazz.owner
159
+ });
160
+ list.$jazz.push(node2);
161
+ return node2;
162
+ }
163
+ const existingNode = await schema.loadUnique(
164
+ uniqueId,
165
+ list.$jazz.owner.$jazz.id,
166
+ {
167
+ loadAs: this.worker
168
+ }
169
+ );
170
+ if (existingNode && existingNode.$jazz?.raw.get("_deleted") !== true) {
171
+ throw new Error("Entity already exists");
172
+ }
173
+ const node = await schema.upsertUnique({
174
+ value: {
175
+ ...data,
176
+ _deleted: false
177
+ },
178
+ owner: list.$jazz.owner,
179
+ unique: uniqueId
180
+ });
181
+ if (!node) {
182
+ throw new Error("Unable to create entity");
183
+ }
184
+ list.$jazz.push(node);
185
+ return node;
186
+ }
187
+ async findOne(model, where) {
188
+ return this.findMany(model, where, 1).then((users) => users?.at(0) ?? null);
189
+ }
190
+ async findById(model, where) {
191
+ const id = where[0].value;
192
+ if (!id.startsWith("co_")) {
193
+ return null;
194
+ }
195
+ const node = await this.getSchema(model).load(id, { loadAs: this.worker });
196
+ if (!node) {
197
+ return null;
198
+ }
199
+ if (node.$jazz.raw.get("_deleted")) {
200
+ return null;
201
+ }
202
+ return node;
203
+ }
204
+ async findByUnique(model, where) {
205
+ const value = where[0].value;
206
+ const node = await this.getSchema(model).loadUnique(
207
+ value,
208
+ this.owner.$jazz.id,
209
+ {
210
+ loadAs: this.worker
211
+ }
212
+ );
213
+ if (!node) {
214
+ return null;
215
+ }
216
+ if (node.$jazz.raw.get("_deleted")) {
217
+ return null;
218
+ }
219
+ return node;
220
+ }
221
+ async findMany(model, where, limit, sortBy, offset) {
222
+ this.getSchema(model);
223
+ if (isWhereBySingleField("id", where)) {
224
+ return this.findById(model, where).then((node) => node ? [node] : []);
225
+ }
226
+ const resolvedRoot = await this.databaseRoot.$jazz.ensureLoaded({
227
+ resolve: {
228
+ tables: {
229
+ [model]: {
230
+ $each: true
231
+ }
232
+ }
233
+ }
234
+ });
235
+ const list = resolvedRoot.tables?.[model];
236
+ if (!list) {
237
+ return [];
238
+ }
239
+ return this.filterSortPaginateList(list, where, limit, sortBy, offset);
240
+ }
241
+ async update(model, where, update) {
242
+ const nodes = await this.findMany(model, where);
243
+ if (nodes.length === 0) {
244
+ return [];
245
+ }
246
+ for (const node of nodes) {
247
+ for (const [key, value] of Object.entries(
248
+ update
249
+ )) {
250
+ node.$jazz.set(key, value);
251
+ }
252
+ }
253
+ return nodes;
254
+ }
255
+ async deleteValue(model, where) {
256
+ const items = await this.findMany(model, where);
257
+ if (items.length === 0) {
258
+ return 0;
259
+ }
260
+ const resolved = await this.databaseRoot.$jazz.ensureLoaded({
261
+ resolve: {
262
+ tables: {
263
+ [model]: {
264
+ $each: true
265
+ }
266
+ }
267
+ }
268
+ });
269
+ if (!resolved) {
270
+ throw new Error("Unable to load values");
271
+ }
272
+ const list = resolved?.tables?.[model];
273
+ for (const toBeDeleted of items) {
274
+ const index = [...list.entries()].findIndex(
275
+ ([_, value]) => value && value.$jazz.id === toBeDeleted.$jazz.id
276
+ );
277
+ toBeDeleted.$jazz.set("_deleted", true);
278
+ if (index !== -1) {
279
+ list.$jazz.remove(index);
280
+ }
281
+ }
282
+ return items.length;
283
+ }
284
+ async count(model, where) {
285
+ return this.findMany(model, where).then((values) => values.length);
286
+ }
287
+ getSchema(model) {
288
+ const schema = this.databaseSchema.shape.tables.shape[model]?.element;
289
+ if (!schema) {
290
+ throw new Error(`Schema for model "${model}" not found`);
291
+ }
292
+ return schema;
293
+ }
294
+ filterSortPaginateList(list, where, limit, sortBy, offset) {
295
+ return [
296
+ list.filter(
297
+ (item) => item !== null && item.$jazz.raw.get("_deleted") !== true
298
+ )
299
+ ].map((list2) => filterListByWhere(list2, where)).map((list2) => sortListByField(list2, sortBy)).map((list2) => paginateList(list2, limit, offset)).at(0);
300
+ }
301
+ };
302
+
303
+ // src/better-auth/database-adapter/repository/user.ts
304
+ import { co, z } from "jazz-tools";
305
+ var EmailIndex = co.map({ user: z.string().nullable() });
306
+ var UserRepository = class extends JazzRepository {
307
+ /**
308
+ * Custom logic:
309
+ * - sessions are stored inside the user object
310
+ * - keep sync email index
311
+ */
312
+ async create(model, data, uniqueId) {
313
+ const SessionListSchema = this.databaseSchema.shape.tables.shape.session;
314
+ if (!SessionListSchema) {
315
+ throw new Error("Session list schema not found");
316
+ }
317
+ const userEmail = data[this.getEmailProperty()];
318
+ const emailIndex = await this.loadEmailIndex(userEmail);
319
+ if (emailIndex?.user) {
320
+ throw new Error("Email already exists");
321
+ }
322
+ const user = await super.create(model, data, uniqueId);
323
+ await this.updateEmailIndex(userEmail, user.$jazz.id);
324
+ user.$jazz.set(
325
+ "sessions",
326
+ co.list(SessionListSchema).create([], user.$jazz.owner)
327
+ );
328
+ return user;
329
+ }
330
+ /**
331
+ * Custom logic:
332
+ * - if the email is in the where clause, find by email
333
+ */
334
+ async findMany(model, where, limit, sortBy, offset) {
335
+ if (isWhereBySingleField("email", where)) {
336
+ return this.findByEmail(where[0].value);
337
+ }
338
+ return super.findMany(model, where, limit, sortBy, offset);
339
+ }
340
+ getEmailProperty() {
341
+ return this.betterAuthSchema.user?.fields.email?.fieldName || "email";
342
+ }
343
+ async findByEmail(email) {
344
+ const emailIndex = await this.loadEmailIndex(email);
345
+ const user = emailIndex?.user;
346
+ if (!user) {
347
+ return [];
348
+ }
349
+ return this.findById("user", [
350
+ { field: "id", operator: "eq", value: user, connector: "AND" }
351
+ ]).then((user2) => user2 ? [user2] : []);
352
+ }
353
+ /**
354
+ * Custom logic:
355
+ * - if the email is changed, update the email index
356
+ */
357
+ async update(model, where, update) {
358
+ const nodes = await this.findMany(model, where);
359
+ if (nodes.length === 0) {
360
+ return [];
361
+ }
362
+ const newEmail = update[this.getEmailProperty()];
363
+ for (const node of nodes) {
364
+ const oldEmail = node.$jazz.raw.get(this.getEmailProperty());
365
+ for (const [key, value] of Object.entries(
366
+ update
367
+ )) {
368
+ node.$jazz.set(key, value);
369
+ }
370
+ if (oldEmail !== newEmail && oldEmail !== void 0 && newEmail !== void 0) {
371
+ await this.updateEmailIndex(oldEmail, null);
372
+ await this.updateEmailIndex(newEmail, node.$jazz.id);
373
+ }
374
+ }
375
+ return nodes;
376
+ }
377
+ async deleteValue(model, where) {
378
+ const nodes = await this.findMany(model, where);
379
+ const deleted = await super.deleteValue(model, where);
380
+ for (const node of nodes) {
381
+ const email = node.$jazz.raw.get(this.getEmailProperty());
382
+ if (email) {
383
+ await this.updateEmailIndex(email, null);
384
+ }
385
+ }
386
+ return deleted;
387
+ }
388
+ async loadEmailIndex(email) {
389
+ const emailIndex = await EmailIndex.loadUnique(email, this.owner.$jazz.id, {
390
+ loadAs: this.worker
391
+ });
392
+ return emailIndex;
393
+ }
394
+ async updateEmailIndex(email, userId) {
395
+ await EmailIndex.upsertUnique({
396
+ value: {
397
+ user: userId
398
+ },
399
+ unique: email,
400
+ owner: this.owner
401
+ });
402
+ }
403
+ };
404
+
405
+ // src/better-auth/database-adapter/repository/session.ts
406
+ var SessionRepository = class extends JazzRepository {
407
+ constructor(databaseSchema, databaseRoot, worker, betterAuthSchema = {}, ensureSync = false) {
408
+ super(databaseSchema, databaseRoot, worker, betterAuthSchema, ensureSync);
409
+ this.userRepository = new UserRepository(
410
+ databaseSchema,
411
+ databaseRoot,
412
+ worker,
413
+ betterAuthSchema
414
+ );
415
+ }
416
+ /**
417
+ * Custom logic: sessions are stored inside the user object
418
+ */
419
+ async create(model, data, uniqueId) {
420
+ if (typeof data.token !== "string" || typeof data.userId !== "string") {
421
+ throw new Error("Token and userId are required for session creation");
422
+ }
423
+ const user = await this.userRepository.findById("user", [
424
+ {
425
+ field: "id",
426
+ operator: "eq",
427
+ value: data.userId,
428
+ connector: "AND"
429
+ }
430
+ ]);
431
+ if (!user) {
432
+ throw new Error("User not found");
433
+ }
434
+ const { sessions } = await user.$jazz.ensureLoaded({
435
+ resolve: {
436
+ sessions: true
437
+ }
438
+ });
439
+ const session = this.getSchema("session").create(data, {
440
+ unique: data.token,
441
+ owner: this.owner
442
+ });
443
+ sessions.$jazz.push(session);
444
+ return session;
445
+ }
446
+ /**
447
+ * Custom logic: sessions are stored inside the user object.
448
+ */
449
+ async findMany(model, where, limit, sortBy, offset) {
450
+ if (isWhereBySingleField("id", where)) {
451
+ return this.findById(model, where).then((node) => node ? [node] : []);
452
+ }
453
+ if (isWhereBySingleField("token", where)) {
454
+ return this.findByUnique(model, where).then(
455
+ (node) => node ? [node] : []
456
+ );
457
+ }
458
+ if (containWhereByField("userId", where)) {
459
+ const [userIdWhere, otherWhere] = extractWhereByField("userId", where);
460
+ const user = await this.userRepository.findById("user", [
461
+ {
462
+ field: "id",
463
+ operator: "eq",
464
+ value: userIdWhere.value,
465
+ connector: "AND"
466
+ }
467
+ ]);
468
+ if (!user) {
469
+ console.warn("Trying to find user's sessions, but user not found");
470
+ return [];
471
+ }
472
+ const { sessions } = await user.$jazz.ensureLoaded({
473
+ resolve: {
474
+ sessions: {
475
+ $each: true
476
+ }
477
+ }
478
+ });
479
+ return this.filterSortPaginateList(
480
+ sessions,
481
+ otherWhere,
482
+ limit,
483
+ sortBy,
484
+ offset
485
+ );
486
+ }
487
+ throw new Error(
488
+ "Unable to find session with where: " + JSON.stringify(where)
489
+ );
490
+ }
491
+ /**
492
+ * Custom logic: sessions are stored inside the user object.
493
+ */
494
+ async deleteValue(model, where) {
495
+ const items = await this.findMany(model, where);
496
+ if (items.length === 0) {
497
+ return 0;
498
+ }
499
+ const userId = items[0].userId;
500
+ return this.deleteSession(userId, items);
501
+ }
502
+ async deleteSession(userId, items) {
503
+ const user = await this.userRepository.findById("user", [
504
+ {
505
+ field: "id",
506
+ operator: "eq",
507
+ value: userId,
508
+ connector: "AND"
509
+ }
510
+ ]);
511
+ if (!user) {
512
+ throw new Error("User not found");
513
+ }
514
+ const { sessions } = await user.$jazz.ensureLoaded({
515
+ resolve: {
516
+ sessions: true
517
+ }
518
+ });
519
+ for (const toBeDeleted of items) {
520
+ const index = [...sessions.entries()].findIndex(
521
+ ([_, value]) => value && value.$jazz.id === toBeDeleted.$jazz.id
522
+ );
523
+ toBeDeleted.$jazz.set("_deleted", true);
524
+ if (index !== -1) {
525
+ sessions.$jazz.remove(index);
526
+ }
527
+ }
528
+ return items.length;
529
+ }
530
+ };
531
+
532
+ // src/better-auth/database-adapter/repository/verification.ts
533
+ var VerificationRepository = class extends JazzRepository {
534
+ /**
535
+ * Custom logic: property identifier is used as uniqueId
536
+ */
537
+ async create(model, data, uniqueId) {
538
+ return super.create(model, data, data["identifier"]);
539
+ }
540
+ /**
541
+ * Custom logic: property identifier is used as uniqueId
542
+ * If we look for identifier, we use findByUnique instead of findMany
543
+ */
544
+ async findMany(model, where, limit, sortBy, offset) {
545
+ if (isWhereBySingleField("identifier", where)) {
546
+ return this.findByUnique(model, where).then(
547
+ (node) => node ? [node] : []
548
+ );
549
+ }
550
+ return super.findMany(model, where, limit, sortBy, offset);
551
+ }
552
+ };
553
+
554
+ // src/better-auth/database-adapter/repository/account.ts
555
+ import { co as co2, z as z2 } from "jazz-tools";
556
+ var AccountIdIndex = co2.list(z2.string());
557
+ var AccountRepository = class extends JazzRepository {
558
+ /**
559
+ * Custom logic:
560
+ * - keep sync accountId index
561
+ */
562
+ async create(model, data, uniqueId) {
563
+ const account = await super.create(model, data, uniqueId);
564
+ await this.updateAccountIdIndex(
565
+ account[this.getAccountIdProperty()],
566
+ account.$jazz.id
567
+ );
568
+ return account;
569
+ }
570
+ /**
571
+ * Custom logic:
572
+ * - if the accountId is in the where clause, get the ids from the index
573
+ */
574
+ async findMany(model, where, limit, sortBy, offset) {
575
+ if (isWhereBySingleField(this.getAccountIdProperty(), where)) {
576
+ const accountIdIndex = await this.getAccountIdIndex(where[0].value);
577
+ const ids = accountIdIndex ?? [];
578
+ if (ids.length === 0) {
579
+ return [];
580
+ }
581
+ const results = await Promise.all(
582
+ ids.map(
583
+ (id) => super.findById(model, [
584
+ { field: "id", operator: "eq", value: id, connector: "AND" }
585
+ ])
586
+ )
587
+ );
588
+ return results.filter((value) => value !== null);
589
+ }
590
+ return super.findMany(model, where, limit, sortBy, offset);
591
+ }
592
+ async deleteValue(model, where) {
593
+ const nodes = await this.findMany(model, where);
594
+ const deleted = await super.deleteValue(model, where);
595
+ for (const node of nodes) {
596
+ const accountId = node.$jazz.raw.get(this.getAccountIdProperty());
597
+ if (accountId) {
598
+ await this.deleteAccountIdIndex(accountId, node.$jazz.id);
599
+ }
600
+ }
601
+ return deleted;
602
+ }
603
+ async getAccountIdIndex(accountId) {
604
+ const indexUnique = this.getAccountIdProperty() + "_" + accountId;
605
+ const accountIdIndex = await AccountIdIndex.loadUnique(
606
+ indexUnique,
607
+ this.owner.$jazz.id,
608
+ {
609
+ loadAs: this.worker
610
+ }
611
+ );
612
+ return accountIdIndex;
613
+ }
614
+ async updateAccountIdIndex(accountId, entityId) {
615
+ const accountIdIndex = await this.getAccountIdIndex(accountId);
616
+ const ids = accountIdIndex ?? [];
617
+ await AccountIdIndex.upsertUnique({
618
+ value: [...ids, entityId],
619
+ unique: this.getAccountIdProperty() + "_" + accountId,
620
+ owner: this.owner
621
+ });
622
+ }
623
+ async deleteAccountIdIndex(accountId, entityId) {
624
+ const accountIdIndex = await this.getAccountIdIndex(accountId);
625
+ const ids = accountIdIndex ?? [];
626
+ await AccountIdIndex.upsertUnique({
627
+ value: ids.filter((id) => id !== entityId),
628
+ unique: this.getAccountIdProperty() + "_" + accountId,
629
+ owner: this.owner
630
+ });
631
+ }
632
+ getAccountIdProperty() {
633
+ return this.betterAuthSchema.account?.fields.accountId?.fieldName || "accountId";
634
+ }
635
+ };
636
+
637
+ // src/better-auth/database-adapter/schema.ts
638
+ import { Group, co as co3, z as z3 } from "jazz-tools";
639
+ var DATABASE_ROOT_ID = "better-auth-root";
640
+ function createJazzSchema(schema) {
641
+ const tablesSchema = generateSchemaFromBetterAuthSchema(schema);
642
+ const DatabaseRoot = co3.map({
643
+ group: Group,
644
+ tables: co3.map(tablesSchema)
645
+ });
646
+ const WorkerAccount = co3.account({
647
+ profile: co3.profile(),
648
+ root: co3.map({})
649
+ }).withMigration(async (account) => {
650
+ const dbRoot = await DatabaseRoot.loadUnique(
651
+ DATABASE_ROOT_ID,
652
+ account.$jazz.id,
653
+ {
654
+ resolve: {
655
+ group: true,
656
+ tables: true
657
+ },
658
+ loadAs: account
659
+ }
660
+ );
661
+ if (!dbRoot) {
662
+ const adminGroup = Group.create({ owner: account });
663
+ await DatabaseRoot.upsertUnique({
664
+ value: {
665
+ group: adminGroup,
666
+ // create empty tables for each model
667
+ tables: co3.map(tablesSchema).create(
668
+ Object.fromEntries(
669
+ Object.entries(tablesSchema).map(([key, value]) => [
670
+ key,
671
+ value.create([], adminGroup)
672
+ ])
673
+ ),
674
+ adminGroup
675
+ )
676
+ },
677
+ unique: DATABASE_ROOT_ID,
678
+ owner: account
679
+ });
680
+ } else {
681
+ for (const [key, value] of Object.entries(
682
+ DatabaseRoot.shape.tables.shape
683
+ )) {
684
+ if (dbRoot.tables[key] === void 0) {
685
+ dbRoot.tables.$jazz.set(key, value.create([], dbRoot.group));
686
+ }
687
+ }
688
+ }
689
+ });
690
+ return {
691
+ WorkerAccount,
692
+ DatabaseRoot,
693
+ betterAuthSchema: schema,
694
+ async loadDatabase(account, options) {
695
+ if (options?.resolve === false || typeof options?.resolve === "object" && options?.resolve.group !== true) {
696
+ throw new Error("Group is required to load the database");
697
+ }
698
+ const db = await DatabaseRoot.loadUnique(
699
+ DATABASE_ROOT_ID,
700
+ account.$jazz.id,
701
+ {
702
+ resolve: {
703
+ group: true,
704
+ tables: true
705
+ },
706
+ loadAs: account,
707
+ ...options
708
+ }
709
+ );
710
+ if (!db) {
711
+ throw new Error("Database not found");
712
+ }
713
+ return db;
714
+ }
715
+ };
716
+ }
717
+ function generateSchemaFromBetterAuthSchema(schema) {
718
+ const tablesSchema = {};
719
+ for (const [key, value] of Object.entries(schema)) {
720
+ const modelShape = {
721
+ _deleted: z3.boolean()
722
+ };
723
+ for (const [fieldName, field] of Object.entries(value.fields)) {
724
+ modelShape[field.fieldName || fieldName] = convertFieldToCoValue(field);
725
+ }
726
+ const coMap = co3.map(modelShape);
727
+ tablesSchema[key] = co3.list(coMap);
728
+ }
729
+ if (tablesSchema["user"] && tablesSchema["session"]) {
730
+ tablesSchema["user"] = co3.list(
731
+ co3.map({
732
+ ...tablesSchema["user"].element.shape,
733
+ sessions: tablesSchema["session"]
734
+ }).withMigration((user) => {
735
+ if (user.sessions === void 0) {
736
+ user.$jazz.set(
737
+ "sessions",
738
+ tablesSchema["session"].create([], user.$jazz.owner)
739
+ );
740
+ }
741
+ })
742
+ );
743
+ } else {
744
+ throw new Error(
745
+ "Cannot find user and session tables, sessions will not be persisted"
746
+ );
747
+ }
748
+ return tablesSchema;
749
+ }
750
+ function convertFieldToCoValue(field) {
751
+ let zodType;
752
+ switch (field.type) {
753
+ case "string":
754
+ zodType = z3.string();
755
+ break;
756
+ case "number":
757
+ zodType = z3.number();
758
+ break;
759
+ case "boolean":
760
+ zodType = z3.boolean();
761
+ break;
762
+ case "date":
763
+ zodType = z3.date();
764
+ break;
765
+ default:
766
+ throw new Error(`Unsupported field type: ${field.type}`);
767
+ }
768
+ if (field.required === false) {
769
+ zodType = zodType.optional();
770
+ }
771
+ return zodType;
772
+ }
773
+ function tableItem2Record(tableItem) {
774
+ if (!tableItem) {
775
+ return tableItem;
776
+ }
777
+ const { $jazz, ...rest } = tableItem;
778
+ return {
779
+ ...rest,
780
+ id: $jazz.id
781
+ };
782
+ }
783
+
784
+ // src/better-auth/database-adapter/index.ts
785
+ var JazzBetterAuthDatabaseAdapter = (config) => createAdapter({
786
+ config: {
787
+ adapterId: "jazz-tools-adapter",
788
+ // A unique identifier for the adapter.
789
+ adapterName: "Jazz Tools Adapter",
790
+ // The name of the adapter.
791
+ debugLogs: config.debugLogs ?? false,
792
+ // Whether to enable debug logs.
793
+ supportsJSON: true,
794
+ // Whether the database supports JSON. (Default: false)
795
+ supportsDates: true,
796
+ // Whether the database supports dates. (Default: true)
797
+ supportsBooleans: true,
798
+ // Whether the database supports booleans. (Default: true)
799
+ supportsNumericIds: false,
800
+ // Whether the database supports auto-incrementing numeric IDs. (Default: true)
801
+ disableIdGeneration: true
802
+ },
803
+ adapter: ({ schema }) => {
804
+ const JazzSchema = createJazzSchema(schema);
805
+ let worker = void 0;
806
+ async function getWorker() {
807
+ if (worker) {
808
+ return worker;
809
+ }
810
+ const result = await startWorker({
811
+ AccountSchema: JazzSchema.WorkerAccount,
812
+ syncServer: config.syncServer,
813
+ accountID: config.accountID,
814
+ accountSecret: config.accountSecret,
815
+ skipInboxLoad: true,
816
+ asActiveAccount: false
817
+ });
818
+ worker = result.worker;
819
+ return worker;
820
+ }
821
+ async function initRepository(model, ensureSync = false) {
822
+ let Repository = void 0;
823
+ switch (model) {
824
+ case "user":
825
+ Repository = UserRepository;
826
+ break;
827
+ case "session":
828
+ Repository = SessionRepository;
829
+ break;
830
+ case "verification":
831
+ Repository = VerificationRepository;
832
+ break;
833
+ case "account":
834
+ Repository = AccountRepository;
835
+ break;
836
+ }
837
+ if (!Repository) {
838
+ Repository = JazzRepository;
839
+ }
840
+ const worker2 = await getWorker();
841
+ const database = await JazzSchema.loadDatabase(worker2);
842
+ const repository = new Repository(
843
+ JazzSchema.DatabaseRoot,
844
+ database,
845
+ worker2,
846
+ schema,
847
+ ensureSync
848
+ );
849
+ return repository;
850
+ }
851
+ return {
852
+ create: async ({ data, model, select }) => {
853
+ const repository = await initRepository(model, true);
854
+ const created = await repository.create(model, data);
855
+ await repository.ensureSync();
856
+ return tableItem2Record(created);
857
+ },
858
+ update: async ({ model, where, update }) => {
859
+ const repository = await initRepository(model, true);
860
+ const updated = await repository.update(
861
+ model,
862
+ where,
863
+ update
864
+ );
865
+ if (updated.length === 0) {
866
+ return null;
867
+ }
868
+ await repository.ensureSync();
869
+ return tableItem2Record(updated[0]);
870
+ },
871
+ updateMany: async ({ model, where, update }) => {
872
+ const repository = await initRepository(model, true);
873
+ const updated = await repository.update(model, where, update);
874
+ await repository.ensureSync();
875
+ return updated.length;
876
+ },
877
+ delete: async ({ model, where }) => {
878
+ const repository = await initRepository(model, true);
879
+ await repository.deleteValue(model, where);
880
+ await repository.ensureSync();
881
+ },
882
+ findOne: async ({ model, where }) => {
883
+ const repository = await initRepository(model);
884
+ const item = await repository.findOne(model, where);
885
+ return tableItem2Record(item);
886
+ },
887
+ findMany: async ({
888
+ model,
889
+ where,
890
+ limit,
891
+ sortBy,
892
+ offset
893
+ }) => {
894
+ const repository = await initRepository(model);
895
+ const items = await repository.findMany(
896
+ model,
897
+ where,
898
+ limit,
899
+ sortBy,
900
+ offset
901
+ );
902
+ return items.map(tableItem2Record);
903
+ },
904
+ deleteMany: async ({ model, where }) => {
905
+ const repository = await initRepository(model, true);
906
+ const deleted = await repository.deleteValue(model, where);
907
+ await repository.ensureSync();
908
+ return deleted;
909
+ },
910
+ count: async ({ model, where }) => {
911
+ const repository = await initRepository(model);
912
+ return repository.count(model, where);
913
+ }
914
+ };
915
+ }
916
+ });
917
+ export {
918
+ JazzBetterAuthDatabaseAdapter
919
+ };
920
+ //# sourceMappingURL=index.js.map