better-auth-firestore 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,14 +9,29 @@ const MAP_TO_FIRESTORE = {
9
9
  };
10
10
  const MAP_FROM_FIRESTORE = Object.fromEntries(Object.entries(MAP_TO_FIRESTORE).map(([k, v]) => [v, k]));
11
11
  const identity = (x) => x;
12
+ const DB_TO_CANONICAL_FIELD = {
13
+ user_id: "userId",
14
+ session_token: "sessionToken",
15
+ provider_account_id: "providerAccountId",
16
+ email_verified: "emailVerified",
17
+ };
18
+ function canonicalizeFieldName(field) {
19
+ return DB_TO_CANONICAL_FIELD[field] ?? field;
20
+ }
12
21
  function mapFieldsFactory(preferSnakeCase) {
13
22
  if (preferSnakeCase) {
14
23
  return {
15
- toDb: (field) => MAP_TO_FIRESTORE[field] ?? field,
24
+ toDb: (field) => {
25
+ const canonical = canonicalizeFieldName(field);
26
+ return MAP_TO_FIRESTORE[canonical] ?? canonical;
27
+ },
16
28
  fromDb: (field) => MAP_FROM_FIRESTORE[field] ?? field,
17
29
  };
18
30
  }
19
- return { toDb: identity, fromDb: identity };
31
+ return {
32
+ toDb: (field) => canonicalizeFieldName(field),
33
+ fromDb: (field) => MAP_FROM_FIRESTORE[field] ?? field,
34
+ };
20
35
  }
