Skip to content

Release/2.0.26#2427

Merged
mikib0 merged 173 commits into
mainfrom
release/2.0.26
May 16, 2026
Merged

Release/2.0.26#2427
mikib0 merged 173 commits into
mainfrom
release/2.0.26

Conversation

@mikib0
Copy link
Copy Markdown
Collaborator

@mikib0 mikib0 commented May 15, 2026

This pull request introduces several improvements and fixes across the codebase, focusing on dependency management, type safety, and minor UI enhancements. The most significant changes include enforcing strict dependency installation, aligning types with backend schemas, and improving error handling and user interface consistency.

Dependency Management and CI Improvements:

  • All GitHub Actions workflows now use bun install --frozen-lockfile to ensure deterministic dependency installation, and the cache: true option has been removed from the oven-sh/setup-bun step for consistency and reliability. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]
  • The .github/scripts/configure-deps.ts script now detects Cloudflare Pages builds and provides tailored error messages for missing tokens, improving developer experience in CI environments. [1] [2]

Type Safety and API Alignment:

  • In apps/admin/lib/api.ts, all AdminUser, AdminPack, and AdminCatalogItem types are now derived from their respective Zod schemas, ensuring consistency with backend validation. Related API methods have been updated to use string IDs for user operations, and new types for ETL failures are imported from schemas. [1] [2] [3] [4] [5]
  • The adminFetch helper function is introduced for consistent admin API calls.

UI and UX Improvements:

  • The Apple sign-in button now always displays the Apple logo for clarity in the authentication screen.
  • The geocode request in the location search screen now throws an explicit error if the network request fails, improving error handling.
  • In the Edit Catalog dialog, the handling of the weightUnit field is improved to avoid passing empty strings as values and ensure correct defaulting. [1] [2]

Other Notable Changes:

  • The number of code characters for the one-time password is increased from 5 to 6, aligning with typical OTP standards.
  • The queryKeys utility in the admin app now includes keys for OSM-related queries, supporting future enhancements.
  • All direct dependency versions in apps/admin/package.json are now referenced from the internal catalog: registry for improved dependency management.
  • Version bumps for apps/admin and apps/expo to 2.0.26. [1] [2]

Summary by CodeRabbit

Release Notes

  • New Features

    • Added password reset functionality with email OTP verification
    • Generated static Open Graph images for improved social media sharing on guides and landing pages
  • Bug Fixes

    • Improved HTTP response error handling
    • Made weight fields optional in catalog items
  • Chores

    • Version bumped to 2.0.26 across applications
    • Standardized dependency management with catalog versioning

Review Change Stack

mikib0 and others added 30 commits May 9, 2026 21:46
- GearInventoryScreen: replaces mock data with usePacks(); deduplicates
  items across packs, filters deleted, derives categories dynamically
- AIScreen: replaces MOCK_RESPONSES with DefaultChatTransport hitting
  /api/chat; uses sendMessage/status from @ai-sdk/react v3 API
- Adds @ai-sdk/react and ai to apps/web deps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
setup-bun v2 does not accept a 'cache' input; valid options are
'no-cache', 'bun-version', etc. Removes the invalid input from all
affected workflow files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
gear-inventory:
- Skip soft-deleted packs (pack.deleted) in item aggregation
- Use toGrams(weight, weightUnit) for correct unit conversion
- Capitalize category labels for display (first-aid → First Aid)

ai-screen:
- Memoize DefaultChatTransport to prevent per-render reinitialization
- Concatenate all text parts instead of only the first one
- Filter to user/assistant roles before rendering bubbles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Ensures lockfile drift is caught in CI. Lighthouse already had this;
adds it to checks, unit-tests, api-tests, migrations, sync-guides-r2,
and e2e-tests. Skips copilot-setup-steps (needs to write lockfile).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…hemas

- Replace legacy JWT auth in apps/trails with better-auth/react client
  (authClient.signIn/signUp/signOut/requestPasswordReset)
- Add apps/trails/lib/auth-client.ts with nextCookies() SSR plugin
- Rewrite AuthGate/VerifyEmail/useAuth to use Better Auth session
- Fix AdminUserItem/Pack/CatalogItem TypeBox schemas to match DB selects
  (remove fields not selected, add nullable fields that are selected)
- Align apps/admin/lib/api.ts interfaces with corrected TypeBox schemas
- Fix UserSchema.id: z.number() → z.string() (Better Auth uses UUID text pk)
- Fix mapToUser/applySessionUser to include emailVerified/createdAt/updatedAt
- Fix ItemReviews.tsx null guards for nullable review fields
- Fix web/lib/types.ts id fields: number → string throughout
- Fix web/lib/data.ts mock IDs to match string type
- Add queryKeys.osm used by admin trails dashboard page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove useLoginMutation/useRegisterMutation from packages/app (legacy
  JWT endpoints no longer exist; auth is handled by Better Auth)
