Skip to content
Merged
Show file tree
Hide file tree
Changes from 171 commits
Commits
Show all changes
173 commits
Select commit Hold shift + click to select a range
75622c8
Merge pull request #2399 from PackRat-AI/main
mikib0 May 9, 2026
29fe5e0
fix(expo): update Google sign-in logic to use new authClient method
mikib0 May 9, 2026
2aee172
Merge pull request #2400 from PackRat-AI/fix/google-auth
mikib0 May 9, 2026
2e2377e
feat(web): wire gear-inventory and ai-chat screens to real API
andrew-bierman May 8, 2026
43a08a7
fix(ci): remove unsupported cache input from oven-sh/setup-bun@v2
andrew-bierman May 12, 2026
460c895
fix(web): address PR review comments on gear-inventory and ai screens
andrew-bierman May 12, 2026
2497119
fix(ci): add --frozen-lockfile to bun install in all CI workflows
andrew-bierman May 12, 2026
ed55dd1
fix(types): migrate trails to Better Auth client, align admin/user sc…
andrew-bierman May 12, 2026
5dc4210
chore(trails): sort package.json dependencies
andrew-bierman May 12, 2026
b0cfbee
fix(auth): remove LegacyAuth cast, migrate web app to Better Auth client
andrew-bierman May 12, 2026
34064aa
chore(web): sort package.json dependencies
andrew-bierman May 12, 2026
d409a03
refactor(web/auth): use useMutation for login/register instead of raw…
andrew-bierman May 12, 2026
f1f748b
fix(types): patch @packrat-ai/nativewindui to suppress ts-nocheck errors
andrew-bierman May 12, 2026
35cef0d
chore: sort package.json after bun patch
andrew-bierman May 12, 2026
29d2b70
fix(a11y): add aria-label to gear inventory search input
andrew-bierman May 12, 2026
23a0b28
Merge pull request #2398 from PackRat-AI/feat/web-wire-remaining-screens
andrew-bierman May 12, 2026
8b297c5
chore(biome): remove packages/units/src/index.ts from useMaxParams ex…
andrew-bierman May 12, 2026
e8c52a8
fix(units): refactor convert/displayWeight to satisfy useMaxParams rule
andrew-bierman May 12, 2026
c6e7094
Merge pull request #2387 from PackRat-AI/chore-biome-max-params-one
andrew-bierman May 13, 2026
1587e33
fix(auth): restore missing Apple logo on apple sign-in button
mikib0 May 14, 2026
b9e0862
fix(auth): remove setNativeProps call on OTP field focus
mikib0 May 14, 2026
a0e210f
feat(auth): replace Better Auth password reset with custom 6-digit OT…
mikib0 May 14, 2026
e1edb96
fix(auth): annotate password reset routes as public
mikib0 May 14, 2026
19b85f7
fix(auth): read session token from SecureStore to stop spurious reaut…
mikib0 May 14, 2026
3584f2c
Initial plan
Copilot Aug 20, 2025
277d6b5
Initial plan
Copilot Aug 20, 2025
d4d55cf
Initial plan
Copilot Aug 20, 2025
2ee7993
Initial plan
Copilot Aug 20, 2025
f9e0ced
Initial plan
Copilot Aug 22, 2025
65ee90b
Initial plan
Copilot Aug 22, 2025
268c484
Initial plan
Copilot Aug 23, 2025
9d8b9e0
Initial plan
Copilot Aug 23, 2025
4c603bf
Initial plan
Copilot Aug 20, 2025
cba730f
Initial plan
Copilot Aug 23, 2025
2098c0a
Initial plan
Copilot Aug 24, 2025
7c1d03f
Initial plan
Copilot Aug 23, 2025
74208a3
Initial plan
Copilot Aug 23, 2025
c6fe4c8
Initial plan
Copilot Sep 9, 2025
ea1a6f3
Initial plan
Copilot Sep 11, 2025
5a0b8b5
Initial plan
Copilot Sep 10, 2025
dbed3b3
Initial plan
Copilot Sep 11, 2025
fd2bca9
Initial plan
Copilot Sep 12, 2025
2a3927f
Initial plan
Copilot Oct 4, 2025
a1007a6
Initial plan
Copilot Oct 17, 2025
a62b9d9
Initial plan
Copilot Oct 17, 2025
07cedcc
Initial plan
Copilot Oct 18, 2025
5fb4623
Initial plan
Copilot Oct 20, 2025
f26491b
Initial plan
Copilot Oct 25, 2025
7e4c44e
Initial plan
Copilot Oct 26, 2025
c900bd7
Initial plan
Copilot Nov 18, 2025
12fd8fb
Initial plan
Copilot Nov 6, 2025
052cd01
Initial plan
Copilot Nov 6, 2025
6a605e3
Initial plan
Copilot Nov 8, 2025
0e7c2b7
Initial plan
Copilot Nov 8, 2025
e9d488e
Initial plan
Copilot Nov 9, 2025
66e23d7
Initial plan
Copilot Nov 9, 2025
691863f
Initial plan
Copilot Nov 11, 2025
ce38874
Initial plan
Copilot Nov 11, 2025
abf4e12
Initial plan
Copilot Nov 11, 2025
cc9ab97
Initial plan
Copilot Nov 11, 2025
076832c
Initial plan
Copilot Nov 18, 2025
ca6aaf3
Initial plan
Copilot Nov 18, 2025
ca56245
Initial plan
Copilot Nov 18, 2025
a00737a
Initial plan
Copilot Nov 18, 2025
4607681
Initial plan
Copilot Nov 18, 2025
c80a270
Initial plan
Copilot Nov 18, 2025
7b839c6
Initial plan
Copilot Nov 18, 2025
1a5c046
Initial plan
Copilot Nov 18, 2025
fb38aa3
Initial plan
Copilot Nov 18, 2025
c906445
Initial plan
Copilot Nov 18, 2025
3ebd3e5
Initial plan
Copilot Nov 18, 2025
871a6e6
Initial plan
Copilot Nov 18, 2025
6cd50be
Initial plan
Copilot Nov 18, 2025
c3ef508
Initial plan
Copilot Dec 2, 2025
5fa7fb2
Initial plan
Copilot Dec 13, 2025
eff86a3
Initial plan
Copilot Mar 9, 2026
490cc6e
Initial plan
Copilot Mar 9, 2026
9bee8b1
Initial plan
Copilot Mar 9, 2026
536c663
Initial plan
Copilot Mar 10, 2026
ac5db64
Initial plan
Copilot Mar 9, 2026
1316fb9
Initial plan
Copilot Mar 10, 2026
408ffa7
Initial plan
Copilot Feb 21, 2026
e731328
Initial plan
Copilot Feb 27, 2026
a3ff82d
Initial plan
Copilot Mar 10, 2026
ce6a013
Initial plan
Copilot Mar 7, 2026
97c410d
Initial plan
Copilot Mar 10, 2026
b868fdb
Initial plan
Copilot Mar 11, 2026
af7e4cf
Initial plan
Copilot Mar 9, 2026
fe59d53
Initial plan
Copilot Mar 9, 2026
23451c1
Initial plan
Copilot Mar 13, 2026
c49fb49
Initial plan
Copilot Mar 13, 2026
c661f5f
Initial plan
Copilot Mar 13, 2026
8f78c09
Initial plan
Copilot Mar 13, 2026
874253e
fix(expo/CreatePackItemForm): default quantity to 1 instead of 0
mikib0 Mar 13, 2026
bdb4e13
Initial plan
Copilot Mar 13, 2026
a43d4ba
Initial plan
Copilot Mar 16, 2026
c54c396
Initial plan
Copilot Mar 9, 2026
6091ec5
Initial plan
Copilot Mar 13, 2026
8994538
Initial plan
Copilot Mar 13, 2026
85e3d42
Initial plan
Copilot Mar 9, 2026
a66e360
Initial plan
Copilot Mar 9, 2026
9cb8e86
Initial plan
Copilot Apr 1, 2026
991b21b
Initial plan
Copilot Mar 21, 2026
1adcc0a
Initial plan
Copilot Mar 9, 2026
d3fad53
Initial plan
Copilot Mar 9, 2026
138325b
Initial plan
Copilot Mar 9, 2026
6c6cbb7
Initial plan
Copilot Mar 9, 2026
300f8d9
Initial plan
Copilot Mar 9, 2026
3182ec2
Initial plan
Copilot Mar 9, 2026
c1be87c
Initial plan
Copilot Mar 9, 2026
67b8a0d
Initial plan
Copilot Mar 9, 2026
e9f0a13
Initial plan
Copilot Mar 9, 2026
30aa570
Initial plan
Copilot Mar 9, 2026
17e1727
Initial plan
Copilot Aug 22, 2025
41cc410
Initial plan
Copilot Feb 27, 2026
dc6fb03
chore: reopen trigger (no-op commit to restore PR state)
andrew-bierman Apr 11, 2026
375cec3
ci: trigger biome check
andrew-bierman Apr 11, 2026
89af5bf
ci: retrigger CI after biome fixes
andrew-bierman Apr 11, 2026
84ac668
Initial plan
Copilot Mar 9, 2026
58e76d1
ci: trigger checks for dependabot merges
andrew-bierman Apr 13, 2026
9f0cb60
Initial plan
Copilot Apr 13, 2026
eeb762f
ci: retrigger checks after copilot merge-conflict fix
andrew-bierman Apr 14, 2026
06f0cc1
ci: trigger CI on Copilot bot's expo-symbols type fixes
andrew-bierman Apr 14, 2026
0fc5f35
Initial plan
Copilot Apr 14, 2026
d31aee0
trigger: retrigger CI after node_modules clean install verified vites…
andrew-bierman Apr 15, 2026
0c35b33
Initial plan
Copilot Apr 14, 2026
ea32f1f
trigger: retrigger CI after node_modules clean install verified vites…
andrew-bierman Apr 15, 2026
6fb579d
ci: re-trigger checks after @types/react alignment fix
claude Apr 16, 2026
fb2fea3
Initial plan
Copilot Apr 14, 2026
6ce180f
Initial plan
Copilot Apr 16, 2026
a9f51ad
ci: trigger CI run on updated branch
claude Apr 16, 2026
97937ba
Initial plan
Copilot Sep 22, 2025
b93b769
Initial plan
Copilot Sep 22, 2025
8c4fe51
ci: trigger workflows
andrew-bierman Apr 14, 2026
104cc3f
ci: retrigger CI after suspected transient runner failure
claude Apr 26, 2026
cc76f11
ci: retrigger workflows
andrew-bierman Apr 29, 2026
12bb727
fix(expo): null-safe color scheme toggle and geocode response check
andrew-bierman May 14, 2026
420f2eb
chore(expo/lib/api/packrat): improve typing
mikib0 May 14, 2026
cfcad31
chore(api/passwordResetService): resolve type issue
mikib0 May 14, 2026
38b8fd2
Merge pull request #2425 from PackRat-AI/fix/auth
mikib0 May 14, 2026
edbbe05
fix(etl): use raw SQL for completion write to bypass neon-http enum i…
andrew-bierman May 8, 2026
327512f
fix(etl): make catalog_items weight nullable + add ETL integration tests
andrew-bierman May 8, 2026
76a3ad9
fix(db): regenerate migration with drizzle-kit (0037_rich_electro)
andrew-bierman May 9, 2026
ae7c4b0
fix(etl): handle nullable weight/weightUnit when building pack items …
andrew-bierman May 12, 2026
0620808
fix(admin,etl): fix CORS Access-Control-Allow-Origin missing on prefl…
andrew-bierman May 12, 2026
5ef9b41
fix(types): resolve TypeScript errors blocking CI checks job
andrew-bierman May 12, 2026
d59d933
chore(deps): pin @packrat-ai/nativewindui to 2.0.3-2
andrew-bierman May 12, 2026
6c47e8c
feat(admin,etl): align TypeBox schemas with route columns + add ETL a…
andrew-bierman May 12, 2026
63eca7b
fix(etl): flush remaining items before updating totalProcessed + use …
andrew-bierman May 13, 2026
c7da8cd
fix(etl): yield to event loop every 100 rows instead of every row
andrew-bierman May 13, 2026
f475d03
fix(etl): respect stream backpressure to prevent Worker OOM on large …
andrew-bierman May 13, 2026
0fb11bf
fix(etl): raise cpu_ms limit to 400k (CF max) for large-file queue pr…
andrew-bierman May 13, 2026
9ecdad8
feat(etl): split large R2 files into 20 MB byte-range chunks at queue…
andrew-bierman May 13, 2026
e83583c
fix(admin,etl): address CodeRabbit/Copilot review comments
andrew-bierman May 12, 2026
5925ebf
fix(cors): add admin.packratai.com + *.workers.dev to root cors allow…
andrew-bierman May 12, 2026
7b915b4
fix(admin/analytics): coerce Neon int8 strings to Number() in overvie…
andrew-bierman May 12, 2026
ea8c729
fix(og): generate static PNG OG images for landing and guides static …
Copilot May 13, 2026
50445d7
chore(deps): enroll 47 third-party packages into Bun workspace catalog
andrew-bierman May 13, 2026
2fcba62
fix(guides): remove standalone bun.lock that broke Cloudflare Pages c…
andrew-bierman May 13, 2026
e36a3fa
fix(ci): add CF Pages-specific error message for missing GitHub Packa…
andrew-bierman May 14, 2026
9e340ad
fix(deps): replace vitest version pins with catalog: in landing and g…
andrew-bierman May 14, 2026
098adaf
fix(api): lower cpu_ms limit to 300000 — CF max is 300 s not 400 s
andrew-bierman May 14, 2026
78382fe
fix(etl): atomic totalProcessed updates and reset counters on retry
andrew-bierman May 14, 2026
721fad0
fixup: remove retry counter reset — incompatible with byte-range chun…
andrew-bierman May 14, 2026
ef675cc
chore: migrate trails/web deps to workspace catalog
andrew-bierman May 14, 2026
0be62e5
chore: regenerate bun.lock after catalog migration
andrew-bierman May 14, 2026
806f2f8
fix(etl): pass chunks instead of objectKeys to queueCatalogETL
andrew-bierman May 14, 2026
4fead9f
Merge pull request #2424 from PackRat-AI/chore/merge-main-into-develo…
andrew-bierman May 15, 2026
72c4e40
fix(auth): check __Secure- prefixed cookie when reading session token
mikib0 May 15, 2026
1917ea7
Merge pull request #2426 from PackRat-AI/fix/auth-secure-cookie-prefix
mikib0 May 15, 2026
54dfd07
chore: bump version to v2.0.26
mikib0 May 15, 2026
9c35486
chore: merge origin/main into release/2.0.26
mikib0 May 15, 2026
07d50ad
fix(trails): correct authClient import to use trailsAuthClient
mikib0 May 15, 2026
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
18 changes: 16 additions & 2 deletions .github/scripts/configure-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ function isCI(): boolean {
);
}

function isCFPages(): boolean {
return process.env.CF_PAGES === '1';
}

function printLocalFix(): void {
console.error(`\n❌ ${TOKEN_VAR} is not exported in your shell.`);
console.error('\nBun reads bunfig.toml before the preinstall hook runs, so the token');
Expand All @@ -47,8 +51,18 @@ async function configureDeps() {
}

if (isCI()) {
console.error(`❌ ${TOKEN_VAR} not found in CI environment`);
console.error(`Set ${TOKEN_VAR} in your CI secrets and expose it to this job.`);
if (isCFPages()) {
console.error(`❌ ${TOKEN_VAR} not found in Cloudflare Pages build environment.`);
console.error('Add it as an environment variable in the CF Pages project settings:');
console.error(
' dash.cloudflare.com → Pages → packrat-guides → Settings → Environment variables',
);
console.error(` Variable name: ${TOKEN_VAR}`);
console.error(' Value: a GitHub PAT with read:packages scope');
} else {
console.error(`❌ ${TOKEN_VAR} not found in CI environment`);
console.error(`Set ${TOKEN_VAR} in your CI secrets and expose it to this job.`);
}
process.exit(1);
}

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/api-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Run API tests
run: bun run --cwd packages/api test 2>&1 | tee /tmp/api-tests-output.log
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile
- name: Run Biome (check mode)
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.fix == true) }}
run: bun biome check
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ steps.bun-version.outputs.version }}
cache: true