21
36
  /**
22
37
  * Firestore caps the `IN` operator at 30 comparison values. When a `where`
@@ -170,6 +185,36 @@ function applyOperator(query, field, operator, value) {
170
185
  return query.where(field, "==", value);
171
186
  }
172
187
  }
188
+ function isDocumentReferenceLike(value) {
189
+ return (typeof value === "object" &&
190
+ value !== null &&
191
+ "id" in value &&
192
+ typeof value.id === "string" &&
193
+ "path" in value &&
194
+ typeof value.path === "string");
195
+ }
196
+ function normalizeSessionWriteData(data) {
197
+ const { user_id, session_token, ...rest } = data;
198
+ const normalized = { ...rest };
199
+ const userIdValue = normalized.userId ?? user_id;
200
+ if (typeof userIdValue === "string") {
201
+ normalized.userId = userIdValue;
202
+ }
203
+ else if (isDocumentReferenceLike(userIdValue)) {
204
+ normalized.userId = userIdValue.id;
205
+ }
206
+ const sessionTokenValue = normalized.sessionToken ?? session_token;
207
+ if (typeof sessionTokenValue === "string") {
208
+ normalized.sessionToken = sessionTokenValue;
209
+ }
210
+ return normalized;
211
+ }
212
+ function normalizeWriteData(model, data) {
213
+ const normalizedModel = model.toLowerCase().replace(/s$/, "");
214
+ if (normalizedModel !== "session")
215
+ return data;
216
+ return normalizeSessionWriteData(data);
217
+ }
173
218
  export const firestoreAdapter = (config = {}) => {
174
219
  const db = resolveDb(config);
175
220
  const { namingStrategy = "default", collections: collectionsOverride = {}, debugLogs = false, } = (config && config.collection
@@ -193,8 +238,9 @@ export const firestoreAdapter = (config = {}) => {
193
238
  create: async ({ model, data }) => {
194
239
  const col = getCollectionRef(db, model, collections);
195
240
  let ref = col.doc();
241
+ const normalizedData = normalizeWriteData(model, data);
196
242
  const docData = {};
197
- for (const [k, v] of Object.entries(data)) {
243
+ for (const [k, v] of Object.entries(normalizedData)) {
198
244
  if (k === "id" && v) {
199
245
  ref = col.doc(v);
200
246
  continue;
@@ -202,7 +248,7 @@ export const firestoreAdapter = (config = {}) => {
202
248
  docData[mapper.toDb(k)] = v;
203
249
  }
204
250
  transaction.set(ref, docData);
205
- return { ...data, id: ref.id };
251
+ return { ...normalizedData, id: ref.id };
206
252
  },
207
253
  update: async ({ model, where, update }) => {
208
254
  const col = getCollectionRef(db, model, collections);
@@ -216,8 +262,9 @@ export const firestoreAdapter = (config = {}) => {
216
262
  }
217
263
  if (!doc)
218
264
  return null;
265
+ const normalizedUpdate = normalizeWriteData(model, update);
219
266
  const updateData = {};
220
- for (const [k, v] of Object.entries(update)) {
267
+ for (const [k, v] of Object.entries(normalizedUpdate)) {
221
268
  updateData[mapper.toDb(k)] = v;
222
269
  }
223
270
  transaction.update(doc.ref, updateData);
@@ -228,7 +275,7 @@ export const firestoreAdapter = (config = {}) => {
228
275
  result[mapper.fromDb(k)] = v;
229
276
  }
230
277
  }
231
- return { ...result, ...update };
278
+ return { ...result, ...normalizedUpdate };
232
279
  },
233
280
  findOne: async ({ model, where }) => {
234
281
  const col = getCollectionRef(db, model, collections);
@@ -261,8 +308,9 @@ export const firestoreAdapter = (config = {}) => {
261
308
  create: async ({ model, data }) => {
262
309
  const col = getCollectionRef(db, model, collections);
263
310
  let ref = col.doc();
311
+ const normalizedData = normalizeWriteData(model, data);
264
312
  const docData = {};
265
- for (const [k, v] of Object.entries(data)) {
313
+ for (const [k, v] of Object.entries(normalizedData)) {
266
314
  if (k === "id" && v) {
267
315
  ref = col.doc(v);
268
316
  continue;
@@ -300,14 +348,15 @@ export const firestoreAdapter = (config = {}) => {
300
348
  }
301
349
  if (debugLogs) {
302
350
  console.log(`[Firestore Adapter] CREATE ${model} - returning:`, {
303
- ...data,
351
+ ...normalizedData,
304
352
  ...result,
305
353
  });
306
354
  }
307
- return { ...data, ...result };
355
+ return { ...normalizedData, ...result };
308
356
  },
309
357
  update: async ({ model, where, update }) => {
310
358
  const col = getCollectionRef(db, model, collections);
359
+ const normalizedUpdate = normalizeWriteData(model, update);
311
360
  // Special case: if where clause is just "id eq value", use doc() instead of query
312
361
  if (where &&
313
362
  where.length === 1 &&
@@ -330,7 +379,7 @@ export const firestoreAdapter = (config = {}) => {
330
379
  return null;
331
380
  }
332
381
  const updateData = {};
333
- for (const [k, v] of Object.entries(update)) {
382
+ for (const [k, v] of Object.entries(normalizedUpdate)) {
334
383
  updateData[mapper.toDb(k)] = v;
335
384
  }
336
385
  if (debugLogs) {
@@ -373,7 +422,7 @@ export const firestoreAdapter = (config = {}) => {
373
422
  return null;
374
423
  }
375
424
  const updateData = {};
376
- for (const [k, v] of Object.entries(update)) {
425
+ for (const [k, v] of Object.entries(normalizedUpdate)) {
377
426
  updateData[mapper.toDb(k)] = v;
378
427
  }
379
428
  if (debugLogs) {
@@ -398,8 +447,9 @@ export const firestoreAdapter = (config = {}) => {
398
447
  const col = getCollectionRef(db, model, collections);
399
448
  let count = 0;
400
449
  const seenDocIds = new Set();
450
+ const normalizedUpdate = normalizeWriteData(model, update);
401
451
  const updateData = {};
402
- for (const [k, v] of Object.entries(update)) {
452
+ for (const [k, v] of Object.entries(normalizedUpdate)) {
403
453
  updateData[mapper.toDb(k)] = v;
404
454
  }
405
455
  for (const whereClause of getChunkedWhereClauses(where)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth-firestore",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "private": false,
5
5
  "description": "Firestore adapter for Better Auth (Firebase Admin SDK)",
6
6
  "author": "Slava Yultyyev <yultyyev@gmail.com>",