+120
-24
AGENTS.md
+120
-24
AGENTS.md
···
1
-
# Agent Guidelines for Boombox
1
+
# Agent Guidelines for Boombox (Monorepo)
2
2
3
-
## Commands
4
-
- **Build**: `bun run build` (web), no build needed for backend
5
-
- **Dev**: `bun run dev` (root - starts all workspaces), `bun run dev` (individual workspace)
6
-
- **Test**: `bun test` (backend), `bun test <file>` (single test)
7
-
- **Format**: `bun run format` (web only)
8
-
- **DB**: `bun db:migrate`, `bun db:gen` (from root)
3
+
This repo is a Bun monorepo with 3 workspaces:
4
+
- `backend/`: Bun + Elysia + Effect + Drizzle (SQLite)
5
+
- `web/`: Vite + TanStack Start (React) + Tailwind + shadcn/ui
6
+
- `shared/`: shared Effect `Schema` types/utilities (`@boombox/shared`)
9
7
10
-
## Code Style
11
-
- **Tabs**: Use tabs (4-width), 120 char line length
12
-
- **Imports**: Use absolute imports, no barrel files
13
-
- **TypeScript**: Strict - no `any`, explicit types preferred
14
-
- **Effect**: Use Effect.gen syntax, proper error handling with TaggedError
15
-
- **React**: Function components, Jotai for state, shadcn/ui components
16
-
- **Naming**: camelCase for variables/functions, PascalCase for components/types
17
-
- **Error Handling**: Use Effect error handling, tagged errors for typed failures
8
+
If you’re changing only one service, also read the workspace-specific guide:
9
+
- Backend: `backend/AGENTS.md`
10
+
- Web: `web/AGENTS.md`
18
11
19
-
## Framework Usage
20
-
- **Runtime**: Bun (not Node.js) - use `bun` commands, `Bun.file()`, etc.
21
-
- **Backend**: Elysia + Effect + Drizzle ORM + SQLite
22
-
- **Frontend**: Waku (React framework) + Jotai + UnoCSS + shadcn/ui
23
-
- **Database**: SQLite with Drizzle migrations
12
+
## Quick commands (real scripts)
24
13
25
-
## Repository Structure
26
-
Monorepo with workspaces: `backend/`, `web/`, `shared/`. Use workspace references (`@boombox/shared`).
14
+
### Install
15
+
- **Install all deps**: `bun install` (run from repo root)
27
16
28
-
## Cursor Rules
29
-
- Use Bun instead of Node.js, npm, pnpm, or vite. Prefer `bun test`, `bun install`, `Bun.serve()`, etc.
17
+
### Dev
18
+
- **Dev (all workspaces)**: `bun run dev`
19
+
- This runs `bun --filter '*' dev` from root (starts backend + web).
20
+
- **Dev (backend only)**:
21
+
- `cd backend && bun run dev`
22
+
- or `bun --filter @boombox/backend dev`
23
+
- **Dev (web only)**:
24
+
- `cd web && bun run dev` (Vite on port `3000`)
25
+
- or `bun --filter web-tanstack dev`
26
+
27
+
### Build
28
+
- **Build (backend)**: `cd backend && bun run build`
29
+
- **Build (web)**: `cd web && bun run build`
30
+
31
+
### Tests (Vitest)
32
+
- **Test (backend)**: `cd backend && bun run test` (`vitest run`)
33
+
- **Test (web)**: `cd web && bun run test` (`vitest run`)
34
+
35
+
#### Run a single test (recommended patterns)
36
+
- **Single test file**:
37
+
- Backend: `cd backend && bun run test -- test/flac.test.ts`
38
+
- Web: `cd web && bun run test -- src/**/some.test.ts`
39
+
- **Single test by name** (Vitest `-t`):
40
+
- Backend: `cd backend && bun run test -- -t "readMetadata should return album"`
41
+
- Web: `cd web && bun run test -- -t "renders"`
42
+
- **From repo root via workspace filter** (handy in CI scripts):
43
+
- Backend: `bun --filter @boombox/backend test -- test/flac.test.ts`
44
+
- Web: `bun --filter web-tanstack test -- -t "something"`
45
+
46
+
### Lint / format
47
+
- **Format (all)**: `bun run format` (runs `oxfmt .` from root)
48
+
- **Web (lint)**: `cd web && bun run lint`
49
+
- **Web (format)**: `cd web && bun run format`
50
+
- **Web (format + lint fix)**: `cd web && bun run check`
51
+
- **Backend (lint)**: `cd backend && bunx oxlint .`
52
+
- **Backend (format)**: `cd backend && bunx oxfmt --write .`
53
+
54
+
### Database
55
+
- **Migrate (root)**: `bun db:migrate` (runs `backend` migrate script)
56
+
- **Generate migrations (root)**: `bun db:gen` (runs `drizzle-kit generate` in backend)
57
+
58
+
## Repo structure & how code is organized
59
+
60
+
### Workspaces
61
+
- **`backend/`**: API + ingestion + DB layer
62
+
- Effect-first architecture: services via `Effect.Service`, composed with `Layer`
63
+
- Elysia routes run Effects via `ManagedRuntime.runPromise`
64
+
- SQLite is used both via Drizzle ORM (queries) and direct Bun SQLite migrator usage for migrations
65
+
- **`web/`**: React app
66
+
- TanStack Start router (file-based routes) + TanStack Query integration
67
+
- Tailwind CSS styling
68
+
- “shadcn/ui” components live under `web/src/components/ui`
69
+
- **`shared/`**: shared Effect `Schema` models/brands and utilities
70
+
71
+
### Import paths (no barrels)
72
+
- **Backend alias**: `~/*` → `backend/src/*` (see `backend/tsconfig.json`)
73
+
- **Web alias**: `@/*` → `web/src/*` (see `web/tsconfig.json`)
74
+
- **Shared**: import as `@boombox/shared` (workspace dependency)
75
+
- **Rule of thumb**: prefer explicit module imports (no barrel files), and keep imports stable (avoid deep relative paths like `../../../../x`).
76
+
77
+
## Code style (enforced by config)
78
+
79
+
### Formatting
80
+
- **Formatter**: oxfmt (Oxc formatter)
81
+
- **Tabs**: `tabWidth = 4`, `useTabs = true`
82
+
- **Line length**: `printWidth = 120`
83
+
- **Semicolons**: enabled
84
+
- Run `bun run format` from repo root to format everything
85
+
86
+
### TypeScript
87
+
- **Strict**: all workspaces have `"strict": true`
88
+
- **Avoid `any`**: prefer explicit types or `unknown` + decoding
89
+
- **Runtime validation**:
90
+
- Prefer `effect/Schema` for boundaries (DB rows → API DTOs, env vars, external inputs)
91
+
- Use `Schema.decodeUnknown` / `Schema.transformOrFail` for safe transformations
92
+
93
+
### Naming & files
94
+
- **Types / classes**: `PascalCase` (`AlbumNotFoundError`, `ApiService`)
95
+
- **Functions / variables**: `camelCase` (`getAlbumById`, `syncLibraryStream`)
96
+
- **React components**: `PascalCase` exported components; filenames tend to be kebab-case (`album-card.tsx`, `song-row.tsx`)
97
+
- **Constants**: `SCREAMING_SNAKE_CASE` for “true constants” (`SHUTDOWN_TIMEOUT_MS`)
98
+
99
+
## Error handling (Effect-first)
100
+
101
+
### Prefer typed failures
102
+
- **Create domain errors** using Effect’s tagged errors:
103
+
- `Data.TaggedError("MyError")<{ ... }>`
104
+
- or `Schema.TaggedError<...>()("MyError", { ...schema... })` when you want schema-validated payloads
105
+
- **Handle failures explicitly**:
106
+
- `Effect.catchTag("MyError", ...)` for tagged errors
107
+
- `Effect.mapError(...)` to translate lower-level errors into domain errors
108
+
- `Effect.tapError(Effect.logError)` / `Effect.tapErrorCause(...)` for logging without changing control flow
109
+
110
+
### Don’t throw for control flow (except at framework boundaries)
111
+
- In pure Effect code, prefer `Effect.fail(...)` / `Effect.fromNullable` rather than `throw`.
112
+
- In Elysia route handlers, throwing is acceptable only for *immediate request validation* or framework-level early exits; otherwise return an Effect and map errors to HTTP status codes.
113
+
114
+
## Cursor / editor rules
115
+
116
+
### Bun-first policy
117
+
- Use **Bun** for installs/scripts/tests. Avoid npm/pnpm/yarn.
118
+
119
+
### Cursor rules found in repo
120
+
- `web/.cursorrules` includes shadcn guidance (uses `pnpx shadcn@latest add <component>`). Follow it when adding shadcn components.
121
+
122
+
## “Agent ergonomics” (how to work safely here)
123
+
- Keep changes scoped to the relevant workspace (`backend/` vs `web/`).
124
+
- When editing API contracts used by web, update both sides (backend `ApiType` + web client usage).
125
+
- Prefer adding/adjusting tests close to the code (`backend/test/*`, `backend/src/**.test.ts`, `web/**.test.ts`).
-8
backend/.prettierrc.toml
-8
backend/.prettierrc.toml
+118
backend/AGENTS.md
+118
backend/AGENTS.md
···
1
+
# Backend Agent Guide (`@boombox/backend`)
2
+
3
+
This workspace is the Bun API + ingestion service built with **Elysia + Effect + Drizzle (SQLite)**.
4
+
5
+
If you haven’t yet, read the repo entrypoint first: `../AGENTS.md`.
6
+
7
+
## Commands (run from `backend/`)
8
+
9
+
- **Dev (watch)**: `bun run dev`
10
+
- Runs `bun run --watch ./src/index.ts`
11
+
- **Build**: `bun run build`
12
+
- Builds `./src/index.ts` to `./dist` (`bun build --target=bun --bytecode`)
13
+
- **Test**: `bun run test`
14
+
- Runs `vitest run`
15
+
16
+
### Single test execution
17
+
18
+
- **Single file**: `bun run test -- test/flac.test.ts`
19
+
- **By name**: `bun run test -- -t "parseFile should parse flac just fine"`
20
+
- **Watch mode (Vitest)**: `bunx vitest` or `bunx vitest --watch`
21
+
22
+
### Database
23
+
24
+
- **Migrate**: `bun run db:migrate`
25
+
- Runs `src/db/migrate.ts`
26
+
- **Generate migration**: `bun run db:gen`
27
+
- Runs `drizzle-kit generate`
28
+
29
+
### Lint / format
30
+
31
+
- **Lint (oxlint)**: `bunx oxlint .`
32
+
- **Format (oxfmt)**: `bunx oxfmt .`
33
+
34
+
## Entry points & folder map
35
+
36
+
- **`src/index.ts`**: runtime + layers + startup/shutdown + periodic sync loop
37
+
- **`src/api.ts`**: Elysia server + Effect-powered handlers + typed API surface
38
+
- **`src/db/`**:
39
+
- `schema.ts`: Drizzle schema & relations
40
+
- `index.ts`: Effect SQL/Drizzle service layer (`DatabaseLive`)
41
+
- `migrate.ts`: migration runner
42
+
- **`src/file-parser.ts`**: stream-based directory scan + file parsing per extension
43
+
- **`src/sync-library.ts`**: batching + inserts + relation wiring
44
+
- **`src/flac/`, `src/m4a/`**: format-specific metadata readers (Effect services + errors)
45
+
- **`test/`**: Vitest tests (some use `@effect/vitest`)
46
+
- **`test-data/`**: fixture audio files
47
+
48
+
## Coding patterns (preferred)
49
+
50
+
### Effect services + layers
51
+
52
+
Use `Effect.Service` and compose layers rather than manually passing dependencies.
53
+
54
+
- Prefer:
55
+
- `class X extends Effect.Service<X>()("...", { dependencies: [...], accessors: true, effect: Effect.gen(...) }) {}`
56
+
- `Layer.merge / Layer.mergeAll / Layer.provideMerge` to assemble the app layer
57
+
58
+
### “Effect-first” function style
59
+
60
+
- Prefer `Effect.gen(function* () { ... })` for sequencing.
61
+
- Use `Effect.fn("label")(function* (...) { ... })` for named effects (better tracing/logging).
62
+
- Use `pipe(...)` only when it improves readability; don’t over-nest.
63
+
64
+
### Typed errors (no untyped throws in core logic)
65
+
66
+
- Define domain failures with `Data.TaggedError(...)` or `Schema.TaggedError(...)`.
67
+
- When you need to change the error domain:
68
+
- `Effect.mapError((cause) => new MyDomainError({ ... }))`
69
+
- When you need to handle a specific failure:
70
+
- `Effect.catchTag("MyDomainError", (e) => ...)`
71
+
72
+
Good examples already in the codebase:
73
+
74
+
- `src/api.ts`: `FileNotFoundError`, `AlbumNotFoundError` (tagged) and `Effect.catchTag(...)` in route handlers
75
+
- `src/m4a/errors.ts`: schema-backed tagged errors for structured payloads
76
+
77
+
### Schema at boundaries (decode/transform)
78
+
79
+
Use `effect/Schema` for:
80
+
81
+
- Env/config validation (`src/utils/env.ts`)
82
+
- DB row → API DTO transformations (`Schema.transformOrFail`, `Schema.decodeUnknown`)
83
+
84
+
If you’re returning data from DB queries, prefer:
85
+
86
+
- `Schema.decodeUnknown(...)` on the raw DB row(s)
87
+
- then transform to your public response schema
88
+
89
+
## Elysia + Effect integration
90
+
91
+
### Handler rule of thumb
92
+
93
+
- **Inside handlers**: build an `Effect` value, then execute via `runtime.runPromise`.
94
+
- **Error mapping**: don’t rely on “whatever runtime throws”:
95
+
- translate domain errors to HTTP status with `Effect.catchTag(...)` and return `elysia/status(...)`
96
+
97
+
`backend/ISSUES.md` calls out that error handling is currently inconsistent; if you touch `src/api.ts`, consider improving handler wrappers rather than adding more one-off mappings.
98
+
99
+
## Concurrency & SQLite notes
100
+
101
+
SQLite will lock under write-heavy concurrent load.
102
+
103
+
- In streams that write to DB, prefer `Stream.mapEffect(fn, { concurrency: 1 })` unless you’ve verified safe parallelism.
104
+
- Batch inserts with `Stream.grouped(n)` (see `src/sync-library.ts`).
105
+
106
+
## Config & ports
107
+
108
+
- `DB_URL` and `FOLDER_PATH` are required env vars (see `src/utils/env.ts`).
109
+
- The API currently listens on port `3003` in `src/api.ts` and `src/index.ts` logs that port.
110
+
- `backend/ISSUES.md` suggests making port configurable via `Config`.
111
+
112
+
## Testing conventions
113
+
114
+
This workspace uses Vitest, plus `@effect/vitest` in several tests.
115
+
116
+
- For Effect workflows, prefer `test.effect("name", () => Effect.gen(...))`.
117
+
- Provide dependencies with `Effect.provide(SomeLayer)` (see `backend/test/*.test.ts`).
118
+
- For plain Vitest `it(...)`, wrap effect execution with `ManagedRuntime.runPromise(...)` when needed.
+11
-12
backend/src/api.ts
+11
-12
backend/src/api.ts
···
123
123
new AlbumNotFoundError({
124
124
message: "Album not found",
125
125
cause: e,
126
-
})
127
-
)
126
+
}),
127
+
),
128
128
);
129
129
130
130
yield* Effect.log(album);
···
200
200
artists,
201
201
musicbrainz: row.musicbrainz ?? undefined,
202
202
});
203
-
})
203
+
}),
204
204
);
205
205
206
206
return yield* Effect.all(result);
···
216
216
new FileNotFoundError({
217
217
message: `Failed to find file with id ${id}`,
218
218
cause: { id },
219
-
})
219
+
}),
220
220
);
221
221
}
222
222
···
230
230
new FileNotFoundError({
231
231
message: `File not found on disk: ${file.path}`,
232
232
cause: { id, path: file.path },
233
-
})
233
+
}),
234
234
);
235
235
}
236
236
237
237
const filename = file.path.split("/").pop();
238
238
const encodedFilename = encodeURIComponent(filename ?? "");
239
239
240
-
set.headers[
241
-
"Content-Disposition"
242
-
] = `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`;
240
+
set.headers["Content-Disposition"] =
241
+
`attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`;
243
242
set.headers["Content-Type"] = "audio/flac";
244
243
set.headers["Accept-Ranges"] = "bytes";
245
244
···
258
257
.innerJoin(albumTable, eq(songTable.albumId, albumTable.id))
259
258
.innerJoin(songToArtistTable, eq(songToArtistTable.songId, songTable.id))
260
259
.innerJoin(artistTable, eq(songToArtistTable.artistId, artistTable.id))
261
-
.all()
260
+
.all(),
262
261
);
263
262
264
263
const reduced = rows.reduce<Record<string, GetSongType>>((acc, row) => {
···
325
324
query: t.Object({
326
325
include: t.Optional(t.Array(t.String())),
327
326
}),
328
-
}
327
+
},
329
328
)
330
329
331
330
.get(
···
334
333
pipe(
335
334
ApiService.getFileById(id, set),
336
335
Effect.catchTag("FileNotFoundError", (e) => Effect.succeed(status(404, e.message))),
337
-
runtime.runPromise
336
+
runtime.runPromise,
338
337
),
339
338
{
340
339
params: t.Object({
341
340
id: t.String(),
342
341
}),
343
-
}
342
+
},
344
343
)
345
344
.get("/songs", () => pipe(ApiService.getAllSongs(), runtime.runPromise));
346
345
+1
-1
backend/src/db/index.ts
+1
-1
backend/src/db/index.ts
+5
-5
backend/src/file-parser.ts
+5
-5
backend/src/file-parser.ts
···
52
52
(metadata): ParseResult => ({
53
53
_tag: "success",
54
54
metadata,
55
-
})
55
+
}),
56
56
),
57
57
Effect.catchAll((err) =>
58
58
Effect.succeed<ParseResult>({
···
61
61
path: file,
62
62
error: err instanceof Error ? err.message : String(err),
63
63
},
64
-
})
65
-
)
64
+
}),
65
+
),
66
66
),
67
-
{ concurrency: 10 }
67
+
{ concurrency: 10 },
68
68
),
69
69
Stream.tap((result) => {
70
70
progress++;
···
79
79
return Console.log(`Progress: ${progress}/${total} (${((progress / total) * 100).toFixed(1)}%)`);
80
80
}
81
81
return Effect.void;
82
-
})
82
+
}),
83
83
);
84
84
85
85
return stream;
+4
-4
backend/src/index.ts
+4
-4
backend/src/index.ts
···
13
13
const AppLayer = Layer.merge(FlacService.Default, M4aService.Default).pipe(
14
14
Layer.provideMerge(DatabaseLive.Default),
15
15
Layer.provideMerge(BunContext.layer),
16
-
Layer.merge(OtelLive)
16
+
Layer.merge(OtelLive),
17
17
);
18
18
19
19
const SHUTDOWN_TIMEOUT_MS = 10_000;
···
50
50
Effect.gen(function* () {
51
51
yield* Effect.log(`Received ${signal}, starting graceful shutdown...`);
52
52
yield* Deferred.succeed(shutdownSignal, undefined);
53
-
}).pipe(Effect.provide(AppLayer))
53
+
}).pipe(Effect.provide(AppLayer)),
54
54
);
55
55
};
56
56
···
64
64
// Wrap with error handling so failures are logged and don't silently stop the repeat loop
65
65
const syncWithErrorHandling = syncLibraryStream(folderPath).pipe(
66
66
Effect.tapErrorCause((cause) =>
67
-
Effect.log(`Sync failed with cause: ${cause}`).pipe(Effect.annotateLogs("level", "error"))
67
+
Effect.log(`Sync failed with cause: ${cause}`).pipe(Effect.annotateLogs("level", "error")),
68
68
),
69
-
Effect.catchAllCause((cause) => Effect.log(`Sync run failed, will retry on next schedule. Cause: ${cause}`))
69
+
Effect.catchAllCause((cause) => Effect.log(`Sync run failed, will retry on next schedule. Cause: ${cause}`)),
70
70
);
71
71
72
72
const syncFiber = yield* Effect.fork(syncWithErrorHandling.pipe(Effect.repeat(Schedule.spaced("3 minutes"))));
+1
-1
backend/src/lib.ts
+1
-1
backend/src/lib.ts
+5
-5
backend/src/m4a/service.test.ts
+5
-5
backend/src/m4a/service.test.ts
···
16
16
const input = nonM4aFilePath;
17
17
const actual = yield* Effect.exit(m4aService.readMetadata(input));
18
18
expect(Exit.isFailure(actual)).toBe(true);
19
-
})
19
+
}),
20
20
));
21
21
22
22
it("readMetadata should NOT throw an error on a valid m4a file", () =>
···
26
26
const input = m4aFilePath;
27
27
const actual = yield* Effect.exit(m4aService.readMetadata(input));
28
28
expect(Exit.isSuccess(actual)).toBe(true);
29
-
})
29
+
}),
30
30
));
31
31
32
32
it("readMetadata should return album, artist and title", () =>
···
41
41
expect(actual.artists).toContain("Foster the People");
42
42
expect(actual.title).toBe("Downtown");
43
43
expect(actual.trackNumber).toBe(15);
44
-
})
44
+
}),
45
45
));
46
46
47
47
it("readMetadata should be able to parse musicbrainz tags", () =>
···
54
54
expect(actual.musicBrainzReleaseGroupId).toBe("535748f7-5b3d-4a2a-8f9c-bd8baa587239");
55
55
expect(actual.musicBrainzArtistId).toBe("e0e1a584-dd0a-4bd1-88d1-c4c62895039d");
56
56
expect(actual.musicBrainzTrackId).toBe("be8931c6-f360-41eb-8a19-1ca97342cdb4");
57
-
})
57
+
}),
58
58
));
59
59
60
60
const m4aFilePathNoMusicBrainz = "./test-data/no-musicbrainz.m4a";
···
68
68
expect(actual.musicBrainzReleaseGroupId).toBeUndefined();
69
69
expect(actual.musicBrainzArtistId).toBeUndefined();
70
70
expect(actual.musicBrainzTrackId).toBeUndefined();
71
-
})
71
+
}),
72
72
));
+1
-1
backend/src/m4a/service.ts
+1
-1
backend/src/m4a/service.ts
+1
-1
backend/src/m4a/transformers.ts
+1
-1
backend/src/m4a/transformers.ts
+5
-5
backend/test/flac.test.ts
+5
-5
backend/test/flac.test.ts
···
10
10
const inputNonFlac = "./test-data/01 - hover.mp3";
11
11
const actualNonFlac = yield* flacService.readMetadata(inputNonFlac).pipe(
12
12
Effect.as(true),
13
-
Effect.catchTag("FlacError", (_) => Effect.succeed(false))
13
+
Effect.catchTag("FlacError", (_) => Effect.succeed(false)),
14
14
);
15
15
16
16
expect(actualNonFlac).toBe(false);
17
-
}).pipe(provide)
17
+
}).pipe(provide),
18
18
);
19
19
20
20
test.effect("readMetadata should NOT error if file is FLAC", () =>
···
23
23
const input = "./test-data/11 - Tropical Fish.flac";
24
24
const actual = yield* flacService.readMetadata(input).pipe(
25
25
Effect.as(true),
26
-
Effect.catchTag("FlacError", (_) => Effect.succeed(false))
26
+
Effect.catchTag("FlacError", (_) => Effect.succeed(false)),
27
27
);
28
28
29
29
expect(actual).toBe(true);
30
-
}).pipe(provide)
30
+
}).pipe(provide),
31
31
);
32
32
33
33
test.effect("readMetadata should return album, artist and title", () =>
···
39
39
expect(actual.album).toContain("midnight cruisin");
40
40
expect(actual.album).toContain("MUGSHOT");
41
41
expect(actual).toHaveProperty("title", "TROPICAL FISH");
42
-
}).pipe(provide)
42
+
}).pipe(provide),
43
43
);
+2
-2
backend/vitest.config.ts
+2
-2
backend/vitest.config.ts
-38
bun.lock
-38
bun.lock
···
93
93
"zustand": "^5.0.8",
94
94
},
95
95
"devDependencies": {
96
-
"@prettier/plugin-oxc": "^0.0.4",
97
96
"@tanstack/eslint-config": "^0.3.0",
98
97
"@testing-library/dom": "^10.4.0",
99
98
"@testing-library/react": "^16.2.0",
···
103
102
"@vitejs/plugin-react": "^5.0.4",
104
103
"babel-plugin-react-compiler": "^1.0.0",
105
104
"jsdom": "^27.0.0",
106
-
"prettier": "^3.5.3",
107
105
"typescript": "^5.7.2",
108
106
"vite": "^7.1.7",
109
107
"vitest": "^3.0.5",
···
394
392
395
393
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.38.0", "", {}, "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg=="],
396
394
397
-
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.74.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lgq8TJq22eyfojfa2jBFy2m66ckAo7iNRYDdyn9reXYA3I6Wx7tgGWVx1JAp1lO+aUiqdqP/uPlDaETL9tqRcg=="],
398
-
399
-
"@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.74.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xbY/io/hkARggbpYEMFX6CwFzb7f4iS6WuBoBeZtdqRWfIEi7sm/uYWXfyVeB8uqOATvJ07WRFC2upI8PSI83g=="],
400
-
401
-
"@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.74.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-FIj2gAGtFaW0Zk+TnGyenMUoRu1ju+kJ/h71D77xc1owOItbFZFGa+4WSVck1H8rTtceeJlK+kux+vCjGFCl9Q=="],
402
-
403
-
"@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.74.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-W1I+g5TJg0TRRMHgEWNWsTIfe782V3QuaPgZxnfPNmDMywYdtlzllzclBgaDq6qzvZCCQc/UhvNb37KWTCTj8A=="],
404
-
405
-
"@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.74.0", "", { "os": "linux", "cpu": "arm" }, "sha512-gxqkyRGApeVI8dgvJ19SYe59XASW3uVxF1YUgkE7peW/XIg5QRAOVTFKyTjI9acYuK1MF6OJHqx30cmxmZLtiQ=="],
406
-
407
-
"@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.74.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jpnAUP4Fa93VdPPDzxxBguJmldj/Gpz7wTXKFzpAueqBMfZsy9KNC+0qT2uZ9HGUDMzNuKw0Se3bPCpL/gfD2Q=="],
408
-
409
-
"@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.74.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fcWyM7BNfCkHqIf3kll8fJctbR/PseL4RnS2isD9Y3FFBhp4efGAzhDaxIUK5GK7kIcFh1P+puIRig8WJ6IMVQ=="],
410
-
411
-
"@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.74.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AMY30z/C77HgiRRJX7YtVUaelKq1ex0aaj28XoJu4SCezdS8i0IftUNTtGS1UzGjGZB8zQz5SFwVy4dRu4GLwg=="],
412
-
413
-
"@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.74.0", "", { "os": "linux", "cpu": "none" }, "sha512-/RZAP24TgZo4vV/01TBlzRqs0R7E6xvatww4LnmZEBBulQBU/SkypDywfriFqWuFoa61WFXPV7sLcTjJGjim/w=="],
414
-
415
-
"@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.74.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-620J1beNAlGSPBD+Msb3ptvrwxu04B8iULCH03zlf0JSLy/5sqlD6qBs0XUVkUJv1vbakUw1gfVnUQqv0UTuEg=="],
416
-
417
-
"@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.74.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WBFgQmGtFnPNzHyLKbC1wkYGaRIBxXGofO0+hz1xrrkPgbxbJS1Ukva1EB8sPaVBBQ52Bdc2GjLSp721NWRvww=="],
418
-
419
-
"@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.74.0", "", { "os": "linux", "cpu": "x64" }, "sha512-y4mapxi0RGqlp3t6Sm+knJlAEqdKDYrEue2LlXOka/F2i4sRN0XhEMPiSOB3ppHmvK4I2zY2XBYTsX1Fel0fAg=="],
420
-
421
-
"@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.74.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-yDS9bRDh5ymobiS2xBmjlrGdUuU61IZoJBaJC5fELdYT5LJNBXlbr3Yc6m2PWfRJwkH6Aq5fRvxAZ4wCbkGa8w=="],
422
-
423
-
"@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.74.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-XFWY52Rfb4N5wEbMCTSBMxRkDLGbAI9CBSL24BIDywwDJMl31gHEVlmHdCDRoXAmanCI6gwbXYTrWe0HvXJ7Aw=="],
424
-
425
-
"@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.74.0", "", { "os": "win32", "cpu": "x64" }, "sha512-1D3x6iU2apLyfTQHygbdaNbX3nZaHu4yaXpD7ilYpoLo7f0MX0tUuoDrqJyJrVGqvyXgc0uz4yXz9tH9ZZhvvg=="],
426
-
427
-
"@oxc-project/types": ["@oxc-project/types@0.74.0", "", {}, "sha512-KOw/RZrVlHGhCXh1RufBFF7Nuo7HdY5w1lRJukM/igIl6x9qtz8QycDvZdzb4qnHO7znrPyo2sJrFJK2eKHgfQ=="],
428
-
429
395
"@oxfmt/darwin-arm64": ["@oxfmt/darwin-arm64@0.16.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-I+Unj7wePcUTK7p/YKtgbm4yer6dw7dTlmCJa0UilFZyge5uD4rwCSfSDx3A+a6Z3A60/SqXMbNR2UyidWF4Cg=="],
430
396
431
397
"@oxfmt/darwin-x64": ["@oxfmt/darwin-x64@0.16.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-EfiXFKEOV5gXgEatFK89OOoSmd8E9Xq83TcjPLWQNFBO4cgaQsfKmctpgJmJjQnoUwD7nQsm0ruj3ae7Gva8QA=="],
···
485
451
"@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="],
486
452
487
453
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
488
-
489
-
"@prettier/plugin-oxc": ["@prettier/plugin-oxc@0.0.4", "", { "dependencies": { "oxc-parser": "0.74.0" } }, "sha512-UGXe+g/rSRbglL0FOJiar+a+nUrst7KaFmsg05wYbKiInGWP6eAj/f8A2Uobgo5KxEtb2X10zeflNH6RK2xeIQ=="],
490
454
491
455
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
492
456
···
1307
1271
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
1308
1272
1309
1273
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
1310
-
1311
-
"oxc-parser": ["oxc-parser@0.74.0", "", { "dependencies": { "@oxc-project/types": "^0.74.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm64": "0.74.0", "@oxc-parser/binding-darwin-arm64": "0.74.0", "@oxc-parser/binding-darwin-x64": "0.74.0", "@oxc-parser/binding-freebsd-x64": "0.74.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.74.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.74.0", "@oxc-parser/binding-linux-arm64-gnu": "0.74.0", "@oxc-parser/binding-linux-arm64-musl": "0.74.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.74.0", "@oxc-parser/binding-linux-s390x-gnu": "0.74.0", "@oxc-parser/binding-linux-x64-gnu": "0.74.0", "@oxc-parser/binding-linux-x64-musl": "0.74.0", "@oxc-parser/binding-wasm32-wasi": "0.74.0", "@oxc-parser/binding-win32-arm64-msvc": "0.74.0", "@oxc-parser/binding-win32-x64-msvc": "0.74.0" } }, "sha512-2tDN/ttU8WE6oFh8EzKNam7KE7ZXSG5uXmvX85iNzxdJfMssDWcj3gpYzZi1E04XuE7m3v1dVWl/8BE886vPGw=="],
1312
1274
1313
1275
"oxfmt": ["oxfmt@0.16.0", "", { "optionalDependencies": { "@oxfmt/darwin-arm64": "0.16.0", "@oxfmt/darwin-x64": "0.16.0", "@oxfmt/linux-arm64-gnu": "0.16.0", "@oxfmt/linux-arm64-musl": "0.16.0", "@oxfmt/linux-x64-gnu": "0.16.0", "@oxfmt/linux-x64-musl": "0.16.0", "@oxfmt/win32-arm64": "0.16.0", "@oxfmt/win32-x64": "0.16.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-uRnnBAN0zH07FXSfvSKbIw+Jrohv4Px2RwNiZOGI4/pvns4sx0+k4WSt+tqwd7bDeoWaXiGmhZgnbK63hi6hVQ=="],
1314
1276
+2
-1
package.json
+2
-1
package.json
···
9
9
"scripts": {
10
10
"dev": "bun --filter '*' dev",
11
11
"db:migrate": "bun --filter @boombox/backend db:migrate",
12
-
"db:gen": "bun --filter @boombox/backend db:gen"
12
+
"db:gen": "bun --filter @boombox/backend db:gen",
13
+
"format": "bunx oxfmt ."
13
14
},
14
15
"devDependencies": {
15
16
"oxfmt": "^0.16.0"
+1
-1
vitest.config.js
+1
-1
vitest.config.js
-11
web/.prettierrc.toml
-11
web/.prettierrc.toml
+131
web/AGENTS.md
+131
web/AGENTS.md
···
1
+
# Web Agent Guide (`web-tanstack`)
2
+
3
+
This workspace is a **Vite + TanStack Start (React)** app with Tailwind + shadcn/ui.
4
+
5
+
If you haven’t yet, read the repo entrypoint first: `../AGENTS.md`.
6
+
7
+
## Commands (run from `web/`)
8
+
9
+
- **Dev**: `bun run dev`
10
+
- Runs `vite dev --port 3000`
11
+
- **Build**: `bun run build`
12
+
- Runs `vite build`
13
+
- **Preview**: `bun run serve`
14
+
- Runs `vite preview`
15
+
- **Test**: `bun run test`
16
+
- Runs `vitest run`
17
+
- **Lint**: `bun run lint`
18
+
- Runs `eslint` (TanStack ESLint config)
19
+
- **Format**: `bun run format`
20
+
- Runs `oxfmt .`
21
+
- **Format + lint fix**: `bun run check`
22
+
- Runs `oxfmt . && eslint --fix`
23
+
24
+
### Single test execution (Vitest)
25
+
26
+
- **Single file**: `bun run test -- src/**/some.test.ts`
27
+
- **By name**: `bun run test -- -t "renders"`
28
+
- **Watch mode**: `bunx vitest`
29
+
30
+
## Project map
31
+
32
+
- **`src/routes/`**: file-based routing (TanStack Router)
33
+
- `__root.tsx`: root document shell (Head, Scripts, devtools, global UI like `AudioPlayer`)
34
+
- `index.tsx`: starter homepage (can be replaced)
35
+
- `album/*`: album pages
36
+
- **`src/router.tsx`**: router creation + SSR query integration wrapper
37
+
- **`src/integrations/tanstack-query/`**: query client/provider integration
38
+
- **`src/components/`**: app components
39
+
- `components/ui/`: shadcn/ui components (do not hand-edit unless needed)
40
+
- `components/player/`: audio player UI
41
+
- **`src/lib/`**: shared web utilities (API client, errors, utils)
42
+
- **`src/store/`**: global state (currently Zustand)
43
+
44
+
## Imports, TypeScript, and formatting
45
+
46
+
### Imports
47
+
48
+
- Use the **`@/*`** alias for `src/*` (configured in `web/tsconfig.json`).
49
+
- Prefer `import type { ... }` for type-only imports (important when importing backend types).
50
+
- Avoid barrel files; import from the exact module.
51
+
52
+
### TypeScript expectations
53
+
54
+
- `"strict": true` and unused checks are enabled (`noUnusedLocals`, `noUnusedParameters`).
55
+
- Prefer explicit return types for exported functions when it clarifies behavior.
56
+
- Use `effect/Schema` when you need runtime validation on untrusted data.
57
+
58
+
### Formatting rules
59
+
60
+
Uses oxfmt (Oxc formatter):
61
+
62
+
- tabs, `tabWidth = 4`
63
+
- `printWidth = 120`
64
+
- semicolons enabled
65
+
66
+
## UI + styling rules
67
+
68
+
### Tailwind
69
+
70
+
- Tailwind is the primary styling system. Prefer utility classes over bespoke CSS.
71
+
- Shared CSS entry is `src/styles.css`.
72
+
73
+
### shadcn/ui
74
+
75
+
- UI primitives are under `src/components/ui/` and are typically managed by the shadcn CLI.
76
+
- Repo Cursor rule: `web/.cursorrules` says to add new components with:
77
+
- `pnpx shadcn@latest add <component>`
78
+
79
+
Even though the repo is Bun-first, follow that shadcn instruction when installing shadcn components (it matches shadcn’s documented workflow).
80
+
81
+
## Data fetching & API integration
82
+
83
+
### Typed backend client (Elysia Eden)
84
+
85
+
The web client is typed against the backend’s Elysia server type:
86
+
87
+
- `src/lib/api.ts` exports `client = treaty<ApiType>("localhost:3003")`
88
+
89
+
Guidelines:
90
+
91
+
- Keep backend type imports as `type` imports.
92
+
- Don’t hardcode fetch URLs in multiple places; route everything through the `client` (or a small wrapper in `src/lib/`).
93
+
- If you change backend routes/response shapes, update the web usage in the same PR.
94
+
95
+
### TanStack Query + Router integration
96
+
97
+
- Router is created in `src/router.tsx`.
98
+
- Query integration lives in `src/integrations/tanstack-query/`.
99
+
- Prefer loaders / query hooks where TanStack Start expects them; keep side effects inside effects/hooks.
100
+
101
+
## State management (Zustand)
102
+
103
+
The app currently uses Zustand (not Jotai) for global state:
104
+
105
+
- Example: `src/store/player.ts` uses `persist` middleware to store volume in localStorage.
106
+
107
+
Guidelines:
108
+
109
+
- Keep stores small and domain-focused (one store per concern).
110
+
- Prefer derived selectors in components rather than storing redundant computed state.
111
+
112
+
## Error handling
113
+
114
+
### Prefer typed errors for domain failures
115
+
116
+
The web workspace already defines Effect tagged errors in `src/lib/errors.ts`.
117
+
118
+
- When modeling a failure that you intend to handle, prefer `Data.TaggedError("...")<{ ... }>`
119
+
- When calling async functions, fail early with a typed error and surface it at the component boundary.
120
+
121
+
### UI surfacing
122
+
123
+
- For user-visible errors, prefer a clear empty state + retry action.
124
+
- For dev-only errors, console logging is OK, but don’t ship noisy logs in hot paths.
125
+
126
+
## Testing guidance
127
+
128
+
Vitest is set up for the workspace.
129
+
130
+
- Prefer Testing Library for component tests (`@testing-library/react` is installed).
131
+
- For pure utilities, write plain unit tests under `src/**/__tests__` or alongside the module.
+2
-4
web/package.json
+2
-4
web/package.json
···
8
8
"serve": "vite preview",
9
9
"test": "vitest run",
10
10
"lint": "eslint",
11
-
"format": "prettier",
12
-
"check": "prettier --write . && eslint --fix"
11
+
"format": "bunx oxfmt .",
12
+
"check": "bunx oxfmt . && eslint --fix"
13
13
},
14
14
"dependencies": {
15
15
"@elysiajs/eden": "^1.4.4",
···
42
42
"zustand": "^5.0.8"
43
43
},
44
44
"devDependencies": {
45
-
"@prettier/plugin-oxc": "^0.0.4",
46
45
"@tanstack/eslint-config": "^0.3.0",
47
46
"@testing-library/dom": "^10.4.0",
48
47
"@testing-library/react": "^16.2.0",
···
52
51
"@vitejs/plugin-react": "^5.0.4",
53
52
"babel-plugin-react-compiler": "^1.0.0",
54
53
"jsdom": "^27.0.0",
55
-
"prettier": "^3.5.3",
56
54
"typescript": "^5.7.2",
57
55
"vite": "^7.1.7",
58
56
"vitest": "^3.0.5",
+321
-323
web/src/routeTree.gen.ts
+321
-323
web/src/routeTree.gen.ts
···
8
8
// You should NOT make any changes in this file as it will be overwritten.
9
9
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
10
11
-
import { Route as rootRouteImport } from './routes/__root'
12
-
import { Route as McpRouteImport } from './routes/mcp'
13
-
import { Route as IndexRouteImport } from './routes/index'
14
-
import { Route as AlbumIndexRouteImport } from './routes/album/index'
15
-
import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query'
16
-
import { Route as DemoMcpTodosRouteImport } from './routes/demo/mcp-todos'
17
-
import { Route as AlbumAlbumIdRouteImport } from './routes/album/$albumId'
18
-
import { Route as DemoStartServerFuncsRouteImport } from './routes/demo/start.server-funcs'
19
-
import { Route as DemoStartApiRequestRouteImport } from './routes/demo/start.api-request'
20
-
import { Route as DemoApiTqTodosRouteImport } from './routes/demo/api.tq-todos'
21
-
import { Route as DemoApiNamesRouteImport } from './routes/demo/api.names'
22
-
import { Route as DemoApiMcpTodosRouteImport } from './routes/demo/api.mcp-todos'
23
-
import { Route as DemoStartSsrIndexRouteImport } from './routes/demo/start.ssr.index'
24
-
import { Route as DemoStartSsrSpaModeRouteImport } from './routes/demo/start.ssr.spa-mode'
25
-
import { Route as DemoStartSsrFullSsrRouteImport } from './routes/demo/start.ssr.full-ssr'
26
-
import { Route as DemoStartSsrDataOnlyRouteImport } from './routes/demo/start.ssr.data-only'
11
+
import { Route as rootRouteImport } from "./routes/__root";
12
+
import { Route as McpRouteImport } from "./routes/mcp";
13
+
import { Route as IndexRouteImport } from "./routes/index";
14
+
import { Route as AlbumIndexRouteImport } from "./routes/album/index";
15
+
import { Route as DemoTanstackQueryRouteImport } from "./routes/demo/tanstack-query";
16
+
import { Route as DemoMcpTodosRouteImport } from "./routes/demo/mcp-todos";
17
+
import { Route as AlbumAlbumIdRouteImport } from "./routes/album/$albumId";
18
+
import { Route as DemoStartServerFuncsRouteImport } from "./routes/demo/start.server-funcs";
19
+
import { Route as DemoStartApiRequestRouteImport } from "./routes/demo/start.api-request";
20
+
import { Route as DemoApiTqTodosRouteImport } from "./routes/demo/api.tq-todos";
21
+
import { Route as DemoApiNamesRouteImport } from "./routes/demo/api.names";
22
+
import { Route as DemoApiMcpTodosRouteImport } from "./routes/demo/api.mcp-todos";
23
+
import { Route as DemoStartSsrIndexRouteImport } from "./routes/demo/start.ssr.index";
24
+
import { Route as DemoStartSsrSpaModeRouteImport } from "./routes/demo/start.ssr.spa-mode";
25
+
import { Route as DemoStartSsrFullSsrRouteImport } from "./routes/demo/start.ssr.full-ssr";
26
+
import { Route as DemoStartSsrDataOnlyRouteImport } from "./routes/demo/start.ssr.data-only";
27
27
28
28
const McpRoute = McpRouteImport.update({
29
-
id: '/mcp',
30
-
path: '/mcp',
31
-
getParentRoute: () => rootRouteImport,
32
-
} as any)
29
+
id: "/mcp",
30
+
path: "/mcp",
31
+
getParentRoute: () => rootRouteImport,
32
+
} as any);
33
33
const IndexRoute = IndexRouteImport.update({
34
-
id: '/',
35
-
path: '/',
36
-
getParentRoute: () => rootRouteImport,
37
-
} as any)
34
+
id: "/",
35
+
path: "/",
36
+
getParentRoute: () => rootRouteImport,
37
+
} as any);
38
38
const AlbumIndexRoute = AlbumIndexRouteImport.update({
39
-
id: '/album/',
40
-
path: '/album/',
41
-
getParentRoute: () => rootRouteImport,
42
-
} as any)
39
+
id: "/album/",
40
+
path: "/album/",
41
+
getParentRoute: () => rootRouteImport,
42
+
} as any);
43
43
const DemoTanstackQueryRoute = DemoTanstackQueryRouteImport.update({
44
-
id: '/demo/tanstack-query',
45
-
path: '/demo/tanstack-query',
46
-
getParentRoute: () => rootRouteImport,
47
-
} as any)
44
+
id: "/demo/tanstack-query",
45
+
path: "/demo/tanstack-query",
46
+
getParentRoute: () => rootRouteImport,
47
+
} as any);
48
48
const DemoMcpTodosRoute = DemoMcpTodosRouteImport.update({
49
-
id: '/demo/mcp-todos',
50
-
path: '/demo/mcp-todos',
51
-
getParentRoute: () => rootRouteImport,
52
-
} as any)
49
+
id: "/demo/mcp-todos",
50
+
path: "/demo/mcp-todos",
51
+
getParentRoute: () => rootRouteImport,
52
+
} as any);
53
53
const AlbumAlbumIdRoute = AlbumAlbumIdRouteImport.update({
54
-
id: '/album/$albumId',
55
-
path: '/album/$albumId',
56
-
getParentRoute: () => rootRouteImport,
57
-
} as any)
54
+
id: "/album/$albumId",
55
+
path: "/album/$albumId",
56
+
getParentRoute: () => rootRouteImport,
57
+
} as any);
58
58
const DemoStartServerFuncsRoute = DemoStartServerFuncsRouteImport.update({
59
-
id: '/demo/start/server-funcs',
60
-
path: '/demo/start/server-funcs',
61
-
getParentRoute: () => rootRouteImport,
62
-
} as any)
59
+
id: "/demo/start/server-funcs",
60
+
path: "/demo/start/server-funcs",
61
+
getParentRoute: () => rootRouteImport,
62
+
} as any);
63
63
const DemoStartApiRequestRoute = DemoStartApiRequestRouteImport.update({
64
-
id: '/demo/start/api-request',
65
-
path: '/demo/start/api-request',
66
-
getParentRoute: () => rootRouteImport,
67
-
} as any)
64
+
id: "/demo/start/api-request",
65
+
path: "/demo/start/api-request",
66
+
getParentRoute: () => rootRouteImport,
67
+
} as any);
68
68
const DemoApiTqTodosRoute = DemoApiTqTodosRouteImport.update({
69
-
id: '/demo/api/tq-todos',
70
-
path: '/demo/api/tq-todos',
71
-
getParentRoute: () => rootRouteImport,
72
-
} as any)
69
+
id: "/demo/api/tq-todos",
70
+
path: "/demo/api/tq-todos",
71
+
getParentRoute: () => rootRouteImport,
72
+
} as any);
73
73
const DemoApiNamesRoute = DemoApiNamesRouteImport.update({
74
-
id: '/demo/api/names',
75
-
path: '/demo/api/names',
76
-
getParentRoute: () => rootRouteImport,
77
-
} as any)
74
+
id: "/demo/api/names",
75
+
path: "/demo/api/names",
76
+
getParentRoute: () => rootRouteImport,
77
+
} as any);
78
78
const DemoApiMcpTodosRoute = DemoApiMcpTodosRouteImport.update({
79
-
id: '/demo/api/mcp-todos',
80
-
path: '/demo/api/mcp-todos',
81
-
getParentRoute: () => rootRouteImport,
82
-
} as any)
79
+
id: "/demo/api/mcp-todos",
80
+
path: "/demo/api/mcp-todos",
81
+
getParentRoute: () => rootRouteImport,
82
+
} as any);
83
83
const DemoStartSsrIndexRoute = DemoStartSsrIndexRouteImport.update({
84
-
id: '/demo/start/ssr/',
85
-
path: '/demo/start/ssr/',
86
-
getParentRoute: () => rootRouteImport,
87
-
} as any)
84
+
id: "/demo/start/ssr/",
85
+
path: "/demo/start/ssr/",
86
+
getParentRoute: () => rootRouteImport,
87
+
} as any);
88
88
const DemoStartSsrSpaModeRoute = DemoStartSsrSpaModeRouteImport.update({
89
-
id: '/demo/start/ssr/spa-mode',
90
-
path: '/demo/start/ssr/spa-mode',
91
-
getParentRoute: () => rootRouteImport,
92
-
} as any)
89
+
id: "/demo/start/ssr/spa-mode",
90
+
path: "/demo/start/ssr/spa-mode",
91
+
getParentRoute: () => rootRouteImport,
92
+
} as any);
93
93
const DemoStartSsrFullSsrRoute = DemoStartSsrFullSsrRouteImport.update({
94
-
id: '/demo/start/ssr/full-ssr',
95
-
path: '/demo/start/ssr/full-ssr',
96
-
getParentRoute: () => rootRouteImport,
97
-
} as any)
94
+
id: "/demo/start/ssr/full-ssr",
95
+
path: "/demo/start/ssr/full-ssr",
96
+
getParentRoute: () => rootRouteImport,
97
+
} as any);
98
98
const DemoStartSsrDataOnlyRoute = DemoStartSsrDataOnlyRouteImport.update({
99
-
id: '/demo/start/ssr/data-only',
100
-
path: '/demo/start/ssr/data-only',
101
-
getParentRoute: () => rootRouteImport,
102
-
} as any)
99
+
id: "/demo/start/ssr/data-only",
100
+
path: "/demo/start/ssr/data-only",
101
+
getParentRoute: () => rootRouteImport,
102
+
} as any);
103
103
104
104
export interface FileRoutesByFullPath {
105
-
'/': typeof IndexRoute
106
-
'/mcp': typeof McpRoute
107
-
'/album/$albumId': typeof AlbumAlbumIdRoute
108
-
'/demo/mcp-todos': typeof DemoMcpTodosRoute
109
-
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
110
-
'/album': typeof AlbumIndexRoute
111
-
'/demo/api/mcp-todos': typeof DemoApiMcpTodosRoute
112
-
'/demo/api/names': typeof DemoApiNamesRoute
113
-
'/demo/api/tq-todos': typeof DemoApiTqTodosRoute
114
-
'/demo/start/api-request': typeof DemoStartApiRequestRoute
115
-
'/demo/start/server-funcs': typeof DemoStartServerFuncsRoute
116
-
'/demo/start/ssr/data-only': typeof DemoStartSsrDataOnlyRoute
117
-
'/demo/start/ssr/full-ssr': typeof DemoStartSsrFullSsrRoute
118
-
'/demo/start/ssr/spa-mode': typeof DemoStartSsrSpaModeRoute
119
-
'/demo/start/ssr': typeof DemoStartSsrIndexRoute
105
+
"/": typeof IndexRoute;
106
+
"/mcp": typeof McpRoute;
107
+
"/album/$albumId": typeof AlbumAlbumIdRoute;
108
+
"/demo/mcp-todos": typeof DemoMcpTodosRoute;
109
+
"/demo/tanstack-query": typeof DemoTanstackQueryRoute;
110
+
"/album": typeof AlbumIndexRoute;
111
+
"/demo/api/mcp-todos": typeof DemoApiMcpTodosRoute;
112
+
"/demo/api/names": typeof DemoApiNamesRoute;
113
+
"/demo/api/tq-todos": typeof DemoApiTqTodosRoute;
114
+
"/demo/start/api-request": typeof DemoStartApiRequestRoute;
115
+
"/demo/start/server-funcs": typeof DemoStartServerFuncsRoute;
116
+
"/demo/start/ssr/data-only": typeof DemoStartSsrDataOnlyRoute;
117
+
"/demo/start/ssr/full-ssr": typeof DemoStartSsrFullSsrRoute;
118
+
"/demo/start/ssr/spa-mode": typeof DemoStartSsrSpaModeRoute;
119
+
"/demo/start/ssr": typeof DemoStartSsrIndexRoute;
120
120
}
121
121
export interface FileRoutesByTo {
122
-
'/': typeof IndexRoute
123
-
'/mcp': typeof McpRoute
124
-
'/album/$albumId': typeof AlbumAlbumIdRoute
125
-
'/demo/mcp-todos': typeof DemoMcpTodosRoute
126
-
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
127
-
'/album': typeof AlbumIndexRoute
128
-
'/demo/api/mcp-todos': typeof DemoApiMcpTodosRoute
129
-
'/demo/api/names': typeof DemoApiNamesRoute
130
-
'/demo/api/tq-todos': typeof DemoApiTqTodosRoute
131
-
'/demo/start/api-request': typeof DemoStartApiRequestRoute
132
-
'/demo/start/server-funcs': typeof DemoStartServerFuncsRoute
133
-
'/demo/start/ssr/data-only': typeof DemoStartSsrDataOnlyRoute
134
-
'/demo/start/ssr/full-ssr': typeof DemoStartSsrFullSsrRoute
135
-
'/demo/start/ssr/spa-mode': typeof DemoStartSsrSpaModeRoute
136
-
'/demo/start/ssr': typeof DemoStartSsrIndexRoute
122
+
"/": typeof IndexRoute;
123
+
"/mcp": typeof McpRoute;
124
+
"/album/$albumId": typeof AlbumAlbumIdRoute;
125
+
"/demo/mcp-todos": typeof DemoMcpTodosRoute;
126
+
"/demo/tanstack-query": typeof DemoTanstackQueryRoute;
127
+
"/album": typeof AlbumIndexRoute;
128
+
"/demo/api/mcp-todos": typeof DemoApiMcpTodosRoute;
129
+
"/demo/api/names": typeof DemoApiNamesRoute;
130
+
"/demo/api/tq-todos": typeof DemoApiTqTodosRoute;
131
+
"/demo/start/api-request": typeof DemoStartApiRequestRoute;
132
+
"/demo/start/server-funcs": typeof DemoStartServerFuncsRoute;
133
+
"/demo/start/ssr/data-only": typeof DemoStartSsrDataOnlyRoute;
134
+
"/demo/start/ssr/full-ssr": typeof DemoStartSsrFullSsrRoute;
135
+
"/demo/start/ssr/spa-mode": typeof DemoStartSsrSpaModeRoute;
136
+
"/demo/start/ssr": typeof DemoStartSsrIndexRoute;
137
137
}
138
138
export interface FileRoutesById {
139
-
__root__: typeof rootRouteImport
140
-
'/': typeof IndexRoute
141
-
'/mcp': typeof McpRoute
142
-
'/album/$albumId': typeof AlbumAlbumIdRoute
143
-
'/demo/mcp-todos': typeof DemoMcpTodosRoute
144
-
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
145
-
'/album/': typeof AlbumIndexRoute
146
-
'/demo/api/mcp-todos': typeof DemoApiMcpTodosRoute
147
-
'/demo/api/names': typeof DemoApiNamesRoute
148
-
'/demo/api/tq-todos': typeof DemoApiTqTodosRoute
149
-
'/demo/start/api-request': typeof DemoStartApiRequestRoute
150
-
'/demo/start/server-funcs': typeof DemoStartServerFuncsRoute
151
-
'/demo/start/ssr/data-only': typeof DemoStartSsrDataOnlyRoute
152
-
'/demo/start/ssr/full-ssr': typeof DemoStartSsrFullSsrRoute
153
-
'/demo/start/ssr/spa-mode': typeof DemoStartSsrSpaModeRoute
154
-
'/demo/start/ssr/': typeof DemoStartSsrIndexRoute
139
+
__root__: typeof rootRouteImport;
140
+
"/": typeof IndexRoute;
141
+
"/mcp": typeof McpRoute;
142
+
"/album/$albumId": typeof AlbumAlbumIdRoute;
143
+
"/demo/mcp-todos": typeof DemoMcpTodosRoute;
144
+
"/demo/tanstack-query": typeof DemoTanstackQueryRoute;
145
+
"/album/": typeof AlbumIndexRoute;
146
+
"/demo/api/mcp-todos": typeof DemoApiMcpTodosRoute;
147
+
"/demo/api/names": typeof DemoApiNamesRoute;
148
+
"/demo/api/tq-todos": typeof DemoApiTqTodosRoute;
149
+
"/demo/start/api-request": typeof DemoStartApiRequestRoute;
150
+
"/demo/start/server-funcs": typeof DemoStartServerFuncsRoute;
151
+
"/demo/start/ssr/data-only": typeof DemoStartSsrDataOnlyRoute;
152
+
"/demo/start/ssr/full-ssr": typeof DemoStartSsrFullSsrRoute;
153
+
"/demo/start/ssr/spa-mode": typeof DemoStartSsrSpaModeRoute;
154
+
"/demo/start/ssr/": typeof DemoStartSsrIndexRoute;
155
155
}
156
156
export interface FileRouteTypes {
157
-
fileRoutesByFullPath: FileRoutesByFullPath
158
-
fullPaths:
159
-
| '/'
160
-
| '/mcp'
161
-
| '/album/$albumId'
162
-
| '/demo/mcp-todos'
163
-
| '/demo/tanstack-query'
164
-
| '/album'
165
-
| '/demo/api/mcp-todos'
166
-
| '/demo/api/names'
167
-
| '/demo/api/tq-todos'
168
-
| '/demo/start/api-request'
169
-
| '/demo/start/server-funcs'
170
-
| '/demo/start/ssr/data-only'
171
-
| '/demo/start/ssr/full-ssr'
172
-
| '/demo/start/ssr/spa-mode'
173
-
| '/demo/start/ssr'
174
-
fileRoutesByTo: FileRoutesByTo
175
-
to:
176
-
| '/'
177
-
| '/mcp'
178
-
| '/album/$albumId'
179
-
| '/demo/mcp-todos'
180
-
| '/demo/tanstack-query'
181
-
| '/album'
182
-
| '/demo/api/mcp-todos'
183
-
| '/demo/api/names'
184
-
| '/demo/api/tq-todos'
185
-
| '/demo/start/api-request'
186
-
| '/demo/start/server-funcs'
187
-
| '/demo/start/ssr/data-only'
188
-
| '/demo/start/ssr/full-ssr'
189
-
| '/demo/start/ssr/spa-mode'
190
-
| '/demo/start/ssr'
191
-
id:
192
-
| '__root__'
193
-
| '/'
194
-
| '/mcp'
195
-
| '/album/$albumId'
196
-
| '/demo/mcp-todos'
197
-
| '/demo/tanstack-query'
198
-
| '/album/'
199
-
| '/demo/api/mcp-todos'
200
-
| '/demo/api/names'
201
-
| '/demo/api/tq-todos'
202
-
| '/demo/start/api-request'
203
-
| '/demo/start/server-funcs'
204
-
| '/demo/start/ssr/data-only'
205
-
| '/demo/start/ssr/full-ssr'
206
-
| '/demo/start/ssr/spa-mode'
207
-
| '/demo/start/ssr/'
208
-
fileRoutesById: FileRoutesById
157
+
fileRoutesByFullPath: FileRoutesByFullPath;
158
+
fullPaths:
159
+
| "/"
160
+
| "/mcp"
161
+
| "/album/$albumId"
162
+
| "/demo/mcp-todos"
163
+
| "/demo/tanstack-query"
164
+
| "/album"
165
+
| "/demo/api/mcp-todos"
166
+
| "/demo/api/names"
167
+
| "/demo/api/tq-todos"
168
+
| "/demo/start/api-request"
169
+
| "/demo/start/server-funcs"
170
+
| "/demo/start/ssr/data-only"
171
+
| "/demo/start/ssr/full-ssr"
172
+
| "/demo/start/ssr/spa-mode"
173
+
| "/demo/start/ssr";
174
+
fileRoutesByTo: FileRoutesByTo;
175
+
to:
176
+
| "/"
177
+
| "/mcp"
178
+
| "/album/$albumId"
179
+
| "/demo/mcp-todos"
180
+
| "/demo/tanstack-query"
181
+
| "/album"
182
+
| "/demo/api/mcp-todos"
183
+
| "/demo/api/names"
184
+
| "/demo/api/tq-todos"
185
+
| "/demo/start/api-request"
186
+
| "/demo/start/server-funcs"
187
+
| "/demo/start/ssr/data-only"
188
+
| "/demo/start/ssr/full-ssr"
189
+
| "/demo/start/ssr/spa-mode"
190
+
| "/demo/start/ssr";
191
+
id:
192
+
| "__root__"
193
+
| "/"
194
+
| "/mcp"
195
+
| "/album/$albumId"
196
+
| "/demo/mcp-todos"
197
+
| "/demo/tanstack-query"
198
+
| "/album/"
199
+
| "/demo/api/mcp-todos"
200
+
| "/demo/api/names"
201
+
| "/demo/api/tq-todos"
202
+
| "/demo/start/api-request"
203
+
| "/demo/start/server-funcs"
204
+
| "/demo/start/ssr/data-only"
205
+
| "/demo/start/ssr/full-ssr"
206
+
| "/demo/start/ssr/spa-mode"
207
+
| "/demo/start/ssr/";
208
+
fileRoutesById: FileRoutesById;
209
209
}
210
210
export interface RootRouteChildren {
211
-
IndexRoute: typeof IndexRoute
212
-
McpRoute: typeof McpRoute
213
-
AlbumAlbumIdRoute: typeof AlbumAlbumIdRoute
214
-
DemoMcpTodosRoute: typeof DemoMcpTodosRoute
215
-
DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute
216
-
AlbumIndexRoute: typeof AlbumIndexRoute
217
-
DemoApiMcpTodosRoute: typeof DemoApiMcpTodosRoute
218
-
DemoApiNamesRoute: typeof DemoApiNamesRoute
219
-
DemoApiTqTodosRoute: typeof DemoApiTqTodosRoute
220
-
DemoStartApiRequestRoute: typeof DemoStartApiRequestRoute
221
-
DemoStartServerFuncsRoute: typeof DemoStartServerFuncsRoute
222
-
DemoStartSsrDataOnlyRoute: typeof DemoStartSsrDataOnlyRoute
223
-
DemoStartSsrFullSsrRoute: typeof DemoStartSsrFullSsrRoute
224
-
DemoStartSsrSpaModeRoute: typeof DemoStartSsrSpaModeRoute
225
-
DemoStartSsrIndexRoute: typeof DemoStartSsrIndexRoute
211
+
IndexRoute: typeof IndexRoute;
212
+
McpRoute: typeof McpRoute;
213
+
AlbumAlbumIdRoute: typeof AlbumAlbumIdRoute;
214
+
DemoMcpTodosRoute: typeof DemoMcpTodosRoute;
215
+
DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute;
216
+
AlbumIndexRoute: typeof AlbumIndexRoute;
217
+
DemoApiMcpTodosRoute: typeof DemoApiMcpTodosRoute;
218
+
DemoApiNamesRoute: typeof DemoApiNamesRoute;
219
+
DemoApiTqTodosRoute: typeof DemoApiTqTodosRoute;
220
+
DemoStartApiRequestRoute: typeof DemoStartApiRequestRoute;
221
+
DemoStartServerFuncsRoute: typeof DemoStartServerFuncsRoute;
222
+
DemoStartSsrDataOnlyRoute: typeof DemoStartSsrDataOnlyRoute;
223
+
DemoStartSsrFullSsrRoute: typeof DemoStartSsrFullSsrRoute;
224
+
DemoStartSsrSpaModeRoute: typeof DemoStartSsrSpaModeRoute;
225
+
DemoStartSsrIndexRoute: typeof DemoStartSsrIndexRoute;
226
226
}
227
227
228
-
declare module '@tanstack/react-router' {
229
-
interface FileRoutesByPath {
230
-
'/mcp': {
231
-
id: '/mcp'
232
-
path: '/mcp'
233
-
fullPath: '/mcp'
234
-
preLoaderRoute: typeof McpRouteImport
235
-
parentRoute: typeof rootRouteImport
236
-
}
237
-
'/': {
238
-
id: '/'
239
-
path: '/'
240
-
fullPath: '/'
241
-
preLoaderRoute: typeof IndexRouteImport
242
-
parentRoute: typeof rootRouteImport
243
-
}
244
-
'/album/': {
245
-
id: '/album/'
246
-
path: '/album'
247
-
fullPath: '/album'
248
-
preLoaderRoute: typeof AlbumIndexRouteImport
249
-
parentRoute: typeof rootRouteImport
250
-
}
251
-
'/demo/tanstack-query': {
252
-
id: '/demo/tanstack-query'
253
-
path: '/demo/tanstack-query'
254
-
fullPath: '/demo/tanstack-query'
255
-
preLoaderRoute: typeof DemoTanstackQueryRouteImport
256
-
parentRoute: typeof rootRouteImport
257
-
}
258
-
'/demo/mcp-todos': {
259
-
id: '/demo/mcp-todos'
260
-
path: '/demo/mcp-todos'
261
-
fullPath: '/demo/mcp-todos'
262
-
preLoaderRoute: typeof DemoMcpTodosRouteImport
263
-
parentRoute: typeof rootRouteImport
264
-
}
265
-
'/album/$albumId': {
266
-
id: '/album/$albumId'
267
-
path: '/album/$albumId'
268
-
fullPath: '/album/$albumId'
269
-
preLoaderRoute: typeof AlbumAlbumIdRouteImport
270
-
parentRoute: typeof rootRouteImport
271
-
}
272
-
'/demo/start/server-funcs': {
273
-
id: '/demo/start/server-funcs'
274
-
path: '/demo/start/server-funcs'
275
-
fullPath: '/demo/start/server-funcs'
276
-
preLoaderRoute: typeof DemoStartServerFuncsRouteImport
277
-
parentRoute: typeof rootRouteImport
278
-
}
279
-
'/demo/start/api-request': {
280
-
id: '/demo/start/api-request'
281
-
path: '/demo/start/api-request'
282
-
fullPath: '/demo/start/api-request'
283
-
preLoaderRoute: typeof DemoStartApiRequestRouteImport
284
-
parentRoute: typeof rootRouteImport
285
-
}
286
-
'/demo/api/tq-todos': {
287
-
id: '/demo/api/tq-todos'
288
-
path: '/demo/api/tq-todos'
289
-
fullPath: '/demo/api/tq-todos'
290
-
preLoaderRoute: typeof DemoApiTqTodosRouteImport
291
-
parentRoute: typeof rootRouteImport
292
-
}
293
-
'/demo/api/names': {
294
-
id: '/demo/api/names'
295
-
path: '/demo/api/names'
296
-
fullPath: '/demo/api/names'
297
-
preLoaderRoute: typeof DemoApiNamesRouteImport
298
-
parentRoute: typeof rootRouteImport
299
-
}
300
-
'/demo/api/mcp-todos': {
301
-
id: '/demo/api/mcp-todos'
302
-
path: '/demo/api/mcp-todos'
303
-
fullPath: '/demo/api/mcp-todos'
304
-
preLoaderRoute: typeof DemoApiMcpTodosRouteImport
305
-
parentRoute: typeof rootRouteImport
306
-
}
307
-
'/demo/start/ssr/': {
308
-
id: '/demo/start/ssr/'
309
-
path: '/demo/start/ssr'
310
-
fullPath: '/demo/start/ssr'
311
-
preLoaderRoute: typeof DemoStartSsrIndexRouteImport
312
-
parentRoute: typeof rootRouteImport
313
-
}
314
-
'/demo/start/ssr/spa-mode': {
315
-
id: '/demo/start/ssr/spa-mode'
316
-
path: '/demo/start/ssr/spa-mode'
317
-
fullPath: '/demo/start/ssr/spa-mode'
318
-
preLoaderRoute: typeof DemoStartSsrSpaModeRouteImport
319
-
parentRoute: typeof rootRouteImport
320
-
}
321
-
'/demo/start/ssr/full-ssr': {
322
-
id: '/demo/start/ssr/full-ssr'
323
-
path: '/demo/start/ssr/full-ssr'
324
-
fullPath: '/demo/start/ssr/full-ssr'
325
-
preLoaderRoute: typeof DemoStartSsrFullSsrRouteImport
326
-
parentRoute: typeof rootRouteImport
327
-
}
328
-
'/demo/start/ssr/data-only': {
329
-
id: '/demo/start/ssr/data-only'
330
-
path: '/demo/start/ssr/data-only'
331
-
fullPath: '/demo/start/ssr/data-only'
332
-
preLoaderRoute: typeof DemoStartSsrDataOnlyRouteImport
333
-
parentRoute: typeof rootRouteImport
334
-
}
335
-
}
228
+
declare module "@tanstack/react-router" {
229
+
interface FileRoutesByPath {
230
+
"/mcp": {
231
+
id: "/mcp";
232
+
path: "/mcp";
233
+
fullPath: "/mcp";
234
+
preLoaderRoute: typeof McpRouteImport;
235
+
parentRoute: typeof rootRouteImport;
236
+
};
237
+
"/": {
238
+
id: "/";
239
+
path: "/";
240
+
fullPath: "/";
241
+
preLoaderRoute: typeof IndexRouteImport;
242
+
parentRoute: typeof rootRouteImport;
243
+
};
244
+
"/album/": {
245
+
id: "/album/";
246
+
path: "/album";
247
+
fullPath: "/album";
248
+
preLoaderRoute: typeof AlbumIndexRouteImport;
249
+
parentRoute: typeof rootRouteImport;
250
+
};
251
+
"/demo/tanstack-query": {
252
+
id: "/demo/tanstack-query";
253
+
path: "/demo/tanstack-query";
254
+
fullPath: "/demo/tanstack-query";
255
+
preLoaderRoute: typeof DemoTanstackQueryRouteImport;
256
+
parentRoute: typeof rootRouteImport;
257
+
};
258
+
"/demo/mcp-todos": {
259
+
id: "/demo/mcp-todos";
260
+
path: "/demo/mcp-todos";
261
+
fullPath: "/demo/mcp-todos";
262
+
preLoaderRoute: typeof DemoMcpTodosRouteImport;
263
+
parentRoute: typeof rootRouteImport;
264
+
};
265
+
"/album/$albumId": {
266
+
id: "/album/$albumId";
267
+
path: "/album/$albumId";
268
+
fullPath: "/album/$albumId";
269
+
preLoaderRoute: typeof AlbumAlbumIdRouteImport;
270
+
parentRoute: typeof rootRouteImport;
271
+
};
272
+
"/demo/start/server-funcs": {
273
+
id: "/demo/start/server-funcs";
274
+
path: "/demo/start/server-funcs";
275
+
fullPath: "/demo/start/server-funcs";
276
+
preLoaderRoute: typeof DemoStartServerFuncsRouteImport;
277
+
parentRoute: typeof rootRouteImport;
278
+
};
279
+
"/demo/start/api-request": {
280
+
id: "/demo/start/api-request";
281
+
path: "/demo/start/api-request";
282
+
fullPath: "/demo/start/api-request";
283
+
preLoaderRoute: typeof DemoStartApiRequestRouteImport;
284
+
parentRoute: typeof rootRouteImport;
285
+
};
286
+
"/demo/api/tq-todos": {
287
+
id: "/demo/api/tq-todos";
288
+
path: "/demo/api/tq-todos";
289
+
fullPath: "/demo/api/tq-todos";
290
+
preLoaderRoute: typeof DemoApiTqTodosRouteImport;
291
+
parentRoute: typeof rootRouteImport;
292
+
};
293
+
"/demo/api/names": {
294
+
id: "/demo/api/names";
295
+
path: "/demo/api/names";
296
+
fullPath: "/demo/api/names";
297
+
preLoaderRoute: typeof DemoApiNamesRouteImport;
298
+
parentRoute: typeof rootRouteImport;
299
+
};
300
+
"/demo/api/mcp-todos": {
301
+
id: "/demo/api/mcp-todos";
302
+
path: "/demo/api/mcp-todos";
303
+
fullPath: "/demo/api/mcp-todos";
304
+
preLoaderRoute: typeof DemoApiMcpTodosRouteImport;
305
+
parentRoute: typeof rootRouteImport;
306
+
};
307
+
"/demo/start/ssr/": {
308
+
id: "/demo/start/ssr/";
309
+
path: "/demo/start/ssr";
310
+
fullPath: "/demo/start/ssr";
311
+
preLoaderRoute: typeof DemoStartSsrIndexRouteImport;
312
+
parentRoute: typeof rootRouteImport;
313
+
};
314
+
"/demo/start/ssr/spa-mode": {
315
+
id: "/demo/start/ssr/spa-mode";
316
+
path: "/demo/start/ssr/spa-mode";
317
+
fullPath: "/demo/start/ssr/spa-mode";
318
+
preLoaderRoute: typeof DemoStartSsrSpaModeRouteImport;
319
+
parentRoute: typeof rootRouteImport;
320
+
};
321
+
"/demo/start/ssr/full-ssr": {
322
+
id: "/demo/start/ssr/full-ssr";
323
+
path: "/demo/start/ssr/full-ssr";
324
+
fullPath: "/demo/start/ssr/full-ssr";
325
+
preLoaderRoute: typeof DemoStartSsrFullSsrRouteImport;
326
+
parentRoute: typeof rootRouteImport;
327
+
};
328
+
"/demo/start/ssr/data-only": {
329
+
id: "/demo/start/ssr/data-only";
330
+
path: "/demo/start/ssr/data-only";
331
+
fullPath: "/demo/start/ssr/data-only";
332
+
preLoaderRoute: typeof DemoStartSsrDataOnlyRouteImport;
333
+
parentRoute: typeof rootRouteImport;
334
+
};
335
+
}
336
336
}
337
337
338
338
const rootRouteChildren: RootRouteChildren = {
339
-
IndexRoute: IndexRoute,
340
-
McpRoute: McpRoute,
341
-
AlbumAlbumIdRoute: AlbumAlbumIdRoute,
342
-
DemoMcpTodosRoute: DemoMcpTodosRoute,
343
-
DemoTanstackQueryRoute: DemoTanstackQueryRoute,
344
-
AlbumIndexRoute: AlbumIndexRoute,
345
-
DemoApiMcpTodosRoute: DemoApiMcpTodosRoute,
346
-
DemoApiNamesRoute: DemoApiNamesRoute,
347
-
DemoApiTqTodosRoute: DemoApiTqTodosRoute,
348
-
DemoStartApiRequestRoute: DemoStartApiRequestRoute,
349
-
DemoStartServerFuncsRoute: DemoStartServerFuncsRoute,
350
-
DemoStartSsrDataOnlyRoute: DemoStartSsrDataOnlyRoute,
351
-
DemoStartSsrFullSsrRoute: DemoStartSsrFullSsrRoute,
352
-
DemoStartSsrSpaModeRoute: DemoStartSsrSpaModeRoute,
353
-
DemoStartSsrIndexRoute: DemoStartSsrIndexRoute,
354
-
}
355
-
export const routeTree = rootRouteImport
356
-
._addFileChildren(rootRouteChildren)
357
-
._addFileTypes<FileRouteTypes>()
339
+
IndexRoute: IndexRoute,
340
+
McpRoute: McpRoute,
341
+
AlbumAlbumIdRoute: AlbumAlbumIdRoute,
342
+
DemoMcpTodosRoute: DemoMcpTodosRoute,
343
+
DemoTanstackQueryRoute: DemoTanstackQueryRoute,
344
+
AlbumIndexRoute: AlbumIndexRoute,
345
+
DemoApiMcpTodosRoute: DemoApiMcpTodosRoute,
346
+
DemoApiNamesRoute: DemoApiNamesRoute,
347
+
DemoApiTqTodosRoute: DemoApiTqTodosRoute,
348
+
DemoStartApiRequestRoute: DemoStartApiRequestRoute,
349
+
DemoStartServerFuncsRoute: DemoStartServerFuncsRoute,
350
+
DemoStartSsrDataOnlyRoute: DemoStartSsrDataOnlyRoute,
351
+
DemoStartSsrFullSsrRoute: DemoStartSsrFullSsrRoute,
352
+
DemoStartSsrSpaModeRoute: DemoStartSsrSpaModeRoute,
353
+
DemoStartSsrIndexRoute: DemoStartSsrIndexRoute,
354
+
};
355
+
export const routeTree = rootRouteImport._addFileChildren(rootRouteChildren)._addFileTypes<FileRouteTypes>();
358
356
359
-
import type { getRouter } from './router.tsx'
360
-
import type { createStart } from '@tanstack/react-start'
361
-
declare module '@tanstack/react-start' {
362
-
interface Register {
363
-
ssr: true
364
-
router: Awaited<ReturnType<typeof getRouter>>
365
-
}
357
+
import type { getRouter } from "./router.tsx";
358
+
import type { createStart } from "@tanstack/react-start";
359
+
declare module "@tanstack/react-start" {
360
+
interface Register {
361
+
ssr: true;
362
+
router: Awaited<ReturnType<typeof getRouter>>;
363
+
}
366
364
}