# Sanity-check that the runner satisfies the repo's engine constraints.
- name: Verify runtime versions
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Setup Expo
uses: expo/expo-github-action@v8
Expand Down Expand Up @@ -343,7 +343,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Setup Expo
uses: expo/expo-github-action@v8
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/lighthouse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
Expand Down Expand Up @@ -60,7 +59,6 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/migrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Determine target environment
id: env
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/release-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10
cache: true

- name: Validate release tag and app versions
run: bun .github/scripts/validate-release-version.ts "${{ steps.release_tag.outputs.tag }}"
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/sync-guides-r2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,13 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Authenticate with GitHub for private packages
run: |
echo "PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV

- name: Install dependencies
run: bun install
run: bun install --frozen-lockfile
timeout-minutes: 5

- name: Sync guides to R2 bucket
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,11 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Run API unit tests
run: bun run --cwd packages/api test:unit:coverage
Expand All @@ -80,12 +79,11 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install
run: bun install --frozen-lockfile

- name: Run Expo unit tests
run: bun run --cwd apps/expo test:coverage
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
.claude/scheduled_tasks.lock
.dev.vars

# Generated OG images (produced at build time by scripts/generate-og-images.ts)
apps/landing/public/og-image.png
apps/guides/public/og-image.png
apps/guides/public/og/

# Git worktrees
.worktrees/
.worktrees
4 changes: 2 additions & 2 deletions apps/admin/components/edit-catalog-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function EditCatalogDialog({ item }: EditCatalogDialogProps) {
: null;
const weightRaw = fd.get('weight')?.toString().trim();
const weight = weightRaw ? Number(weightRaw) : undefined;
const weightUnit = fd.get('weightUnit')?.toString().trim() || item.weightUnit;
const weightUnit = fd.get('weightUnit')?.toString().trim() || item.weightUnit || undefined;
const priceRaw = fd.get('price')?.toString().trim();
const price = priceRaw ? Number(priceRaw) : null;

Expand Down Expand Up @@ -108,7 +108,7 @@ export function EditCatalogDialog({ item }: EditCatalogDialogProps) {
<Input
id="weightUnit"
name="weightUnit"
defaultValue={item.weightUnit}
defaultValue={item.weightUnit ?? ''}
placeholder="g"
/>
</div>
Expand Down
95 changes: 22 additions & 73 deletions apps/admin/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import type { App } from '@packrat/api';
import type {
ActiveUsersSchema,
ActivityPointSchema,
AdminCatalogItemSchema,
AdminPackItemSchema,
AdminUserItemSchema,
BrandRowSchema,
BreakdownItemSchema,
CatalogOverviewSchema,
EmbeddingStatsSchema,
EtlFailureSummarySchema,
EtlJobFailuresSchema,
EtlJobSchema,
EtlResponseSchema,
GrowthPointSchema,
Expand Down Expand Up @@ -69,17 +74,7 @@ export async function getStats(): Promise<AdminStats> {

// ─── Users ────────────────────────────────────────────────────────────────────

export interface AdminUser {
id: number;
email: string;
firstName: string | null;
lastName: string | null;
role: string | null;
emailVerified: boolean | null;
avatarUrl: string | null;
createdAt: string | null;
updatedAt: string | null;
}
export type AdminUser = Static<typeof AdminUserItemSchema>;

export interface PaginatedResponse<T> {
data: T[];
Expand All @@ -106,42 +101,30 @@ export async function getUsers({
return unwrap(data, 'users');
}

export async function deleteUser(id: number): Promise<{ success: boolean }> {
const { data, error } = await adminClient.users({ id: String(id) }).delete();
export async function deleteUser(id: string): Promise<{ success: boolean }> {
const { data, error } = await adminClient.users({ id }).delete();
if (error) throwOnError(error);
return unwrap(data, 'deleteUser');
}

export async function hardDeleteUser(
id: number,
id: string,
reason: string,
): Promise<{ success: boolean; purged: boolean }> {
const { data, error } = await adminClient.users({ id: String(id) }).hard.delete({ reason });
const { data, error } = await adminClient.users({ id }).hard.delete({ reason });
if (error) throwOnError(error);
return unwrap(data, 'hardDeleteUser');
}

export async function restoreUser(id: number): Promise<{ success: boolean }> {
const { data, error } = await adminClient.users({ id: String(id) }).restore.post();
export async function restoreUser(id: string): Promise<{ success: boolean }> {
const { data, error } = await adminClient.users({ id }).restore.post();
if (error) throwOnError(error);
return unwrap(data, 'restoreUser');
}

// ─── Packs ────────────────────────────────────────────────────────────────────

export interface AdminPack {
id: string;
name: string;
description: string | null;
category: string;
isPublic: boolean | null;
isAIGenerated: boolean;
tags: string[] | null;
image: string | null;
createdAt: string | null;
updatedAt: string | null;
userEmail: string | null;
}
export type AdminPack = Static<typeof AdminPackItemSchema>;

export async function getPacks({
limit = 100,
Expand Down Expand Up @@ -169,32 +152,7 @@ export async function deletePack(id: string): Promise<{ success: boolean }> {

// ─── Catalog Items ────────────────────────────────────────────────────────────

export interface AdminCatalogItem {
id: number;
name: string;
description: string | null;
categories: string[] | null;
brand: string | null;
model: string | null;
sku: string | null;
price: number | null;
currency: string | null;
weight: number | null;
weightUnit: string;
availability: string | null;
ratingValue: number | null;
reviewCount: number | null;
color: string | null;
size: string | null;
material: string | null;
seller: string | null;
productUrl: string | null;
images: string[] | null;
variants: Array<{ attribute: string; values: string[] }> | null;
techs: Record<string, string> | null;
links: Array<{ title: string; url: string }> | null;
createdAt: string | null;
}
export type AdminCatalogItem = Static<typeof AdminCatalogItemSchema>;

export interface UpdateCatalogItemInput {
name?: string;
Expand Down Expand Up @@ -377,27 +335,18 @@ export async function deleteTrailCondition(reportId: string): Promise<{ success:
return unwrap(data, 'deleteTrailCondition');
}

async function adminFetch<T>(path: string, init?: RequestInit): Promise<T> {
const res = await adminFetcher(`${API_BASE}/api/admin${path}`, init);
if (!res.ok) throw new Error(`Admin API error: ${res.status}`);
return res.json();
}
Comment thread
mikib0 marked this conversation as resolved.

export function resetStuckEtlJobs(): Promise<{ reset: number; ids: string[] }> {
return adminFetch('/analytics/catalog/etl/reset-stuck', { method: 'POST' });
}

export type EtlErrorRow = { field: string; reason: string; count: number };

export type EtlFailureSummary = {
topErrors: EtlErrorRow[];
totalInvalidItems: number;
};

export type EtlJobFailures = {
jobId: string;
errorBreakdown: EtlErrorRow[];
samples: Array<{
rowIndex: number;
errors: Array<{ field: string; reason: string; value?: unknown }>;
rawData: unknown;
}>;
totalShown: number;
};
export type EtlFailureSummary = Static<typeof EtlFailureSummarySchema>;
export type EtlJobFailures = Static<typeof EtlJobFailuresSchema>;

export function getEtlFailureSummary(limit = 20): Promise<EtlFailureSummary> {
return adminFetch(`/analytics/catalog/etl/failure-summary?limit=${limit}`);
Expand Down
7 changes: 7 additions & 0 deletions apps/admin/lib/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export const queryKeys = {
breakdown: () => [...queryKeys.platform.all(), 'breakdown'] as const,
},

osm: {
all: () => ['osm'] as const,
search: (q: string, sport?: string) => [...queryKeys.osm.all(), 'search', q, sport] as const,
trail: (osmId: string) => [...queryKeys.osm.all(), 'trail', osmId] as const,
conditions: (search?: string) => [...queryKeys.osm.all(), 'conditions', search] as const,
},

catalogAnalytics: {
all: () => ['catalogAnalytics'] as const,
overview: () => [...queryKeys.catalogAnalytics.all(), 'overview'] as const,
Expand Down
Loading
Loading