From 390d89cd66fdc78a8e77904d192613eb480b6dea Mon Sep 17 00:00:00 2001 From: hfellerhoff Date: Mon, 1 Dec 2025 11:05:48 -0500 Subject: [PATCH 1/3] use local db file in dev --- .gitignore | 3 +- package.json | 6 +++- pnpm-lock.yaml | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 070b4cb..f0aac8c 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ yarn-error.log* **/public/worker-*.js.map *.db +*.db* .obsidian/** -.env.local \ No newline at end of file +.env.local diff --git a/package.json b/package.json index 08daff3..27362d0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "private": true, "type": "module", "scripts": { - "dev": "pnpm schema:migrate && next dev --turbopack", + "dev:db": "turso dev --db-file serial.db", + "dev:migrate": "pnpm schema:migrate", + "dev:run": "next dev --turbopack", + "dev": "concurrently --kill-others \"pnpm dev:db\" \"pnpm dev:migrate && pnpm dev:run\"", "dev:email": "email dev --dir ./src/emails --port 4000", "build": "next build --turbopack && pnpm schema:migrate && node --import=tsx ./src/server/scripts/addIdsToFeedItems.ts", "build:atomic": "next build --turbopack", @@ -116,6 +119,7 @@ "@typescript-eslint/eslint-plugin": "^8.46.3", "@typescript-eslint/parser": "^8.46.3", "better-sqlite3": "^12.4.1", + "concurrently": "^9.2.1", "dotenv": "^17.2.3", "drizzle-kit": "^0.31.6", "eslint": "^9.39.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36f97f3..6b5fa9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -307,6 +307,9 @@ importers: better-sqlite3: specifier: ^12.4.1 version: 12.4.1 + concurrently: + specifier: ^9.2.1 + version: 9.2.1 dotenv: specifier: ^17.2.3 version: 17.2.3 @@ -3978,6 +3981,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -4033,6 +4040,11 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} + engines: {node: '>=18'} + hasBin: true + conf@15.0.2: resolution: {integrity: sha512-JBSrutapCafTrddF9dH3lc7+T2tBycGF4uPkI4Js+g4vLLEhG6RZcFi3aJd5zntdf5tQxAejJt8dihkoQ/eSJw==} engines: {node: '>=20'} @@ -4896,6 +4908,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -6571,6 +6587,10 @@ packages: remark-rehype@11.1.2: resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -6643,6 +6663,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -7098,6 +7121,10 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -7536,6 +7563,10 @@ packages: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -7544,6 +7575,14 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -11736,6 +11775,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone@1.0.4: {} clsx@2.1.1: {} @@ -11780,6 +11825,15 @@ snapshots: concat-map@0.0.1: {} + concurrently@9.2.1: + dependencies: + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + conf@15.0.2: dependencies: ajv: 8.17.1 @@ -12770,6 +12824,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -14761,6 +14817,8 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + require-directory@2.1.1: {} + require-from-string@2.0.2: {} requires-port@1.0.0: {} @@ -14828,6 +14886,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -14981,8 +15043,7 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.8.3: - optional: true + shell-quote@1.8.3: {} side-channel-list@1.0.0: dependencies: @@ -15425,6 +15486,8 @@ snapshots: dependencies: punycode: 2.3.1 + tree-kill@1.2.2: {} + trim-lines@3.0.1: {} trough@2.2.0: {} @@ -16037,10 +16100,24 @@ snapshots: xmlhttprequest-ssl@2.1.2: {} + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@2.8.1: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yn@3.1.1: {} yocto-queue@0.1.0: {} From 8ef8665f318be905f08031cac6970135c7600ca9 Mon Sep 17 00:00:00 2001 From: hfellerhoff Date: Mon, 1 Dec 2025 14:01:20 -0500 Subject: [PATCH 2/3] fix list slicing issue --- src/app/(feed)/feed/SidebarFeeds.tsx | 16 +++++++--------- src/lib/iterators.ts | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/app/(feed)/feed/SidebarFeeds.tsx b/src/app/(feed)/feed/SidebarFeeds.tsx index 081f9a8..f2e6556 100644 --- a/src/app/(feed)/feed/SidebarFeeds.tsx +++ b/src/app/(feed)/feed/SidebarFeeds.tsx @@ -1,7 +1,6 @@ import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { AlertCircleIcon, - AlertTriangleIcon, CircleSmall, Edit2Icon, MinusIcon, @@ -18,6 +17,11 @@ import { SidebarMenuButton, SidebarMenuItem, } from "~/components/ui/sidebar"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "~/components/ui/tooltip"; import { categoryFilterAtom, dateFilterAtom, @@ -28,21 +32,15 @@ import { import { useFeedCategories } from "~/lib/data/feed-categories"; import { doesFeedItemPassFilters } from "~/lib/data/feed-items"; import { useFeeds } from "~/lib/data/feeds"; -import { useDeselectViewFilter } from "~/lib/data/views"; -import { useDialogStore } from "./dialogStore"; import { useFeedItemsDict, useFeedItemsOrder, useFeedStatusDict, useFetchFeedItemsStatus, } from "~/lib/data/store"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "~/components/ui/tooltip"; -import { error } from "node:console"; +import { useDeselectViewFilter } from "~/lib/data/views"; import { ApplicationFeed } from "~/server/db/schema"; +import { useDialogStore } from "./dialogStore"; function useCheckFilteredFeedItemsForFeed() { const feedItemsOrder = useFeedItemsOrder(); diff --git a/src/lib/iterators.ts b/src/lib/iterators.ts index 350edc0..aac4307 100644 --- a/src/lib/iterators.ts +++ b/src/lib/iterators.ts @@ -1,7 +1,7 @@ export function prepareArrayChunks(list: T[], length: number) { let chunks: T[][] = []; for (let i = 0; i < list.length; i += length) { - const end = Math.min(i + length, list.length - 1); + const end = Math.min(i + length, list.length); chunks.push(list.slice(i, end)); } return chunks; From 2e0ba194c5223073b0cfd3f69ce78fc158d9f182 Mon Sep 17 00:00:00 2001 From: hfellerhoff Date: Mon, 1 Dec 2025 17:02:47 -0500 Subject: [PATCH 3/3] allow local db development --- .env.example | 2 +- README.md | 11 +++-------- package.json | 2 +- pnpm-lock.yaml | 23 ++++++++++++++++------- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/.env.example b/.env.example index d0055c1..23c7fe0 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ NEXT_PUBLIC_ROOT_URL=http://localhost:3000 # Database -DATABASE_URL= +DATABASE_URL='http://127.0.0.1:8080' # This should be the URL when using default Turso CLI settings. DATABASE_AUTH_TOKEN= # Authentication diff --git a/README.md b/README.md index 6e7835b..de95d8c 100644 --- a/README.md +++ b/README.md @@ -17,20 +17,15 @@ All release notes can be found at [https://serial.tube/releases](https://serial. Getting up and running with Serial is easy. Here are the steps you need to start developing locally: 1. Clone the repository locally -2. Duplicate the `.env.example` file, and rename the copy to `.env` -3. Create a new database on [Turso](https://turso.tech/) - 1. Sign up for an account if you don't have one, and navigate to the database dashboard - 2. Create a new database - 3. In the top right dropdown menu, click "Create Token" - 4. Create a token with read and write permissions - 5. On the success screen, save the top value as `DATABASE_AUTH_TOKEN` and the bottom as `DATABASE_URL` +2. Install the Turso CLI: https://github.com/tursodatabase/turso-cli +3. Duplicate the `.env.example` file, and rename the copy to `.env` 4. Navigate to [Better Auth](https://www.better-auth.com/docs/installation#set-environment-variables) and generate an auth secret. Set this as `BETTER_AUTH_SECRET` 5. (optional) Create an account on [Sendgrid](https://sendgrid.com/en-us) and set up a mailing address. - This is not necessary to get up and running, but is needed if you'd like working password reset and other email-related functionality. 6. Install your packages with `pnpm` 1. If you don't have it already, install [pnpm](https://pnpm.io/) 2. Run `pnpm i` to install packages -7. That's it! Run `pnpm dev` to migrate your database for the first time and boot up the development server. +7. That's it! Run `pnpm dev` to create, migrate, and run your database for the first time, then boot up the development server. ## Self Hosting diff --git a/package.json b/package.json index 27362d0..cfcac67 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,6 @@ "cmdk": "^1.1.1", "core-js": "3.47.0", "dayjs": "^1.11.19", - "drizzle-orm": "^0.44.7", "drizzle-zod": "^0.8.3", "embla-carousel-react": "^8.6.0", "fast-xml-parser": "^5.3.1", @@ -122,6 +121,7 @@ "concurrently": "^9.2.1", "dotenv": "^17.2.3", "drizzle-kit": "^0.31.6", + "drizzle-orm": "^0.44.7", "eslint": "^9.39.1", "eslint-config-next": "16.0.1", "mysql2": "^3.15.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b5fa9b..c1e89e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,12 +174,9 @@ importers: dayjs: specifier: ^1.11.19 version: 1.11.19 - drizzle-orm: - specifier: ^0.44.7 - version: 0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3))(zod@4.1.12) + version: 0.8.3(drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3))(zod@4.1.12) embla-carousel-react: specifier: ^8.6.0 version: 8.6.0(react@19.2.0) @@ -316,6 +313,9 @@ importers: drizzle-kit: specifier: ^0.31.6 version: 0.31.6 + drizzle-orm: + specifier: ^0.44.7 + version: 0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3) eslint: specifier: ^9.39.1 version: 9.39.1(jiti@2.6.1) @@ -3225,6 +3225,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/core-js@2.5.8': resolution: {integrity: sha512-VgnAj6tIAhJhZdJ8/IpxdatM8G4OD3VWGlp6xIxUGENZlpbob9Ty4VVdC1FIEp0aK6DBscDDjyzy5FB60TuNqg==} @@ -10960,6 +10963,11 @@ snapshots: tslib: 2.8.1 optional: true + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 24.10.0 + optional: true + '@types/core-js@2.5.8': {} '@types/cors@2.8.19': @@ -12086,18 +12094,19 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3): + drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3): optionalDependencies: '@libsql/client': 0.15.15 '@planetscale/database': 1.19.0 + '@types/better-sqlite3': 7.6.13 better-sqlite3: 12.4.1 gel: 2.0.2 kysely: 0.28.8 mysql2: 3.15.3 - drizzle-zod@0.8.3(drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3))(zod@4.1.12): + drizzle-zod@0.8.3(drizzle-orm@0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3))(zod@4.1.12): dependencies: - drizzle-orm: 0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3) + drizzle-orm: 0.44.7(@libsql/client@0.15.15)(@planetscale/database@1.19.0)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.4.1)(gel@2.0.2)(kysely@0.28.8)(mysql2@3.15.3) zod: 4.1.12 dunder-proto@1.0.1: