Conversation
|
Warning Rate limit exceeded@gentamura has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 16 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds transactional account provisioning (profile + default category), integrates provisioning into Supabase authentication, exposes DB category defaults, and makes DB schemaPath resolution file-URL-aware. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant ProvAuth as Provisioning\nSupabaseAuth
participant BaseAuth as Base\nSupabaseAuth
participant Provisioner as Account\nProvisioner
participant RLS as RLS\nClient
participant DB as Database
Client->>ProvAuth: authenticate(credentials)
ProvAuth->>BaseAuth: delegate authenticate()
BaseAuth-->>ProvAuth: authResult (token, userId, maybe email)
alt token is Supabase
ProvAuth->>Provisioner: provision({ userId, token, email? })
Provisioner->>RLS: createRlsClient(token)
RLS->>DB: begin transaction
Provisioner->>DB: upsert profile (id=userId, email)
Provisioner->>DB: conditional insert default category (createdBy=userId, kind=system)
DB-->>RLS: commit
Provisioner-->>ProvAuth: provision complete
else not Supabase token
ProvAuth-->>Client: authResult (no provisioning)
end
ProvAuth-->>Client: return authResult
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (10)
packages/db/src/constants/category.ts (1)
1-2: Consider a single object “defaultCategory” export for cohesion.Optional: export a frozen object (name/kind) to keep the pair from drifting and simplify wiring.
+export const DEFAULT_CATEGORY = Object.freeze({ + name: "Inbox", + kind: "system", +} as const); - -export const DEFAULT_CATEGORY_NAME = "Inbox"; -export const DEFAULT_CATEGORY_KIND = "system";packages/db/src/index.ts (1)
221-222: Nit: pass the URL object to fileURLToPath.Slightly more idiomatic and avoids subtle encoding surprises.
-const schemaUrl = new URL("./schema/index.js", import.meta.url); -export const schemaPath = fileURLToPath(schemaUrl.href); +const schemaUrl = new URL("./schema/index.js", import.meta.url); +export const schemaPath = fileURLToPath(schemaUrl);packages/auth/src/authentication/supabase.ts (4)
75-76: Add JWKS fetch resilience knobs (timeout/cache/custom fetch).To avoid request‑thread stalls on JWKS fetches and to control caching, expose and pass RemoteJWKSet options (e.g., timeoutDuration, cacheMaxAge, cooldown).
Example:
- const remoteJwkSet = createRemoteJWKSet(jwksUrl); + const remoteJwkSet = createRemoteJWKSet(jwksUrl, { + // consider wiring these via options + // timeoutDuration: 5000, + // cacheMaxAge: 60_000, + // cooldownDuration: 30_000, + // fetch: options.fetch ?? globalThis.fetch, + });Please confirm jose@v6.x support for these fields in your environment; wire them through SupabaseAuthenticationOptions if you agree.
122-132: Email extraction is fine; consider provider variations.Optional: also look for provider‑specific locations (e.g., user_metadata.email) if you expect third‑party identities without top‑level email.
134-171: Define and test provisioning failure policy (fail‑open vs fail‑closed).Right now, any provisioning error will reject authenticate(), coupling availability to DB. Clarify intent and encode it.
Possible pattern:
interface ProvisioningDependencies extends AccountProvisionerDependencies { readonly accountProvisioner?: AccountProvisioner; readonly authenticationProvider?: AuthenticationProvider; + readonly failOpenOnProvisioningError?: boolean; // default true } async function authenticate(...) { const result = await baseProvider.authenticate(context); if (!isSupabaseToken(result.user.token)) return result; - const email = extractEmailFromToken(result.user.token); - await accountProvisioner.provision({ userId: result.user.id, token: result.user.token, email }); + const email = extractEmailFromToken(result.user.token); + if (dependencies.failOpenOnProvisioningError !== false) { + try { + await accountProvisioner.provision({ userId: result.user.id, token: result.user.token, email }); + } catch { + // optional: log + } + } else { + await accountProvisioner.provision({ userId: result.user.id, token: result.user.token, email }); + } return result; }Also, ensure the underlying category creation is idempotent under concurrency (use a unique index and onConflictDoNothing on categories by (createdBy, kind)). Based on learnings.
173-179: Type guard is minimal; optionally tighten.If you need stricter detection, check for an issuer ending in “/auth/v1” or presence of a role claim before provisioning. Current check is acceptable.
packages/auth/src/account/provision-account.ts (4)
1-10: Fix Biome “Organize Imports”: sort specifiers.Apply this diff (keeps sources the same, sorts specifiers):
-import type { Database, RlsClient, RlsTransaction } from "@listee/db"; -import { - DEFAULT_CATEGORY_KIND, - DEFAULT_CATEGORY_NAME, - and, - categories, - createRlsClient, - eq, - profiles, -} from "@listee/db"; +import type { Database, RlsClient, RlsTransaction } from "@listee/db"; +import { + and, + categories, + createRlsClient, + DEFAULT_CATEGORY_KIND, + DEFAULT_CATEGORY_NAME, + eq, + profiles, +} from "@listee/db";As per coding guidelines.
34-38: Normalize email casing.Lowercase after trim to avoid case-sensitive duplicates with a unique email constraint.
Apply:
- const trimmed = email.trim(); + const trimmed = email.trim().toLowerCase();
72-80: Optional: make the profiles insert conflict target explicit.Not required, but clearer and slightly safer.
Apply:
await tx .insert(profiles) .values({ id: params.userId, email, }) - .onConflictDoNothing(); + .onConflictDoNothing({ target: profiles.id });
96-101: Optional: set profiles.defaultCategoryId when creating the default category.If product semantics expect a default category selected, update the profile after insertion. Requires capturing the inserted id; skip if existing already found.
I can draft this if you confirm the desired behavior.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
packages/auth/package.json(1 hunks)packages/auth/src/account/provision-account.ts(1 hunks)packages/auth/src/authentication/index.ts(1 hunks)packages/auth/src/authentication/supabase.test.ts(2 hunks)packages/auth/src/authentication/supabase.ts(2 hunks)packages/auth/src/index.ts(1 hunks)packages/db/src/constants/category.ts(1 hunks)packages/db/src/index.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
packages/*/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/*/src/**/*.{ts,tsx}: Avoid implicit any; TypeScript is run with strict enabled
Prefer type guards or the satisfies operator over as casts where appropriate
Prefer unknown for external inputs
Use PascalCase for types and enums
Use camelCase for variables and functions
Ensure source comments are written in English
Files:
packages/db/src/constants/category.tspackages/auth/src/authentication/index.tspackages/auth/src/index.tspackages/auth/src/authentication/supabase.test.tspackages/auth/src/account/provision-account.tspackages/db/src/index.tspackages/auth/src/authentication/supabase.ts
packages/*/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Reference shared dependencies via the "catalog:" protocol in package manifests
Files:
packages/auth/package.json
packages/auth/src/authentication/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place runtime-specific authentication adapters under packages/auth/src/authentication/ (e.g., header.ts, supabase.ts, shared utilities, errors.ts)
Files:
packages/auth/src/authentication/index.tspackages/auth/src/authentication/supabase.test.tspackages/auth/src/authentication/supabase.ts
packages/auth/src/authentication/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Extend Supabase JWT verification (createSupabaseAuthentication using .well-known/jwks.json) only via dedicated modules to keep caching and claim validation centralized
Files:
packages/auth/src/authentication/index.tspackages/auth/src/authentication/supabase.test.tspackages/auth/src/authentication/supabase.ts
packages/*/src/**/{*.test.ts,__tests__/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
packages/*/src/**/{*.test.ts,__tests__/**/*.ts}: Write test names and descriptions in English
Co-locate tests as *.test.ts or under tests/ using Bun’s test runner
Files:
packages/auth/src/authentication/supabase.test.ts
🧠 Learnings (2)
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.ts : Extend Supabase JWT verification (createSupabaseAuthentication using .well-known/jwks.json) only via dedicated modules to keep caching and claim validation centralized
Applied to files:
packages/auth/src/authentication/index.tspackages/auth/src/authentication/supabase.test.tspackages/auth/src/authentication/supabase.ts
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.{ts,tsx} : Place runtime-specific authentication adapters under packages/auth/src/authentication/ (e.g., header.ts, supabase.ts, shared utilities, errors.ts)
Applied to files:
packages/auth/src/authentication/index.ts
🧬 Code graph analysis (3)
packages/auth/src/authentication/supabase.test.ts (3)
packages/db/src/index.ts (1)
SupabaseToken(153-162)packages/types/src/authentication.ts (2)
AuthenticationProvider(24-26)HeaderToken(3-7)packages/auth/src/authentication/supabase.ts (1)
createProvisioningSupabaseAuthentication(134-171)
packages/auth/src/account/provision-account.ts (3)
packages/db/src/index.ts (7)
SupabaseToken(153-162)Database(130-130)RlsClient(172-174)createRlsClient(176-208)RlsTransaction(164-166)and(217-217)eq(217-217)packages/db/src/constants/category.ts (2)
DEFAULT_CATEGORY_NAME(1-1)DEFAULT_CATEGORY_KIND(2-2)packages/db/src/schema/index.ts (2)
profiles(22-53)categories(57-98)
packages/auth/src/authentication/supabase.ts (3)
packages/auth/src/account/provision-account.ts (3)
AccountProvisionerDependencies(23-28)AccountProvisioner(19-21)createAccountProvisioner(59-106)packages/types/src/authentication.ts (4)
AuthenticationProvider(24-26)AuthenticationContext(16-18)AuthenticationResult(20-22)AuthenticatedToken(9-9)packages/db/src/index.ts (1)
SupabaseToken(153-162)
🪛 GitHub Actions: CI
packages/auth/src/account/provision-account.ts
[error] 1-1: Biome: Organize Imports failed. The imports and exports are not sorted.
🔇 Additional comments (8)
packages/auth/src/authentication/index.ts (1)
3-6: Exports look good.Re-exporting the provisioning variant alongside the base provider keeps the public API tidy and discoverable.
If consumers rely on deep imports from ./supabase.js today, consider noting this addition in the changelog to steer them to ./authentication. Based on learnings.packages/auth/package.json (1)
17-20: Dependency addition makes sense; confirm runtime vs. types-only.Since provisioning invokes DB/RLS, keeping @listee/db as a runtime dependency is appropriate.
Please confirm there isn’t a second, divergent SupabaseToken type in @listee/types vs @listee/db to avoid type drift across packages.packages/auth/src/authentication/supabase.test.ts (3)
10-14: Import surface update is correct.Aligns tests with the new provisioning entry point; types are imported from @listee/types as expected.
89-133: Great: verifies provisioning after successful auth.Good isolation using a stub provider and capturing params.
Do we want auth to “fail-open” if provisioning throws? If yes, add a test that makes provision() reject and assert authenticate() still resolves. If no, assert the rejection. This locks behavior. Based on learnings.
171-208: Nice negative test for non‑Supabase tokens.Confirms the wrapper ignores opaque header tokens.
packages/db/src/index.ts (1)
218-219: Public export for category constants is good.Makes defaults available to provisioners without deep imports.
packages/auth/src/authentication/supabase.ts (1)
63-120: Auth core looks solid and centralized.Uses remote JWKS with issuer/audience/clock tolerance and role gating; returns normalized result. This aligns with keeping verification centralized. Based on learnings.
packages/auth/src/index.ts (1)
12-17: No issues found—the re-export is valid.The function
createProvisioningSupabaseAuthenticationis properly exported frompackages/auth/src/authentication/index.ts, eliminating the concern about a broken barrel. The re-export inpackages/auth/src/index.ts(lines 12-17) is functioning correctly.
| const existing = await tx | ||
| .select({ id: categories.id }) | ||
| .from(categories) | ||
| .where( | ||
| and( | ||
| eq(categories.createdBy, params.userId), | ||
| eq(categories.kind, defaultCategoryKind), | ||
| ), | ||
| ) | ||
| .limit(1); | ||
|
|
||
| if (existing.length > 0) { | ||
| return; | ||
| } | ||
|
|
||
| await tx.insert(categories).values({ | ||
| name: defaultCategoryName, | ||
| kind: defaultCategoryKind, | ||
| createdBy: params.userId, | ||
| updatedBy: params.userId, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
Make default-category creation idempotent and precise.
- Current existence check only filters by kind + createdBy; it can skip creating the Inbox if another system category exists.
- Select-then-insert is racy; concurrent logins can create duplicates.
Apply both changes:
- Include name in the existence check.
- Rely on ON CONFLICT DO NOTHING with a composite unique (created_by, kind, name).
Code changes:
- const existing = await tx
+ const existing = await tx
.select({ id: categories.id })
.from(categories)
.where(
and(
eq(categories.createdBy, params.userId),
eq(categories.kind, defaultCategoryKind),
+ eq(categories.name, defaultCategoryName),
),
)
.limit(1);
if (existing.length > 0) {
return;
}
- await tx.insert(categories).values({
- name: defaultCategoryName,
- kind: defaultCategoryKind,
- createdBy: params.userId,
- updatedBy: params.userId,
- });
+ await tx
+ .insert(categories)
+ .values({
+ name: defaultCategoryName,
+ kind: defaultCategoryKind,
+ createdBy: params.userId,
+ updatedBy: params.userId,
+ })
+ .onConflictDoNothing({
+ // requires a unique index on (created_by, kind, name)
+ target: [categories.createdBy, categories.kind, categories.name],
+ });Also add a composite unique index in the DB schema/migration:
- uniqueIndex("categories_owner_kind_name_unique").on(table.createdBy, table.kind, table.name)
Check if such a unique index already exists:
🏁 Script executed:
#!/bin/bash
rg -nP -C2 'unique(Index|index)?\(|uniqueIndex\(' packages/db/src/schemaLength of output: 332
I need to search for the categories table definition to check if the composite unique index exists.
🏁 Script executed:
#!/bin/bash
# Search for categories table definition and any indexes on it
fd -t f '*.ts' packages/db/src/schema -x grep -l "categories\|categories\s*=" {} \;Length of output: 283
🏁 Script executed:
#!/bin/bash
# Look for the categories table definition more broadly
rg -nP -C5 'table\s*\(\s*["\']categories' packages/db/src/schemaLength of output: 68
🏁 Script executed:
#!/bin/bash
# Also check for migrations that might define the index
fd -t f '*.ts' packages/db -x grep -l "created_by.*kind.*name\|uniqueIndex.*categories" {} \;Length of output: 283
🏁 Script executed:
#!/bin/bash
# View the actual code at the lines mentioned in the review
sed -n '81,101p' packages/auth/src/account/provision-account.tsLength of output: 526
🏁 Script executed:
#!/bin/bash
# Check if onConflictDoNothing is already being used
rg -nP 'onConflictDoNothing' packages/auth/src/account/provision-account.tsLength of output: 34
🏁 Script executed:
#!/bin/bash
# Look at categories schema file directly
find packages/db/src/schema -name '*.ts' -exec grep -l categories {} \;Length of output: 31
🏁 Script executed:
#!/bin/bash
# Try to find where categories table is defined
rg -nP -A10 'categories\s*=\s*table\(' packages/db/src/schemaLength of output: 0
🏁 Script executed:
#!/bin/bash
# Search for where categories might be imported or defined
rg -nP 'export.*categories|const categories' packages/db/src/schemaLength of output: 160
🏁 Script executed:
#!/bin/bash
# Check schema/index.ts for exports
cat packages/db/src/schema/index.tsLength of output: 4107
🏁 Script executed:
#!/bin/bash
# Look for Drizzle migrations or migration files
fd -t f '*.ts' packages/db/src -path '*/migrat*' -exec ls -la {} \;Length of output: 168
🏁 Script executed:
#!/bin/bash
# Broader search in db schema directory
ls -la packages/db/src/schema/Length of output: 168
🏁 Script executed:
#!/bin/bash
# Look for all table definitions
rg -nP '\btable\s*\(' packages/db/src/schema -A5Length of output: 0
🏁 Script executed:
#!/bin/bash
# Search for Drizzle indexes
rg -nP '\bindex\s*\(|\.index\s*\(' packages/db/src/schema -A2 -B2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Exhaustive search for categories references
rg -nP -C3 'categories' packages/db/src/schema/Length of output: 3909
🏁 Script executed:
#!/bin/bash
# Search for uniqueIndex specifically
rg -nP 'uniqueIndex' packages/db/src/ -C5Length of output: 0
🏁 Script executed:
#!/bin/bash
# List all schema files
find packages/db/src/schema -type f -name '*.ts' | sortLength of output: 31
🏁 Script executed:
#!/bin/bash
# Check the main index.ts file for table definitions
head -100 packages/db/src/schema/index.tsLength of output: 2511
🏁 Script executed:
#!/bin/bash
# Search for sqliteTable or similar Drizzle DSL
rg -nP 'sqliteTable|pgTable|mysqlTable' packages/db/src/schema -A20 | head -150Length of output: 5074
🏁 Script executed:
#!/bin/bash
# Simpler approach - just find all references to categories in schema dir
rg 'categories' packages/db/src/schema -lLength of output: 31
🏁 Script executed:
#!/bin/bash
# Search for category-related files
find packages/db/src -name '*categor*' -o -name '*categ*'Length of output: 37
🏁 Script executed:
#!/bin/bash
# Check if there's a separate categories schema file
fd -i categor packages/db/src/schemaLength of output: 0
🏁 Script executed:
#!/bin/bash
# Look for the complete schema structure
rg -nP -B5 -A15 'table\(' packages/db/src/schema/index.tsLength of output: 0
🏁 Script executed:
#!/bin/bash
# Search for table definition syntax across all schema files
find packages/db/src/schema -name '*.ts' -exec head -200 {} + | head -500Length of output: 4107
🏁 Script executed:
#!/bin/bash
# Try different keywords
rg -nP '(categories|category)' packages/db/src/schema/Length of output: 1177
🏁 Script executed:
#!/bin/bash
# Check for schema.ts file
cat packages/db/src/schema.ts 2>/dev/null || echo "File not found"Length of output: 14
🏁 Script executed:
#!/bin/bash
# Try the parent structure
ls -la packages/db/src/Length of output: 347
🏁 Script executed:
#!/bin/bash
# Look for drizzle config
fd drizzle packages/db/Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check if categories table is defined anywhere in auth package
rg -nP 'categories' packages/auth/src/account/provision-account.ts -B5 -A5Length of output: 952
🏁 Script executed:
#!/bin/bash
# Look more broadly for table definitions
rg -nP -A20 'export const categories|const categories' packages/db/Length of output: 1388
🏁 Script executed:
#!/bin/bash
# Try to find schema definitions with a simpler pattern
rg -nP 'categories' packages/db/src --type ts | head -20Length of output: 1018
🏁 Script executed:
#!/bin/bash
# Check all files in packages/db/src
find packages/db/src -type f -name '*.ts' | xargs grep -l categoriesLength of output: 31
🏁 Script executed:
#!/bin/bash
# Get file structure of packages
ls -la packages/Length of output: 318
Code changes required with corresponding DB schema constraint.
The review correctly identifies two issues:
-
The existence check (lines 85-87) only filters by
createdByandkind, omittingname. This allows other system categories to bypass the Inbox creation. -
The select-then-insert pattern is racy. Without
onConflictDoNothing()or a unique constraint, concurrent logins can create duplicates.
Both code and schema changes are necessary:
- Add
nameto the WHERE clause and use.onConflictDoNothing()with the composite target - Add the composite unique index
(created_by, kind, name)to the categories table schema in packages/db/src/schema/index.ts
The DB schema currently has no such index, so the code change alone is insufficient.
🤖 Prompt for AI Agents
In packages/auth/src/account/provision-account.ts around lines 81–101 the
existence check only filters by createdBy and kind (missing name) and uses a
select-then-insert pattern that is racy; update the WHERE clause to include name
(defaultCategoryName) and change the insert to use onConflictDoNothing()
targeting the composite key (created_by, kind, name) to avoid duplicate inserts
under concurrency; additionally, add a composite unique index on (created_by,
kind, name) in packages/db/src/schema/index.ts so the onConflict target exists
at the DB level and prevents duplicates even if concurrent inserts occur.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the commit diff to verify the fix
git show 832e50049192 --stat
echo "---"
git show 832e50049192
Unrecoverable error: Failed to clone repository
🏁 Script executed:
#!/bin/bash
# Use GitHub CLI to fetch the commit details
gh api repos/listee-dev/listee-libs/commits/832e50049192 --jq '.files[] | {filename: .filename, patch: .patch}'
Unrecoverable error: Stream setup permanently failed: Sandbox setup timed out after 180000ms
🏁 Script executed:
#!/bin/bash
# Fetch the current state of provision-account.ts from the PR branch
gh api repos/listee-dev/listee-libs/contents/packages/auth/src/account/provision-account.ts?ref=feature/add-account-provisioning --jq '.content' | base64 -d | tail -30
echo "---SEPARATOR---"
# Fetch the schema file to check for unique index
gh api repos/listee-dev/listee-libs/contents/packages/db/src/schema/index.ts?ref=feature/add-account-provisioning --jq '.content' | base64 -d | grep -A10 -B10 "uniqueIndex\|categories_system_name"
Unrecoverable error: Stream setup permanently failed: Sandbox setup timed out after 180000ms
@gentamura, thank you for fixing the race condition and idempotency issues! I appreciate you addressing both the existence check (adding name to the WHERE clause) and implementing the proper conflict handling with the composite unique index.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/auth/src/account/provision-account.ts(1 hunks)packages/db/src/schema/index.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/auth/src/account/provision-account.ts
🧰 Additional context used
📓 Path-based instructions (1)
packages/*/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/*/src/**/*.{ts,tsx}: Avoid implicit any; TypeScript is run with strict enabled
Prefer type guards or the satisfies operator over as casts where appropriate
Prefer unknown for external inputs
Use PascalCase for types and enums
Use camelCase for variables and functions
Ensure source comments are written in English
Files:
packages/db/src/schema/index.ts
🔇 Additional comments (1)
packages/db/src/schema/index.ts (1)
1-1: LGTM: Imports correctly added and used.The
eqanduniqueIndeximports are properly utilized in the partial unique index constraint on the categories table.Also applies to: 9-9
Summary by CodeRabbit
New Features
Database
Tests