- Add better-auth to apps/web dependencies
- Create apps/web/lib/auth-client.ts with nextCookies() SSR plugin
- Rewrite apps/web/app/auth/page.tsx to use authClient.signIn/signUp
- Update apps/web/lib/api.ts to get session token from Better Auth
- Replace clearTokens() in profile-screen with authClient.signOut()
- Fix adminFetch as Promise<T> cast (res.json() returns any, no cast needed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Package ships source .tsx files with type errors that skipLibCheck
can't suppress (only applies to .d.ts files). Add // @ts-nocheck to
the 3 affected files via bun patch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
feat(web): wire gear-inventory and ai-chat screens to real API
…clusion

All violations already fixed in development; only exclusion entry remains.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- convert(weight, from, to) → convert(weight, { from, to })
- displayWeight(grams, unit, precision?) → displayWeight(grams, unit) (precision always 2)
- Update all call sites in test files
chore(biome): enforce single-parameter functions
…P flow

- Add passwordResetService: generates OTP, stores in verification table (15-min TTL),
  sends via Resend, verifies with timing-safe compare, updates credential account
  password (falls back to users.passwordHash for legacy users)
- Add POST /api/password-reset/request and /verify routes
- Wire forgotPassword/resetPassword in useAuthActions to custom endpoints
- Update OTP screen from 5 to 6 characters (NIST SP 800-63B)
- Update ResetPasswordRequestSchema code length to 6
…h banner

getAccessToken now reads the expoClient cookie JSON from SecureStore directly
instead of calling authClient.getSession() on every API request, eliminating
concurrent network calls from Legend State polling intervals.

onNeedsReauth now verifies the session is genuinely gone before setting
needsReauthAtom, so transient 401s no longer trigger the sync-paused banner.
andrew-bierman and others added 7 commits May 14, 2026 17:09
…pment

chore: merge main into development
Better Auth prefixes session cookies with __Secure- on HTTPS (remote
dev/prod) but not on HTTP (local). getAccessToken was only looking up
the unprefixed key, returning null for every remote request and causing
a 401 on all authenticated endpoints.
fix(auth): check __Secure- prefixed cookie when reading session token
@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

cloudflare-workers-and-pages Bot commented May 15, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
packrat-admin 9c35486 Commit Preview URL

Branch Preview URL
May 15 2026, 05:10 PM

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@mikib0 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 24 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fe190470-8395-4c8b-b734-99672477d2cf

📥 Commits

Reviewing files that changed from the base of the PR and between 54dfd07 and 07d50ad.

📒 Files selected for processing (7)
  • apps/expo/features/auth/hooks/useAuthActions.ts
  • apps/trails/components/AuthGate.tsx
  • apps/trails/lib/apiClient.ts
  • apps/trails/lib/useAuth.tsx
  • apps/trails/package.json
  • apps/web/app/auth/page.tsx
  • apps/web/package.json

Walkthrough

Adds ETL chunking and progress accounting, password reset routes/services, Better Auth session refactors across apps, OG image generation with tests and metadata, CI hardening (frozen lockfile, Bun cache removal), units API breaking change, admin/client schema/type updates, and widespread package.json catalog/version updates.

Changes

Monorepo functional/infrastructure update

Layer / File(s) Summary
End-to-end implementation and wiring
.github/*, apps/**/*, packages/**/*, patches/*, package.json, biome.json, docs/plans/*
Implements ETL chunking/progress, password-reset API, auth/session refactors, OG image generation and tests, CI/install hardening, units API change and test updates, admin/client schema/type updates, and catalog/version/script changes across workspaces.

Sequence Diagram(s)

(skipped)

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

documentation, dependencies, api, ci/cd, mobile, database

Suggested reviewers

  • andrew-bierman
  • Isthisanmol
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/2.0.26

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 33

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (11)
.github/workflows/sync-guides-r2.yml (2)

29-34: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin third-party actions to full commit SHAs.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

🔒 Example pinning
-        uses: actions/checkout@v6
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

-        uses: oven-sh/setup-bun@v2
+        uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/sync-guides-r2.yml around lines 29 - 34, Replace mutable
action tags with immutable commit SHAs: update the two uses entries
"actions/checkout@v6" and "oven-sh/setup-bun@v2" to the corresponding full
commit SHA pins (e.g., actions/checkout@<full-sha> and
oven-sh/setup-bun@<full-sha>) so the workflow references exact commits; keep
existing inputs like "with: bun-version: latest" unchanged while swapping only
the action references.

1-17: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add a concurrency group to prevent redundant sync runs.

As per coding guidelines, use concurrency groups with cancel-in-progress: true to avoid redundant runs.

🔧 Suggested addition

Add after the on: section:

+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/sync-guides-r2.yml around lines 1 - 17, Add a concurrency
section to the GitHub Actions workflow (named "Sync Guides to R2 Bucket") right
after the on: block to prevent redundant runs: define concurrency with a
descriptive group (e.g., using the workflow name or branch/path context) and set
cancel-in-progress: true so in-progress sync jobs are canceled when a new run
starts; update the workflow's top-level keys (referencing name: "Sync Guides to
R2 Bucket", the on: block, and the concurrency key) accordingly.
.github/workflows/migrations.yml (2)

1-25: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Consider adding a concurrency group to prevent parallel migration runs.

This workflow runs database migrations but lacks a concurrency group. If multiple workflow runs trigger simultaneously (e.g., rapid pushes to main), migrations could run in parallel and cause database conflicts or race conditions.

🔧 Suggested addition

Add after the on: section:

+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: false

Note: Use cancel-in-progress: false for migrations to ensure in-flight migrations complete before starting new ones.

As per coding guidelines, use concurrency groups with cancel-in-progress: true to avoid redundant runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/migrations.yml around lines 1 - 25, The workflow "Database
Migrations" currently lacks a concurrency configuration which can allow parallel
runs; add a concurrency block (placed after the existing on: section) that
defines a group string incorporating the workflow name and environment input
(e.g., using github.ref or the workflow input environment) and set
cancel-in-progress: true per guidelines to prevent redundant concurrent
migration runs; reference the existing symbols "name: Database Migrations",
"workflow_dispatch" and the "environment" input when constructing the group.

36-41: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin third-party actions to full commit SHAs.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

🔒 Example pinning
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

-        uses: oven-sh/setup-bun@v2
+        uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/migrations.yml around lines 36 - 41, The workflow uses
mutable tags for third-party actions ("actions/checkout@v6" and
"oven-sh/setup-bun@v2"); replace these with the corresponding full commit SHAs
to pin the actions. Locate the two steps referencing actions/checkout and
oven-sh/setup-bun and update their "uses" values to the exact commit SHA (e.g.,
actions/checkout@<full-sha> and oven-sh/setup-bun@<full-sha>) fetched from each
repo's releases/commit history, then commit the updated workflow.
.github/workflows/e2e-tests.yml (1)

64-64: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin all third-party actions to full commit SHAs.

This workflow uses many third-party actions with mutable tags instead of pinned commit SHAs. Each unpinned action is a potential supply-chain attack vector.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

Actions to pin:

  • actions/checkout@v6
  • maxim-lobanov/setup-xcode@v1
  • oven-sh/setup-bun@v2
  • expo/expo-github-action@v8
  • actions/setup-java@v5
  • actions/cache@v4 (multiple instances)
  • actions/upload-artifact@v7 (multiple instances)
  • reactivecircus/android-emulator-runner@v2.37.0
🔒 Pin actions to commit SHAs

Find the commit SHA for each action version on the action's GitHub releases page, then update:

-      - uses: actions/checkout@v6
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

Repeat for all third-party actions in both the ios-e2e and android-e2e jobs.

Also applies to: 67-69, 72-74, 90-92, 96-99, 102-109, 112-116, 134-138, 250-254, 258-262, 328-328, 331-333, 336-341, 355-358, 361-368, 372-375, 387-391, 416-422, 426-436, 446-457, 481-485, 489-493

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e-tests.yml at line 64, The workflow uses mutable action
tags (e.g., actions/checkout@v6, maxim-lobanov/setup-xcode@v1,
oven-sh/setup-bun@v2, expo/expo-github-action@v8, actions/setup-java@v5,
actions/cache@v4, actions/upload-artifact@v7,
reactivecircus/android-emulator-runner@v2.37.0) and must be pinned to full
commit SHAs; for each referenced action (all occurrences listed in the comment)
replace the tag with the corresponding full commit SHA from that action's GitHub
repo (e.g., actions/checkout@<full-sha>), ensuring you update every instance
across both ios-e2e and android-e2e jobs and any repeated uses of actions/cache
and actions/upload-artifact so no third-party action uses a mutable tag.
.github/workflows/unit-tests.yml (1)

48-52: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin third-party actions to full commit SHAs.

All third-party actions use mutable tags instead of commit SHAs, exposing the workflow to supply-chain attacks.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

🔒 Example pinning
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

-      - uses: oven-sh/setup-bun@v2
+      - uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1

-        uses: davelosert/vitest-coverage-report-action@v2
+        uses: davelosert/vitest-coverage-report-action@[SHA] # v2.x.x

Find the commit SHA for each action on its GitHub releases page.

Also applies to: 64-70, 77-81, 93-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/unit-tests.yml around lines 48 - 52, The workflow is using
mutable tags for third-party actions (e.g., "uses: actions/checkout@v6" and
"uses: oven-sh/setup-bun@v2"); replace each mutable tag with the corresponding
full commit SHA for the action (e.g., "uses:
actions/checkout@<full-commit-sha>") so the workflow is pinned and
reproducible—locate the commit SHA on each action's GitHub repo/releases page
and update all occurrences (including the other uses blocks noted around lines
64-70, 77-81, 93-99) while preserving the existing inputs/keys (like with:
bun-version: latest).
.github/workflows/checks.yml (1)

26-27: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin third-party actions to full commit SHAs.

All third-party actions use mutable tags instead of commit SHAs, exposing the workflow to supply-chain attacks if upstream tags are moved or compromised.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

🔒 Example pinning
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

-      - uses: oven-sh/setup-bun@v2
+      - uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1

-        uses: stefanzweifel/git-auto-commit-action@v6
+        uses: stefanzweifel/git-auto-commit-action@90e3abea814c5315c597c97ee7ca5dd505f72efc # v6.0.0

Also applies to: 42-44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/checks.yml around lines 26 - 27, The workflow uses mutable
tags for third-party actions (actions/checkout@v6 and oven-sh/setup-bun@v2);
update those action references to their corresponding full commit SHAs instead
of version tags (and do the same for the other occurrences of these actions
later in the file), e.g., replace "actions/checkout@v6" and
"oven-sh/setup-bun@v2" with "actions/checkout@<full-commit-sha>" and
"oven-sh/setup-bun@<full-commit-sha>" respectively, ensuring you fetch the exact
commit SHAs from the actions' repositories and pin every occurrence
consistently.
.github/workflows/api-tests.yml (1)

28-28: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Pin third-party actions to full commit SHAs.

All third-party actions in this workflow use mutable tags (@v6, @v2, @v4) instead of pinned commit SHAs. If an upstream tag is moved or compromised, this workflow could execute malicious code.

As per coding guidelines, pin third-party actions to a full commit SHA (not a mutable tag) to prevent supply-chain attacks.

🔒 Example: How to pin actions to commit SHAs
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6.2.0

-      - uses: oven-sh/setup-bun@v2
+      - uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1

-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0

You can find commit SHAs on each action's GitHub releases page.

Also applies to: 30-32, 44-44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/api-tests.yml at line 28, The workflow uses mutable action
tags (e.g., "uses: actions/checkout@v6" and other "uses:" entries referenced at
30-32 and 44) which must be replaced with pinned full commit SHAs; find every
"uses: <owner>/<repo>@<tag>" entry (notably "actions/checkout@v6",
"actions/setup-node@v4", "actions/cache@v3" or similar) and replace the tag with
the corresponding full commit SHA from that action's GitHub repo releases/commit
history, committing the updated SHA strings so all third-party actions are
pinned to immutable commits.
apps/expo/app/(app)/trip/location-search.tsx (1)

41-48: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Replace direct fetch with the typed API client flow.

The non-OK guard is useful, but this screen still performs a direct network call in Expo code. Move this request
behind the app API client layer so request handling stays consistent and typed.

As per coding guidelines, "Never call fetch() directly — use the typed API client."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo/app/`(app)/trip/location-search.tsx around lines 41 - 48, Replace
the direct fetch(...) block that uses searchQuery and GOOGLE_MAPS_API_KEY with a
call to the app's typed API client (e.g., a new or existing method like
apiClient.getGeocode(searchQuery) or api.getGeocode) so the network request
lives behind the typed client; remove direct use of fetch and the
response/response.ok check and instead handle the typed client's success/error
shape (throw or return based on the client's error response), and if the API key
is currently embedded here move key usage to the server-side endpoint invoked by
the typed client so the Expo code never contains GOOGLE_MAPS_API_KEY.
apps/expo/features/auth/hooks/useAuthActions.ts (1)

95-114: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

signInWithGoogle can leave loading stuck and silently succeed without a user

setIsLoading(false) is only in catch, so successful runs keep loading true. Also, a response with no error and no data.user currently exits without failing.

Proposed fix
 const signInWithGoogle = async () => {
   setIsLoading(true);
   try {
@@
-      if (error) throw new Error(error.message ?? t('auth.failedToSignInWithGoogle'));
-      if (data && 'user' in data && data.user) applySession(data.user as Record<string, unknown>); // safe-cast: Better Auth user type omits additionalFields; role/preferredWeightUnit present at runtime
+      if (error || !data?.user) {
+        throw new Error(error?.message ?? t('auth.failedToSignInWithGoogle'));
+      }
+      applySession(data.user as Record<string, unknown>); // safe-cast: Better Auth user type omits additionalFields; role/preferredWeightUnit present at runtime
     } catch (error) {
-      setIsLoading(false);
-
       if (isErrorWithCode(error) && error.code === statusCodes.SIGN_IN_CANCELLED) {
         console.log(t('auth.userCancelledLogin'));
@@
       }
       throw error;
+    } finally {
+      setIsLoading(false);
     }
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo/features/auth/hooks/useAuthActions.ts` around lines 95 - 114, The
Google sign-in flow in signInWithGoogle leaves isLoading true on success and
silently returns when response has no error but also no data.user; move
setIsLoading(false) into a finally block or ensure it runs after both success
and failure, and add explicit handling after authClient.signIn.social: if
there's no error and either data is missing or 'user' is not in data or
data.user is falsy, throw a descriptive Error (e.g., from
t('auth.failedToSignInWithGoogle')) so applySession is only called when
data.user exists; update references to authClient.signIn.social, applySession,
setIsLoading and keep existing catch logic (isErrorWithCode/statusCodes)
unchanged.
apps/web/package.json (1)

2-4: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the missing version field to unblock release validation.

The release workflow is currently failing because this manifest has no version. Add it near Line 2 to match the release target (2.0.26).

Proposed fix
 {
   "name": "packrat-web-app",
+  "version": "2.0.26",
   "private": true,
   "scripts": {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/package.json` around lines 2 - 4, Add a top-level "version" field to
the package.json manifest so release validation passes: insert "version":
"2.0.26" at the top-level (beside "name": "packrat-web-app") in apps/web's
package.json so the package has the required version metadata for the release
workflow to succeed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/admin/lib/api.ts`:
- Around line 338-342: The helper function adminFetch (which calls adminFetcher
and builds URLs using API_BASE) bypasses the Treaty-typed API client; replace
usages of adminFetch/adminFetcher/API_BASE with the Treaty admin client paths
(e.g., adminClient.<resource>.<action>.<method>(...)) so ETL calls go through
the typed apiClient; update each call site to use the returned shape { data,
error, status } and add the standard checks (if (error || !data) ...) before
using data. Ensure you remove or stop using adminFetch and instead call the
appropriate adminClient route methods matching the original path and payload.

In `@apps/expo/features/auth/hooks/useAuthActions.ts`:
- Around line 190-211: The forgotPassword and resetPassword functions currently
call fetch directly; replace those fetch calls with the app's typed API client
methods for the password-reset endpoints so the requests and errors go through
the centralized API contract and error handling. Update forgotPassword and
resetPassword to call the corresponding typed client methods (the password-reset
request and verify methods) and propagate/translate errors using the client's
error shape instead of manually parsing res.json(); keep the same parameters
(email, token, newPassword) so callers are unchanged. Ensure headers/body are
handled by the typed client and remove the raw fetch logic in useAuthActions'
forgotPassword and resetPassword.

In `@apps/expo/features/catalog/components/ItemReviews.tsx`:
- Around line 47-50: The expansion state uses review.title as reviewKey in the
reviews.map callback (reviewKey, expandedReviews) which can collide for
duplicate titles; change reviewKey to a deterministic unique identifier (e.g.,
combine review.id if present or fallback to `${review.title ?? ''}-${i}` or
simply `${i}-${review.title ?? ''}`) and update all uses of reviewKey (where
expandedReviews is indexed and where keys are assigned in render) so each review
has a distinct key and expansion state is independent.

In `@apps/expo/lib/api/packrat.ts`:
- Around line 18-21: The parseSessionToken function currently calls
JSON.parse(cookieJson) without guarding against malformed input; wrap the
JSON.parse call in a try/catch inside parseSessionToken and handle parse errors
by returning null (or logging) so the function does not throw; after successful
parse, pass the parsed value into fromZod(CookieStoreSchema) as before and
continue returning null if validation fails. Ensure you reference
parseSessionToken, JSON.parse, fromZod, and CookieStoreSchema when making the
change.
- Around line 41-46: Wrap the await authClient.getSession() call inside
onNeedsReauth in a try/catch to avoid propagating thrown errors; if getSession
throws, catch the error, log it (or use the app logger) and then call
store.set(needsReauthAtom, true) to ensure no unhandled rejection and the UI is
informed of reauth required; reference symbols: onNeedsReauth,
authClient.getSession, needsReauthAtom, store.set.

In `@apps/trails/lib/apiClient.ts`:
- Around line 17-20: Update getAccessToken to check the authClient.getSession()
response before dereferencing session: destructure both data and error from
authClient.getSession(), return null if error or !data, then safely return
data.session?.token ?? null; this change affects the getAccessToken async
function and ensures you don't access data.session when the call failed.

In `@apps/trails/lib/auth.ts`:
- Line 42: Update the user schema id from number to string by changing the z
schema for id to z.string() (the User/UserInfo schema where id: z.number() is
currently defined), then update the UserInfo type/any related typings so
UserInfo.id is a string; modify getUser() to detect and migrate legacy
localStorage `user` entries with numeric id (coerce number -> string) to avoid
returning null and immediate logout, and sweep code that reads UserInfo.id
(components, auth helpers) to treat it as a string (replace numeric
comparisons/uses with string-safe logic).

In `@apps/web/components/screens/ai-screen.tsx`:
- Around line 18-39: The chat transport is reading auth from
Cookies.get('access_token') which diverges from the app's centralized auth;
update the DefaultChatTransport instantiation in AIScreen so its headers are
derived from the same authClient/apiClient flow used elsewhere: replace the
current headers: () => ({ Authorization: `Bearer ${Cookies.get('access_token')
?? ''}` }) with a function that calls authClient.getSession() (or uses apiClient
to fetch a session) and returns Authorization: `Bearer ${session?.access_token
?? ''}` (handle async if DefaultChatTransport accepts a promise); ensure
DefaultChatTransport still uses API_BASE and keep the other options unchanged.

In `@apps/web/lib/api.ts`:
- Around line 5-6: The apiClient currently uses webEnv.NEXT_PUBLIC_API_URL which
bypasses the CF Worker proxy; update the createApiClient call (symbol:
apiClient) to use a same-origin or relative base URL instead of
webEnv.NEXT_PUBLIC_API_URL (set baseUrl to '/' or undefined so it uses the app
origin) to ensure requests go through the CF Worker proxy for rate limiting and
cookie-scoped auth.

In `@apps/web/lib/auth-client.ts`:
- Around line 7-10: The auth client is using a full absolute baseURL
(webEnv.NEXT_PUBLIC_API_URL) which scopes cookies to the API origin and breaks
nextCookies(); update createAuthClient usage for authClient to use a same-origin
relative path (e.g., "/api/auth" or just "/api") or omit the origin so cookies
remain scoped to the web app; make the same change for apiClient in
apps/web/lib/api.ts (adjust their baseURL values and keep nextCookies() plugin
intact).

In `@docs/plans/2026-05-13-chore-enroll-catalog-candidates-plan.md`:
- Around line 29-36: The markdown fenced code blocks in the steps that show the
JSON snippets are missing surrounding blank lines (MD031); edit the two blocks
that start with "```json" and contain the lines with "\"package-name\":
\"^x.y.z\"" and "\"package-name\": \"catalog:\"" so that there is an empty line
immediately before each opening fence and an empty line immediately after each
closing fence (i.e., add a blank line between the preceding paragraph/list item
and the ```json fence and a blank line after the ``` fence) to satisfy
markdownlint.

In `@package.json`:
- Line 55: The package.json has a mismatch between the dependency entry
"@packrat-ai/nativewindui": "2.0.3-2" and the patchedDependencies key
"@packrat-ai/nativewindui@2.0.3"; update them to match exactly by either
changing the dependency to "2.0.3" or changing the patchedDependencies key to
"@packrat-ai/nativewindui@2.0.3-2" so pnpm will apply the patch; ensure you
update the string in the package.json entries for both patchedDependencies and
dependencies/devDependencies where the package appears.

In `@packages/api/drizzle/0037_nullable_catalog_weight.sql`:
- Around line 1-5: The repository contains duplicate migrations that drop NOT
NULL on catalog_items.weight/weight_unit (see ALTER TABLE "catalog_items" ALTER
COLUMN "weight" DROP NOT NULL and ALTER COLUMN "weight_unit" DROP NOT NULL) in a
0037_* file; delete all 0037_* migration files that duplicate this change so
only the 0047_cute_bloodscream migration remains in the migration journal,
update any references to the 0037 filenames, and re-run your migration
validation/bootstrap (or migration linter) to confirm the schema changes are
tracked only by 0047_cute_bloodscream.

In `@packages/api/src/index.ts`:
- Line 37: The current CORS config allows credentialed requests for any
*.workers.dev origin (the regex /^https?:\/\/[\w-]+\.workers\.dev$/) which is
unsafe; update the CORS policy to either remove credentials: true for wildcard
worker origins or replace the broad regex with a strict allowlist of exact
origins, and ensure any route that requires auth uses the authPlugin macro
(isAuthenticated: true) and includes explicit role/ownership checks where needed
(verify handlers/middlewares that call authPlugin or check roles/owners). Locate
the CORS setup and the routes that expect credentials, change credentials to
false for wildcard patterns or narrow the origin matcher to specific hostnames,
and audit routes using protected resources to add isAuthenticated: true and
appropriate role/ownership validation.

In `@packages/api/src/routes/admin/analytics/catalog.ts`:
- Around line 419-447: The current retry flow reads etlJobs and then
unconditionally inserts a new running job, causing a TOCTOU race; replace this
with an atomic conditional update or mark to prevent duplicates: perform an
UPDATE on etlJobs (e.g., set status='retrying' and/or set retriedAt/retryJobId)
WHERE id = params.jobId AND status = 'failed' and use RETURNING to get the
updated row (instead of the current select/insert pattern), then only create the
new job (newJobId/objectKey/insert into etlJobs) and queue if the UPDATE
returned a row; alternatively, add and check a retriedAt or retryJobId column on
the original and reject the retry when that field is already set.
- Around line 277-301: The SQL extraction of err->>'field' and err->>'reason'
can produce NULLs, but the code and EtlErrorRowSchema expect non-null strings;
update the query that uses jsonb_array_elements(${invalidItemLogs.errors}) (and
the similar query at the other occurrence) to either FILTER out NULLs (e.g.,
WHERE err->>'field' IS NOT NULL AND err->>'reason' IS NOT NULL) or COALESCE
those values to a sentinel string so the returned rows conform to the typed
shape; adjust the SELECT/WHERE in the sql block that populates rows (and any
mapping that uses r.field/r.reason) so the result matches { field: string;
reason: string; count: number } and aligns with EtlErrorRowSchema.
- Around line 413-470: The retry endpoint enqueues the original objectKey as a
single chunk and thus loses the byte-range splitting used in
routes/catalog/index.ts; update the handler in the POST '/etl/:jobId/retry'
route (the code that builds chunks and calls queueCatalogETL) to reuse the same
chunking logic: perform an R2 head/metadata lookup (R2BucketService.head or the
helper used in routes/catalog/index.ts), compute byte-range sub-chunks for
objects >20MB the same way the existing splitting code does, and pass those
chunks (with range fields) into queueCatalogETL instead of a single { objectKey
} chunk; alternatively extract the splitting helper from routes/catalog/index.ts
into a shared function and call it from this retry handler so queued chunks
match the original behavior.

In `@packages/api/src/routes/admin/index.ts`:
- Around line 122-132: The origin allowlist currently returns true for any
origin ending with '.workers.dev' inside the origin: (request) => { ... }
function, which is too permissive when credentials: true; replace that broad
check with a strict match against a fixed set of allowed worker subdomains
(e.g., create an allowedWorkerOrigins Set or array and check
allowedWorkerOrigins.has(origin)) or a tightly-scoped regex for only the
specific preview prefixes you own, and ensure the credentials: true behavior is
only applied when origin exactly matches one of those allowed entries; update
the origin check in this function (and remove the generic
origin.endsWith('.workers.dev') branch) so only explicitly whitelisted worker
URLs are accepted.

In `@packages/api/src/routes/catalog/index.ts`:
- Around line 186-200: The loop serially calls r2.head for each item in chunks,
causing unnecessary latency; change it to run all HEADs in parallel by mapping
chunks to r2.head promises (e.g., use Promise.all on chunks.map) and then
iterate the resulting metas to populate queueChunks with the same logic (push
{objectKey} when meta is falsy or size<=CHUNK_BYTES, otherwise compute n and
push segments with byteStart/byteEnd using CHUNK_BYTES); reference the
variables/functions: chunks, r2.head, CHUNK_BYTES, queueChunks, byteStart,
byteEnd.
- Around line 186-200: The loop that calls r2.head(objectKey) must treat a null
meta as a hard failure instead of enqueueing the objectKey: after const meta =
await r2.head(objectKey) add a null check (meta === null) and abort the
operation (e.g., throw an error or return a 404 response) so the code does not
push the objectKey into queueChunks; only when meta is non-null proceed to the
existing size check and chunking logic. Ensure the handler updates/propagates
the error so the ETL job is not left marked as running.

In `@packages/api/src/routes/passwordReset.ts`:
- Around line 27-47: Add per-IP and per-email rate limiting and failure lockout
to the '/verify' POST handler that calls verifyOtpAndResetPassword: use the same
rate limiter config as env.TOKEN_RATE_LIMITER (key on request header
'cf-connecting-ip' and on body.email) and increment an attempt counter that
invalidates the OTP after N failed attempts, or temporarily blocks further
attempts for that key; adjust verifyOtpAndResetPassword (or wrap it) to
atomically track failures and invalidate the OTP on threshold. Also stop
returning raw error.message to clients—catch errors, log the full error
server-side, and return a user-safe generic message (e.g., "Password reset
failed") via the existing status(400) response. Ensure
ResetPasswordRequestSchema remains applied and the rate limiter is applied
before calling verifyOtpAndResetPassword.
- Around line 10-25: The /request handler calls requestPasswordReset(body.email)
without error handling which can leak account existence via different HTTP
responses; wrap the await requestPasswordReset(...) in a try/catch inside the
POST handler for '/request', catch any thrown error, log it internally (e.g.,
using the existing logger or console.error) and do not rethrow, and always
return the same { success: true, message: 'If an account exists, a reset code
has been sent.' } response so the endpoint never reveals whether the email
exists.

In `@packages/api/src/services/etl/processCatalogEtl.ts`:
- Around line 100-108: The partial-row skip branch in processCatalogEtl.ts (the
skipPartialRow block using text.indexOf('\n') and text.slice(nl + 1)) can hang
if the input uses old-Mac '\r' line endings; adjust the logic inside that block
(referencing skipPartialRow, text.indexOf, text.slice) to look for '\n' first
and if not found fall back to locating '\r' (or any of '\r\n' sequences) and
advance past whichever terminator is found so the buffer always progresses; also
add a brief comment or doc note near this code indicating the assumption about
allowed line endings (LF/CRLF) so maintainers know why '\r' is handled as a
fallback.
- Around line 50-58: The injectedHeader extraction can silently truncate when
the header line exceeds 4096 bytes: in the byteStart > 0 branch (symbols:
injectedHeader, r2Service.get, headerSlice.text(), byteStart) detect whether the
fetched headerText contains a newline; if not, either extend the range/read more
bytes (looping/fetching additional ranges until a '\n' is found) or throw a
clear error indicating the header window was too small for objectKey so the
chunk is rejected; ensure the final injectedHeader is the full header line up to
the first '\n' (or fail fast when not available).
- Around line 89-117: The producer IIFE that reads from
streamToText(r2Object.body) must be awaited and its errors propagated into the
CSV parser so they don't become unhandled rejections and leave the consumer
waiting; assign the IIFE to a variable (e.g., producer), add a .catch that
forwards the error into parser (e.g., parser.emit or parser.destroy with the
error), and after the consumer loop over "for await (const record of parser)"
await the producer so any producer-side exception is observed by the outer
try/catch; ensure parser.end() still runs in normal flow and errors from
parser.write(...) are also forwarded into parser for proper failure handling.

In `@packages/api/src/services/passwordResetService.ts`:
- Around line 17-38: The delete-then-insert in requestPasswordReset and the
update-then-delete in verifyOtpAndResetPassword are not atomic and can leave
inconsistent state if interrupted; wrap each multi-step sequence in a single
db.transaction(...) so the delete+insert (in requestPasswordReset) and the
update+delete (in verifyOtpAndResetPassword) run as one atomic unit, using the
transaction-scoped DB handle for the subsequent queries (replace direct
createDb() usages inside those flows with the transaction client) and ensure
errors roll back the transaction.
- Around line 27-35: The verification code is stored in plaintext and there is
no attempt limit; update the create-and-verify flow in passwordResetService.ts
to (1) hash the OTP before storing (e.g., use a strong one-way KDF like
bcrypt/argon2/scrypt with a per-row salt) and store hashedValue (rename from
value) plus salt if needed and initialize failedAttempts=0 on the verification
record created in the block that inserts into the verification table (id,
identifier, ...); and (2) add and enforce a maxAttempts counter on each
verification row (failedAttempts column) so that on each failed check you
increment failedAttempts and invalidate/delete the row (or mark it) when it
reaches N (e.g., 5), and on verify compare the user-supplied code by hashing it
the same way and using timing-safe comparison (instead of comparing plaintext),
deleting the record on success. Ensure fields and logic around
verification.identifier, verification.expiresAt and the insert/delete flows are
updated to use hashedValue and failedAttempts so brute-force and DB-leak risks
are mitigated.
- Around line 60-61: In verifyOtpAndResetPassword, avoid leaking account
existence by replacing the specific throw new Error('User not found') after
db.query.users.findFirst(...) with the same generic error used earlier (e.g.,
'Invalid or expired reset code' or a shared constant) so both
requestPasswordReset and verifyOtpAndResetPassword return the identical generic
message; update the error text thrown in verifyOtpAndResetPassword (around the
users.email lookup) to match the existing generic message used for bad OTPs.
- Around line 12-14: The generateOtp function currently uses Math.random() which
is not cryptographically secure; replace it with a CSPRNG approach (e.g., using
crypto.getRandomValues on Cloudflare Workers or
crypto.randomInt/crypto.randomBytes on Node) to produce OTP_LENGTH digits:
allocate a byte buffer, fill with crypto.getRandomValues, and map bytes to
digits using rejection sampling to avoid modulo bias, returning a string of
length OTP_LENGTH; update the generateOtp implementation (and any tests) to use
this secure method instead of Math.random().
- Around line 63-82: After updating the password (after the account/users update
and before deleting the verification row), revoke all active sessions for the
user by deleting from the session table: import the session schema (session)
from `@packrat/api/db/schema` and call db.delete(session).where(eq(session.userId,
user.id)) so all Better Auth sessions for user.id are removed; alternatively,
call the Better Auth session-revocation API at that same point if preferred.

In `@packages/api/test/etl.test.ts`:
- Around line 52-68: The helpers insertJob and getJob currently call
createDbClient({} as any) which bypasses type safety; update these helpers to
pass a properly typed minimal env or test client instead of using any — either
change the argument to use `unknown` or define a small TestEnv type matching
createDbClient's parameter and construct a typed empty/minimal object, or reuse
an existing pre-configured test DB client (e.g., a shared test pool) and call
createDbClient with that; ensure references to createDbClient in both insertJob
and getJob are updated so no `as any` casts remain.
- Around line 32-48: The mocks in mockR2WithCsv and mockR2WithNull use `as any`,
removing type safety; replace those casts with a properly typed mock that
conforms to the R2BucketService interface (e.g., return a
Partial<R2BucketService> or a Mocked<R2BucketService> implementation) so the
object with get: vi.fn().mockResolvedValue(...) matches the expected service
type; update the mockImplementationOnce return type to a typed shape (or cast
via `as unknown as R2BucketService` if unavoidable) and ensure the get method
signature matches the real R2BucketService.get to restore compile-time checks.
- Around line 197-228: Add an explicit module reset before the dynamic import to
ensure test isolation: call vi.resetModules() immediately before importing
generateManyEmbeddings in the test so the import returns a fresh module (then
mock generateManyEmbeddings as you already do); this change affects the test
that calls processValidItemsBatch and references generateManyEmbeddings (and
prevents the cached global mock from setup.ts from carrying state into this
test).

---

Outside diff comments:
In @.github/workflows/api-tests.yml:
- Line 28: The workflow uses mutable action tags (e.g., "uses:
actions/checkout@v6" and other "uses:" entries referenced at 30-32 and 44) which
must be replaced with pinned full commit SHAs; find every "uses:
<owner>/<repo>@<tag>" entry (notably "actions/checkout@v6",
"actions/setup-node@v4", "actions/cache@v3" or similar) and replace the tag with
the corresponding full commit SHA from that action's GitHub repo releases/commit
history, committing the updated SHA strings so all third-party actions are
pinned to immutable commits.

In @.github/workflows/checks.yml:
- Around line 26-27: The workflow uses mutable tags for third-party actions
(actions/checkout@v6 and oven-sh/setup-bun@v2); update those action references
to their corresponding full commit SHAs instead of version tags (and do the same
for the other occurrences of these actions later in the file), e.g., replace
"actions/checkout@v6" and "oven-sh/setup-bun@v2" with
"actions/checkout@<full-commit-sha>" and "oven-sh/setup-bun@<full-commit-sha>"
respectively, ensuring you fetch the exact commit SHAs from the actions'
repositories and pin every occurrence consistently.

In @.github/workflows/e2e-tests.yml:
- Line 64: The workflow uses mutable action tags (e.g., actions/checkout@v6,
maxim-lobanov/setup-xcode@v1, oven-sh/setup-bun@v2, expo/expo-github-action@v8,
actions/setup-java@v5, actions/cache@v4, actions/upload-artifact@v7,
reactivecircus/android-emulator-runner@v2.37.0) and must be pinned to full
commit SHAs; for each referenced action (all occurrences listed in the comment)
replace the tag with the corresponding full commit SHA from that action's GitHub
repo (e.g., actions/checkout@<full-sha>), ensuring you update every instance
across both ios-e2e and android-e2e jobs and any repeated uses of actions/cache
and actions/upload-artifact so no third-party action uses a mutable tag.

In @.github/workflows/migrations.yml:
- Around line 1-25: The workflow "Database Migrations" currently lacks a
concurrency configuration which can allow parallel runs; add a concurrency block
(placed after the existing on: section) that defines a group string
incorporating the workflow name and environment input (e.g., using github.ref or
the workflow input environment) and set cancel-in-progress: true per guidelines
to prevent redundant concurrent migration runs; reference the existing symbols
"name: Database Migrations", "workflow_dispatch" and the "environment" input
when constructing the group.
- Around line 36-41: The workflow uses mutable tags for third-party actions
("actions/checkout@v6" and "oven-sh/setup-bun@v2"); replace these with the
corresponding full commit SHAs to pin the actions. Locate the two steps
referencing actions/checkout and oven-sh/setup-bun and update their "uses"
values to the exact commit SHA (e.g., actions/checkout@<full-sha> and
oven-sh/setup-bun@<full-sha>) fetched from each repo's releases/commit history,
then commit the updated workflow.

In @.github/workflows/sync-guides-r2.yml:
- Around line 29-34: Replace mutable action tags with immutable commit SHAs:
update the two uses entries "actions/checkout@v6" and "oven-sh/setup-bun@v2" to
the corresponding full commit SHA pins (e.g., actions/checkout@<full-sha> and
oven-sh/setup-bun@<full-sha>) so the workflow references exact commits; keep
existing inputs like "with: bun-version: latest" unchanged while swapping only
the action references.
- Around line 1-17: Add a concurrency section to the GitHub Actions workflow
(named "Sync Guides to R2 Bucket") right after the on: block to prevent
redundant runs: define concurrency with a descriptive group (e.g., using the
workflow name or branch/path context) and set cancel-in-progress: true so
in-progress sync jobs are canceled when a new run starts; update the workflow's
top-level keys (referencing name: "Sync Guides to R2 Bucket", the on: block, and
the concurrency key) accordingly.

In @.github/workflows/unit-tests.yml:
- Around line 48-52: The workflow is using mutable tags for third-party actions
(e.g., "uses: actions/checkout@v6" and "uses: oven-sh/setup-bun@v2"); replace
each mutable tag with the corresponding full commit SHA for the action (e.g.,
"uses: actions/checkout@<full-commit-sha>") so the workflow is pinned and
reproducible—locate the commit SHA on each action's GitHub repo/releases page
and update all occurrences (including the other uses blocks noted around lines
64-70, 77-81, 93-99) while preserving the existing inputs/keys (like with:
bun-version: latest).

In `@apps/expo/app/`(app)/trip/location-search.tsx:
- Around line 41-48: Replace the direct fetch(...) block that uses searchQuery
and GOOGLE_MAPS_API_KEY with a call to the app's typed API client (e.g., a new
or existing method like apiClient.getGeocode(searchQuery) or api.getGeocode) so
the network request lives behind the typed client; remove direct use of fetch
and the response/response.ok check and instead handle the typed client's
success/error shape (throw or return based on the client's error response), and
if the API key is currently embedded here move key usage to the server-side
endpoint invoked by the typed client so the Expo code never contains
GOOGLE_MAPS_API_KEY.

In `@apps/expo/features/auth/hooks/useAuthActions.ts`:
- Around line 95-114: The Google sign-in flow in signInWithGoogle leaves
isLoading true on success and silently returns when response has no error but
also no data.user; move setIsLoading(false) into a finally block or ensure it
runs after both success and failure, and add explicit handling after
authClient.signIn.social: if there's no error and either data is missing or
'user' is not in data or data.user is falsy, throw a descriptive Error (e.g.,
from t('auth.failedToSignInWithGoogle')) so applySession is only called when
data.user exists; update references to authClient.signIn.social, applySession,
setIsLoading and keep existing catch logic (isErrorWithCode/statusCodes)
unchanged.

In `@apps/web/package.json`:
- Around line 2-4: Add a top-level "version" field to the package.json manifest
so release validation passes: insert "version": "2.0.26" at the top-level
(beside "name": "packrat-web-app") in apps/web's package.json so the package has
the required version metadata for the release workflow to succeed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 218f4714-5085-439f-ab51-8990b3a57c90

📥 Commits

Reviewing files that changed from the base of the PR and between 107972a and 54dfd07.

⛔ Files ignored due to path filters (2)
  • apps/guides/bun.lock is excluded by !**/*.lock
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (113)
  • .github/scripts/configure-deps.ts
  • .github/workflows/api-tests.yml
  • .github/workflows/checks.yml
  • .github/workflows/copilot-setup-steps.yml
  • .github/workflows/e2e-tests.yml
  • .github/workflows/lighthouse.yml
  • .github/workflows/migrations.yml
  • .github/workflows/release-ios.yml
  • .github/workflows/sync-guides-r2.yml
  • .github/workflows/unit-tests.yml
  • .gitignore
  • apps/admin/components/edit-catalog-dialog.tsx
  • apps/admin/lib/api.ts
  • apps/admin/lib/queryKeys.ts
  • apps/admin/package.json
  • apps/expo/app.config.ts
  • apps/expo/app/(app)/trip/location-search.tsx
  • apps/expo/app/auth/index.tsx
  • apps/expo/app/auth/one-time-password.tsx
  • apps/expo/features/auth/hooks/useAuthActions.ts
  • apps/expo/features/auth/hooks/useAuthInit.ts
  • apps/expo/features/catalog/components/ItemReviews.tsx
  • apps/expo/lib/api/packrat.ts
  • apps/expo/lib/hooks/useColorScheme.tsx
  • apps/expo/package.json
  • apps/expo/utils/__tests__/weight.test.ts
  • apps/guides/__tests__/og-image.test.ts
  • apps/guides/app/guide/[slug]/opengraph-image.tsx
  • apps/guides/app/guide/[slug]/page.tsx
  • apps/guides/app/layout.tsx
  • apps/guides/app/opengraph-image.tsx
  • apps/guides/app/twitter-image.tsx
  • apps/guides/lib/metadata.ts
  • apps/guides/lib/og-image.tsx
  • apps/guides/package.json
  • apps/guides/scripts/generate-og-images.ts
  • apps/guides/vitest.config.ts
  • apps/landing/__tests__/og-image.test.ts
  • apps/landing/app/layout.tsx
  • apps/landing/app/opengraph-image.tsx
  • apps/landing/app/twitter-image.tsx
  • apps/landing/lib/metadata.ts
  • apps/landing/lib/og-image.tsx
  • apps/landing/package.json
  • apps/landing/scripts/generate-og-images.ts
  • apps/landing/vitest.config.ts
  • apps/trails/components/AuthGate.tsx
  • apps/trails/components/VerifyEmail.tsx
  • apps/trails/lib/apiClient.ts
  • apps/trails/lib/auth-client.ts
  • apps/trails/lib/auth.ts
  • apps/trails/lib/useAuth.tsx
  • apps/trails/package.json
  • apps/web/app/auth/page.tsx
  • apps/web/components/screens/ai-screen.tsx
  • apps/web/components/screens/gear-inventory-screen.tsx
  • apps/web/components/screens/profile-screen.tsx
  • apps/web/lib/api.ts
  • apps/web/lib/auth-client.ts
  • apps/web/lib/data.ts
  • apps/web/lib/types.ts
  • apps/web/package.json
  • biome.json
  • docs/plans/2026-05-13-chore-enroll-catalog-candidates-plan.md
  • package.json
  • packages/analytics/package.json
  • packages/api-client/package.json
  • packages/api/container_src/package.json
  • packages/api/drizzle/0037_nullable_catalog_weight.sql
  • packages/api/drizzle/0037_rich_electro.sql
  • packages/api/drizzle/0047_cute_bloodscream.sql
  • packages/api/drizzle/meta/0047_cute_bloodscream.json
  • packages/api/drizzle/meta/_journal.json
  • packages/api/package.json
  • packages/api/src/db/schema.ts
  • packages/api/src/index.ts
  • packages/api/src/routes/admin/analytics/catalog.ts
  • packages/api/src/routes/admin/index.ts
  • packages/api/src/routes/catalog/index.ts
  • packages/api/src/routes/index.ts
  • packages/api/src/routes/passwordReset.ts
  • packages/api/src/schemas/admin.ts
  • packages/api/src/schemas/auth.ts
  • packages/api/src/schemas/users.ts
  • packages/api/src/services/etl/processCatalogEtl.ts
  • packages/api/src/services/etl/processLogsBatch.ts
  • packages/api/src/services/etl/processValidItemsBatch.ts
  • packages/api/src/services/etl/queue.ts
  • packages/api/src/services/etl/types.ts
  • packages/api/src/services/etl/updateEtlJobProgress.ts
  • packages/api/src/services/packService.ts
  • packages/api/src/services/passwordResetService.ts
  • packages/api/src/utils/__tests__/weight.test.ts
  • packages/api/test/etl.test.ts
  • packages/api/wrangler.jsonc
  • packages/app/package.json
  • packages/app/src/entities/user/index.ts
  • packages/app/src/entities/user/queries.ts
  • packages/checks/package.json
  • packages/cli/package.json
  • packages/config/package.json
  • packages/env/package.json
  • packages/guards/package.json
  • packages/mcp/package.json
  • packages/osm-db/package.json
  • packages/osm-import/package.json
  • packages/overpass/package.json
  • packages/ui/package.json
  • packages/units/package.json
  • packages/units/src/index.test.ts
  • packages/units/src/index.ts
  • packages/web-ui/package.json
  • patches/@packrat-ai%2Fnativewindui@2.0.3.patch
💤 Files with no reviewable changes (5)
  • .github/workflows/copilot-setup-steps.yml
  • packages/app/src/entities/user/index.ts
  • .github/workflows/lighthouse.yml
  • .github/workflows/release-ios.yml
  • biome.json

Comment thread apps/admin/lib/api.ts
Comment thread apps/expo/features/auth/hooks/useAuthActions.ts
Comment thread apps/expo/features/catalog/components/ItemReviews.tsx Outdated
Comment thread apps/expo/lib/api/packrat.ts
Comment thread apps/expo/lib/api/packrat.ts
Comment thread packages/api/src/services/passwordResetService.ts
Comment thread packages/api/src/services/passwordResetService.ts
Comment thread packages/api/test/etl.test.ts
Comment thread packages/api/test/etl.test.ts
Comment thread packages/api/test/etl.test.ts
Resolved 11 file conflicts from diverging auth refactors:

- apps/admin/lib/queryKeys.ts: make `q` optional in osm.search/conditions (main)
- apps/expo/features/auth/hooks/useAuthActions.ts: keep both clientEnvs +
  asBoolean/asString imports; use proper type guards in mapToUser (main)
- apps/expo/features/auth/hooks/useAuthInit.ts: use asString/asBoolean in
  applySessionUser instead of raw String() casts (main)
- apps/expo/features/catalog/components/ItemReviews.tsx: use idx variable
  name and review.text?.length optional chaining (main)
- apps/trails/components/AuthGate.tsx: add trailsAuthClient import; call
  trailsAuthClient.requestPasswordReset directly in forgot-password handler;
  remove unused forgotPassword destructure and VerifyEmail import
- apps/trails/lib/auth-client.ts (add/add): export trailsAuthClient without
  nextCookies plugin (main)
- apps/trails/lib/useAuth.tsx: complete rewrite to main's local-state auth
  approach — adds pendingEmail, verifyEmail, resendVerification, token
  management via trails-app/lib/auth; forgotPassword implemented via
  trailsAuthClient to satisfy AuthActions interface
- apps/trails/package.json: remove direct better-auth dep (main)
- apps/web/app/auth/page.tsx: remove dead useLoginMutation/useRegisterMutation
  helpers; keep simple authClient-based mutations already in the component
- apps/web/package.json: remove ai + better-auth direct deps (main)
- bun.lock: take origin/main lockfile (latest catalog dependency resolution)
@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

cloudflare-workers-and-pages Bot commented May 15, 2026

Deploying packrat-guides with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9c35486
Status: ✅  Deploy successful!
Preview URL: https://2755d9d4.packrat-guides-6gq.pages.dev
Branch Preview URL: https://release-2-0-26.packrat-guides-6gq.pages.dev

View logs

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file api ci/cd mobile web labels May 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

Coverage Report for API Unit Tests Coverage (./packages/api)

Status Category Percentage Covered / Total
🔵 Lines 69.62% 502 / 721
🔵 Statements 69.62% (🎯 65%) 502 / 721
🔵 Functions 92.68% 38 / 41
🔵 Branches 88.32% 227 / 257
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/api/src/services/passwordResetService.ts 0% 0% 0% 0% 1-82
Generated in workflow #1268 for commit 07d50ad by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

Coverage Report for Expo Unit Tests Coverage (./apps/expo)

Status Category Percentage Covered / Total
🔵 Lines 82.61% 480 / 581
🔵 Statements 82.61% (🎯 75%) 480 / 581
🔵 Functions 92.59% 50 / 54
🔵 Branches 90.9% 170 / 187
File CoverageNo changed files found.
Generated in workflow #1268 for commit 07d50ad by the Vitest Coverage Report Action

@cloudflare-workers-and-pages
Copy link
Copy Markdown
Contributor

Deploying packrat-landing with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9c35486
Status: ✅  Deploy successful!
Preview URL: https://026be429.packrat-landing.pages.dev
Branch Preview URL: https://release-2-0-26.packrat-landing.pages.dev

View logs

@mikib0 mikib0 merged commit 7ab32c1 into main May 16, 2026
13 of 15 checks passed
@mikib0 mikib0 deleted the release/2.0.26 branch May 16, 2026 18:51
andrew-bierman added a commit that referenced this pull request May 17, 2026
Main's 07d50ad (fix(trails): correct authClient import to use trailsAuthClient)
overlapped with dev's broader auth refactor. Took dev's versions across:
- apps/expo/features/auth/hooks/useAuthActions.ts (uses asString/asBoolean guards)
- apps/trails/components/AuthGate.tsx (VerifyEmail + pendingEmail integration)
- apps/trails/lib/apiClient.ts (trailsAuthClient as authClient alias)
- apps/trails/lib/useAuth.tsx (pendingEmail in state shape)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api ci/cd dependencies Pull requests that update a dependency file mobile web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants