Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .claude/agent-memory/review-review-issue-fixer/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Agent Memory Index

- [project_firestore_adapter.md](project_firestore_adapter.md) — Firestore adapter fix patterns and decisions for this PR
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Firestore adapter fix patterns
description: Fix patterns and design decisions applied during PR review for the @please-auth/firestore adapter
type: project
---

Key fix decisions applied to this adapter:

1. **Fail-closed defaults**: `matchesClientFilter` default changed to `return false`; `applyOperator` default changed to `return null` (forces client-side). Unknown operators should never silently pass records.

2. **Transaction-aware bulk operations**: `updateMany`/`deleteMany` now check the `transaction` closure variable and use `transaction.update()`/`transaction.delete()` per-doc instead of `db.batch()` when inside a transaction.

3. **Batch partial-failure error enrichment**: `batchDelete`/`batchUpdate` wrap each `batch.commit()` in try-catch and throw an error with `committedCount` and `totalCount` properties.

4. **No re-read after create**: `create()` returns data directly using `docToRecord(id, docData, mapper)` instead of doing a redundant `docRef.get()` after `docRef.set()`.

5. **Custom model name warning**: `getCollectionRef` default case logs a `console.warn` for unknown model names before the passthrough, since better-auth plugins may use custom collections.

**Why:** These fixes reduce Firestore read costs, ensure correctness inside transactions, and make the adapter fail-closed rather than fail-open on unknown operators.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Agent Memory Index

- [project_firestore_adapter.md](./project_firestore_adapter.md) — Firestore adapter for better-auth: architecture, security patterns, and key findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: project_firestore_adapter
description: Firestore adapter for better-auth — architecture, security review findings, and key patterns
type: project
---

This is a new Firestore adapter package for the better-auth library (branch: amondnet/minsu-lee/add-firestore-adatper).

Key files:
- packages/firestore/src/adapter.ts — main adapter logic (CRUD operations)
- packages/firestore/src/utils.ts — where clause processing, field mapping, batch ops
- packages/firestore/src/firestore.ts — Firebase app init helper
- packages/firestore/src/types.ts — config types, snake_case field maps

**Why:** Adding Firestore as a supported database backend for better-auth.

**How to apply:** Security review was performed 2026-03-24. Key findings:

1. IMPORTANT: `updateMany` and `deleteMany` have no result limit on the initial Firestore query (query.get() without .limit()), allowing unbounded reads that can be weaponized for DoS if `where` clauses don't match at the Firestore layer and fall through to client-side filtering. See adapter.ts lines 301-302 and 361-362.

2. IMPORTANT: `getCollectionRef` falls through to `db.collection(model)` for unknown model names, meaning any unvalidated model name from the adapter interface is used directly as a Firestore collection path. See utils.ts line 84.

3. IMPORTANT (design): `findOne` with client-side filters fetches up to 100 docs from Firestore when clientFilters are present (adapter.ts line 141). No upper bound validation means large fetch windows on complex queries.

4. No hardcoded secrets or credentials found. Credential handling delegates entirely to Firebase Admin SDK (Application Default Credentials or explicit AppOptions).

5. The `matchesClientFilter` default case returns `true` (utils.ts line 288), meaning unknown operators silently allow all records through — a logic bypass if new operators are added to CleanedWhere without updating the switch.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ Network Trash Folder
Temporary Items
.apdisk

### Please state
.please/state/

### Turborepo
.turbo

Expand Down
6 changes: 5 additions & 1 deletion .mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ run = "bunx --bun commitlint --edit"
description = "Set up git hooks"
run = """
bun install
mise generate git-pre-commit --hook commit-msg --task commit-msg --write
if [ -d .git ]; then
mise generate git-pre-commit --hook commit-msg --task commit-msg --write
else
echo "Skipping hook setup (worktree detected)"
fi
"""
6 changes: 0 additions & 6 deletions commitlint.config.js

This file was deleted.

Loading