init
This commit is contained in:
commit
519b43e9f8
29 changed files with 1043 additions and 0 deletions
30
.editorconfig
Normal file
30
.editorconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.js]
|
||||
indent_style = tab
|
||||
|
||||
[*.ts]
|
||||
indent_style = tab
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
6
.env.example
Normal file
6
.env.example
Normal file
|
@ -0,0 +1,6 @@
|
|||
SQLITE_DB_PATH="./data"
|
||||
SQLITE_DB_NAME="db.sqlite3"
|
||||
|
||||
BEARER_TOKEN="REPLACE_ME"
|
||||
|
||||
PORT=3000
|
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
.bun
|
||||
.DS_Store
|
||||
.env
|
||||
.env.*
|
||||
.env.development.local
|
||||
.env.local
|
||||
.env.production.local
|
||||
.env.test.local
|
||||
!.env.example
|
||||
.netlify
|
||||
.output
|
||||
.pnp.js
|
||||
.vercel
|
||||
.vercel
|
||||
*.log
|
||||
*.pem
|
||||
**/*.bun
|
||||
**/*.log
|
||||
**/*.tar.gz
|
||||
**/*.tgz
|
||||
**/*.trace
|
||||
**/*.zip
|
||||
/.next/
|
||||
/.pnp
|
||||
/.svelte-kit
|
||||
/~
|
||||
/build
|
||||
/coverage
|
||||
/node_modules
|
||||
/out/
|
||||
/package
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
package-lock.json
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
**/*.sqlite3
|
||||
**/*.sqlite3-shm
|
||||
**/*.sqlite3-wal
|
||||
**/*.sqlite
|
||||
**/*.sqlite-shm
|
||||
**/*.sqlite-wal
|
||||
**/*.db
|
||||
**/*.db-shm
|
||||
**/*.db-wal
|
3
.npmrc
Normal file
3
.npmrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
engine-strict=true
|
||||
resolution-mode=highest
|
||||
@jsr:registry=https://npm.jsr.io
|
19
.prettierignore
Normal file
19
.prettierignore
Normal file
|
@ -0,0 +1,19 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
8
.prettierrc
Normal file
8
.prettierrc
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"useTabs": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100,
|
||||
"plugins": [],
|
||||
"overrides": []
|
||||
}
|
38
Dockerfile
Normal file
38
Dockerfile
Normal file
|
@ -0,0 +1,38 @@
|
|||
# use the official Bun image
|
||||
# see all versions at https://hub.docker.com/r/oven/bun/tags
|
||||
FROM oven/bun:latest AS base
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# install dependencies into temp directory
|
||||
# this will cache them and speed up future builds
|
||||
FROM base AS install
|
||||
RUN mkdir -p /temp/dev
|
||||
COPY package.json bun.lock /temp/dev/
|
||||
RUN cd /temp/dev && bun install --frozen-lockfile
|
||||
|
||||
# install with --production (exclude devDependencies)
|
||||
RUN mkdir -p /temp/prod
|
||||
COPY package.json bun.lock /temp/prod/
|
||||
RUN cd /temp/prod && bun install --frozen-lockfile --production
|
||||
|
||||
# copy node_modules from temp directory
|
||||
# then copy all (non-ignored) project files into the image
|
||||
FROM base AS prerelease
|
||||
COPY --from=install /temp/dev/node_modules node_modules
|
||||
COPY . .
|
||||
|
||||
# [optional] tests & build
|
||||
# RUN bun test
|
||||
# RUN bun run build
|
||||
|
||||
# copy production dependencies and source code into final image
|
||||
FROM base AS release
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=install /temp/prod/node_modules node_modules
|
||||
COPY --from=prerelease /app/ .
|
||||
|
||||
# run the app
|
||||
ENTRYPOINT [ "bun", "run", "start" ]
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Elysia with Bun runtime
|
||||
|
||||
## Getting Started
|
||||
To get started with this template, simply paste this command into your terminal:
|
||||
```bash
|
||||
bun create elysia ./elysia-example
|
||||
```
|
||||
|
||||
## Development
|
||||
To start the development server run:
|
||||
```bash
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Open http://localhost:3000/ with your browser to see the result.
|
311
bun.lock
Normal file
311
bun.lock
Normal file
|
@ -0,0 +1,311 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "progress-tracker-api",
|
||||
"dependencies": {
|
||||
"bun-plugin-tailwind": "^0.0.15",
|
||||
"drizzle-kit": "^0.30.6",
|
||||
"drizzle-orm": "^0.41.0",
|
||||
"tailwindcss": "^4.1.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"oxlint": "latest",
|
||||
"prettier": "^4.0.0-alpha.12",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.8.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"esbuild",
|
||||
],
|
||||
"packages": {
|
||||
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
|
||||
|
||||
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
|
||||
|
||||
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
|
||||
|
||||
"@oxlint/darwin-arm64": ["@oxlint/darwin-arm64@0.16.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lxwzCWM8zkSsv+JMEAvhHoS5X+5ICq/Vupb4RAalozX2V39Y/JXNol6RBxIGD7EEmitxWBghMIMdmqW9Y0wChA=="],
|
||||
|
||||
"@oxlint/darwin-x64": ["@oxlint/darwin-x64@0.16.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-wRUxqisY7X1N88xoAFRcR3K7bPw6xqtNhaxVOaRhu5F3NIt85D80WBayoPl7TZKWTACUX55SGvAJBnOYmE7+zg=="],
|
||||
|
||||
"@oxlint/linux-arm64-gnu": ["@oxlint/linux-arm64-gnu@0.16.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-veM/ve9kqTU7Qei3qjvGzXPZLT8L1vQ2nE8U78DbjrmP9i5MC1QB5ynBB9oQDJ1yce9ExmjTpIor2SF3phfXXQ=="],
|
||||
|
||||
"@oxlint/linux-arm64-musl": ["@oxlint/linux-arm64-musl@0.16.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-QojvKDSA43gbt3pjua+zgX0jfpyWLU6xXEBgA/Ww7HPR7Ec1pbs8lhL1Or7BQl8jywkMdzWiicPtd65+DBw/IQ=="],
|
||||
|
||||
"@oxlint/linux-x64-gnu": ["@oxlint/linux-x64-gnu@0.16.4", "", { "os": "linux", "cpu": "x64" }, "sha512-rVZhsnzQzfhQSEVc+aGoLlWdzhyuXrKxrwv0h1R9rJSB7vzBx2+D2k9LQSW1WkuhUd3Bn4CIDPakT8XUKYxvXQ=="],
|
||||
|
||||
"@oxlint/linux-x64-musl": ["@oxlint/linux-x64-musl@0.16.4", "", { "os": "linux", "cpu": "x64" }, "sha512-ZLc+jh8+HF5ftnvVfWA3jl1/Rq45naakC96MlmRIxHhDNsClo41ssSeANJ15shk1MbCOdEnJh7foHPvU6QmGpQ=="],
|
||||
|
||||
"@oxlint/win32-arm64": ["@oxlint/win32-arm64@0.16.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-/KvI2fLK5V9cPuR7rfomchRJmHBJDH7PFZINNm5o3ivmjstUVsIT2HoArjitwoVdionKKJ0Ac8Vc0xqS/Vvbcg=="],
|
||||
|
||||
"@oxlint/win32-x64": ["@oxlint/win32-x64@0.16.4", "", { "os": "win32", "cpu": "x64" }, "sha512-KS2ztiU039dooBi82i24QL6aa/4PROwg9fEcZc4o3N2BueO01a0s4nKlz/AJL+1Twa6LZJgGsQ87EcAzlj3DUA=="],
|
||||
|
||||
"@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="],
|
||||
|
||||
"@prettier/cli": ["@prettier/cli@0.7.1", "", { "dependencies": { "atomically": "^2.0.3", "fast-ignore": "^1.1.3", "find-up-json": "^2.0.4", "function-once": "^3.0.0", "import-meta-resolve": "^4.1.0", "is-binary-path": "^2.1.0", "js-yaml": "^4.1.0", "json-sorted-stringify": "^1.0.0", "json5": "^2.2.3", "kasi": "^1.1.0", "lomemo": "^1.0.0", "pioppo": "^1.2.0", "promise-resolve-timeout": "^2.0.0", "smol-toml": "^1.3.1", "specialist": "^1.4.5", "tiny-editorconfig": "^1.0.0", "tiny-jsonc": "^1.0.1", "tiny-readdir": "^2.7.4", "tiny-readdir-glob": "^1.23.1", "tiny-spinner": "^2.0.4", "worktank": "^2.7.3", "zeptomatch": "^2.0.0", "zeptomatch-escape": "^1.0.0", "zeptomatch-is-static": "^1.0.0" }, "peerDependencies": { "prettier": "^3.1.0 || ^4.0.0-alpha" }, "bin": { "prettier-next": "dist/bin.js" } }, "sha512-YoXPLOLmEEHP4MKgzcEilzaUtlo80Qm5Pb+59QbgDeOsIExGBkRqZmC2+iwzSwEhlhTEpGqDwqb3+nP/dPay9A=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="],
|
||||
|
||||
"@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
|
||||
|
||||
"ansi-purge": ["ansi-purge@1.0.1", "", {}, "sha512-5NNMT7rljQ24DKHnIYG1qFXs8eUv5mZcT6kOPf5NopQUzpURBh/T4tbQw3TX//q3Zpw3JwVvsVHHsRKJesQHZQ=="],
|
||||
|
||||
"ansi-truncate": ["ansi-truncate@1.2.0", "", { "dependencies": { "fast-string-truncated-width": "^1.2.0" } }, "sha512-/SLVrxNIP8o8iRHjdK3K9s2hDqdvb86NEjZOAB6ecWFsOo+9obaby97prnvAPn6j7ExXCpbvtlJFYPkkspg4BQ=="],
|
||||
|
||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"atomically": ["atomically@2.0.3", "", { "dependencies": { "stubborn-fs": "^1.2.5", "when-exit": "^2.1.1" } }, "sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw=="],
|
||||
|
||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||
|
||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||
|
||||
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.0.15", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-qtAXMNGG4R0UGGI8zWrqm2B7BdXqx48vunJXBPzfDOHPA5WkRUZdTSbE7TFwO4jLhYqSE23YMWsM9NhE6ovobw=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="],
|
||||
|
||||
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||
|
||||
"dettle": ["dettle@1.0.5", "", {}, "sha512-ZVyjhAJ7sCe1PNXEGveObOH9AC8QvMga3HJIghHawtG7mE4K5pW9nz/vDGAr/U7a3LWgdOzEE7ac9MURnyfaTA=="],
|
||||
|
||||
"drizzle-kit": ["drizzle-kit@0.30.6", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g=="],
|
||||
|
||||
"drizzle-orm": ["drizzle-orm@0.41.0", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-7A4ZxhHk9gdlXmTdPj/lREtP+3u8KvZ4yEN6MYVxBzZGex5Wtdc+CWSbu7btgF6TB0N+MNPrvW7RKBbxJchs/Q=="],
|
||||
|
||||
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
|
||||
|
||||
"esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
|
||||
|
||||
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
|
||||
|
||||
"fast-ignore": ["fast-ignore@1.1.3", "", { "dependencies": { "grammex": "^3.1.2", "string-escape-regex": "^1.0.0" } }, "sha512-xTo4UbrOKfEQgOFlPaqFScodTV/Wf3KATEqCZZSMh6OP4bcez0lTsqww3n3/Fve1q9u0jmfDP0q0nOhH4POZEg=="],
|
||||
|
||||
"fast-string-truncated-width": ["fast-string-truncated-width@1.2.1", "", {}, "sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow=="],
|
||||
|
||||
"fast-string-width": ["fast-string-width@1.1.0", "", { "dependencies": { "fast-string-truncated-width": "^1.2.0" } }, "sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ=="],
|
||||
|
||||
"find-up-json": ["find-up-json@2.0.5", "", { "dependencies": { "find-up-path": "^1.0.1" } }, "sha512-1zZZUfD1GOOEEd1AqwbRmCkCCv1O9t0vOpCYgmzfJqKty8WKaKlDyxWej8Aew+vI5lvDiTviaQuaVuu6GzlHzQ=="],
|
||||
|
||||
"find-up-path": ["find-up-path@1.0.1", "", {}, "sha512-cl4Sfxufq9WK848L887b4r+NVZoBjMeB4QydPZ+pXbp6Jt2nUVspTo2svNOm48stIIeSxtuCsULa9+e+LMTzwA=="],
|
||||
|
||||
"function-once": ["function-once@3.0.1", "", {}, "sha512-bE3E8REk4jANDot3l0sLFkXgywBwzFKsmbwdnVHLJUnt/3kV6dNG0oJJqoRBuS1Z9Lr4ZoQgwV0ZNLDgWDbv7Q=="],
|
||||
|
||||
"gel": ["gel@2.0.1", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-gfem3IGvqKqXwEq7XseBogyaRwGsQGuE7Cw/yQsjLGdgiyqX92G1xENPCE0ltunPGcsJIa6XBOTx/PK169mOqw=="],
|
||||
|
||||
"get-current-package": ["get-current-package@1.0.1", "", { "dependencies": { "find-up-json": "^2.0.5" } }, "sha512-c/Rw5ByDQ+zg+Lh/emBWv0bDpugEFdmXPR6/srIemVtIvol0XbT0JAr8Db0cX+Jj/xY9wj1wdjeq2qNB35Tayg=="],
|
||||
|
||||
"get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="],
|
||||
|
||||
"grammex": ["grammex@3.1.10", "", {}, "sha512-UCfMsV/sfqk4TN1+m5ehSOXuADyLUgSuwMI2vCVlbN/REoSmTl4eagswC9DzzVxtsKv7Yp2CmIJNn4fMk8PaQA=="],
|
||||
|
||||
"import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="],
|
||||
|
||||
"ini-simple-parser": ["ini-simple-parser@1.0.1", "", {}, "sha512-myU5nhF2miBQP3tO/giUi+8BI9QhfM/XRZd0RD7G0p+40K6KPAwxMDtH3UEtJ2XJZbd+ZiQOoGh432DTYfzNVQ=="],
|
||||
|
||||
"ionstore": ["ionstore@1.0.1", "", {}, "sha512-g+99vyka3EiNFJCnbq3NxegjV211RzGtkDUMbZGB01Con8ZqUmMx/FpWMeqgDXOqgM7QoVeDhe+CfYCWznaDVA=="],
|
||||
|
||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||
|
||||
"isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||
|
||||
"json-sorted-stringify": ["json-sorted-stringify@1.0.1", "", {}, "sha512-pWv9hqWho37EpwpBgqDYVPKPCgT/ytuvqtlBvb6M44BrnvooTk/5D/aSeohsGDLp+g8waP5dUUGODR+Ley+Idg=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"kasi": ["kasi@1.1.1", "", {}, "sha512-pzBwGWFIjf84T/8aD0XzMli1T3Ckr/jVLh6v0Jskwiv5ehmcgDM+vpYFSk8WzGn4ed4HqgaifTgQUHzzZHa+Qw=="],
|
||||
|
||||
"lomemo": ["lomemo@1.0.1", "", {}, "sha512-g8CnVp7UYypeQKpXpMzyrJoDzhOoqVQYSJApoq/cFI3vGxXoHQ+6lH5cApW9XwzVy5SL9/Owil7/JxbKckw0Lg=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"oxlint": ["oxlint@0.16.4", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "0.16.4", "@oxlint/darwin-x64": "0.16.4", "@oxlint/linux-arm64-gnu": "0.16.4", "@oxlint/linux-arm64-musl": "0.16.4", "@oxlint/linux-x64-gnu": "0.16.4", "@oxlint/linux-x64-musl": "0.16.4", "@oxlint/win32-arm64": "0.16.4", "@oxlint/win32-x64": "0.16.4" }, "bin": { "oxlint": "bin/oxlint", "oxc_language_server": "bin/oxc_language_server" } }, "sha512-zi/a8i2R3OJcAUx1KHGy4B8UWWCN3YLDYzlYSNX9uknfX0PJSzv632Xrw9V0Ty5Y1biD6ZuLyO+5Yy2yeG2ySA=="],
|
||||
|
||||
"pioppo": ["pioppo@1.2.1", "", { "dependencies": { "dettle": "^1.0.5", "when-exit": "^2.1.4" } }, "sha512-1oErGVWD6wFDPmrJWEY1Cj2p829UGT6Fw9OItYFxLkWtBjCvQSMC8wA5IcAR5ms/6gqiY8pnJvIV/+/Imyobew=="],
|
||||
|
||||
"prettier": ["prettier@4.0.0-alpha.12", "", { "dependencies": { "@prettier/cli": "^0.7.1" }, "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-wQ8RK48Io6nRr39OQFXZu+EALwTygXnstPgN9UplY+mqkg6P52ceGifo5gylIwX1X9lOuXxreUFrLxXsCbA+sg=="],
|
||||
|
||||
"prettier-plugin-tailwindcss": ["prettier-plugin-tailwindcss@0.6.11", "", { "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", "@zackad/prettier-plugin-twig": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-import-sort": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", "prettier-plugin-sort-imports": "*", "prettier-plugin-style-order": "*", "prettier-plugin-svelte": "*" }, "optionalPeers": ["@ianvs/prettier-plugin-sort-imports", "@prettier/plugin-pug", "@shopify/prettier-plugin-liquid", "@trivago/prettier-plugin-sort-imports", "@zackad/prettier-plugin-twig", "prettier-plugin-astro", "prettier-plugin-css-order", "prettier-plugin-import-sort", "prettier-plugin-jsdoc", "prettier-plugin-marko", "prettier-plugin-multiline-arrays", "prettier-plugin-organize-attributes", "prettier-plugin-organize-imports", "prettier-plugin-sort-imports", "prettier-plugin-style-order", "prettier-plugin-svelte"] }, "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA=="],
|
||||
|
||||
"promise-make-counter": ["promise-make-counter@1.0.2", "", { "dependencies": { "promise-make-naked": "^3.0.2" } }, "sha512-FJAxTBWQuQoAs4ZOYuKX1FHXxEgKLEzBxUvwr4RoOglkTpOjWuM+RXsK3M9q5lMa8kjqctUrhwYeZFT4ygsnag=="],
|
||||
|
||||
"promise-make-naked": ["promise-make-naked@2.1.2", "", {}, "sha512-y7s8ZuHIG56JYspB24be9GFkXA1zXL85Ur9u1DKrW/tvyUoPxWgBjnalK6Nc6l7wHBcAW0c3PO07+XOsWTRuhg=="],
|
||||
|
||||
"promise-resolve-timeout": ["promise-resolve-timeout@2.0.1", "", {}, "sha512-90Qzzu5SmR+ksmTPsc79121NZGtEiPvKACQLCl6yofknRx5xJI9kNj3oDVSX6dVTneF8Ju6+xpVFdDSzb7cNcg=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
|
||||
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||
|
||||
"shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="],
|
||||
|
||||
"smol-toml": ["smol-toml@1.3.1", "", {}, "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
|
||||
|
||||
"specialist": ["specialist@1.4.5", "", { "dependencies": { "tiny-bin": "^1.10.3", "tiny-colors": "^2.2.2", "tiny-parse-argv": "^2.8.1", "tiny-updater": "^3.5.3" } }, "sha512-4mPQEREzBUW2hzlXX/dWFbQdUWzpkqvMFVpUAdRlo1lUlhKMObDHiAo09oZ94x4cS3uWMJebPOTn+GaQYLfv3Q=="],
|
||||
|
||||
"stdin-blocker": ["stdin-blocker@2.0.1", "", {}, "sha512-NEcAEpag+gE/Iivx1prq1AFPwnmgmcyHNvGZLUqGBoOE/7DZtmhtP9iYqJt8ymueFL+kknhfEebAMWbrWp3FJw=="],
|
||||
|
||||
"string-escape-regex": ["string-escape-regex@1.0.1", "", {}, "sha512-cdSXOHSJ32K/T2dbj9t7rJwonujaOkaINpa1zsXT+PNFIv1zuPjtr0tXanCvUhN2bIu2IB0z/C7ksl+Qsy44nA=="],
|
||||
|
||||
"stubborn-fs": ["stubborn-fs@1.2.5", "", {}, "sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
|
||||
|
||||
"tiny-bin": ["tiny-bin@1.11.1", "", { "dependencies": { "ansi-purge": "^1.0.1", "fast-string-width": "^1.1.0", "get-current-package": "^1.0.1", "tiny-colors": "^2.2.2", "tiny-levenshtein": "^1.0.1", "tiny-parse-argv": "^2.8.2", "tiny-updater": "^3.5.3" } }, "sha512-UFC5EwtmCkFshKOBgXZzNFJsHpZrtbWZ/jQj+pwoIGUUbmenlQGGVDOwVqVOuG1nTxICSd+GLp3b+j7dUKZr2Q=="],
|
||||
|
||||
"tiny-colors": ["tiny-colors@2.2.2", "", {}, "sha512-Elmv7JL+dX0c78caKEelH1nHHBskHzJkaqBRgVvQuxsvVA/Z9Fa2R3ZZtfmkkajcd18e96RLMwJvtFqC8jsZWA=="],
|
||||
|
||||
"tiny-cursor": ["tiny-cursor@2.0.1", "", { "dependencies": { "when-exit": "^2.1.4" } }, "sha512-28ytGEfb7m/8Gdflv+wSo5qRM01fROo2CjJVYon6yYbzPsc3ap3Ps5CZXuS19pIROwswSvZMGbEQ7kWnokdUGA=="],
|
||||
|
||||
"tiny-editorconfig": ["tiny-editorconfig@1.0.0", "", { "dependencies": { "ini-simple-parser": "^1.0.0", "zeptomatch": "^1.1.3" } }, "sha512-rxpWaSurnvPUkL2/qydRH10llK7MD1XfE38zoWTsp/ZWWYnnwPBzGUePBOcXFaNA3cJQm8ItqrofGeRJ6AVaew=="],
|
||||
|
||||
"tiny-jsonc": ["tiny-jsonc@1.0.2", "", {}, "sha512-f5QDAfLq6zIVSyCZQZhhyl0QS6MvAyTxgz4X4x3+EoCktNWEYJ6PeoEA97fyb98njpBNNi88ybpD7m+BDFXaCw=="],
|
||||
|
||||
"tiny-levenshtein": ["tiny-levenshtein@1.0.1", "", {}, "sha512-Q4rRa0pxGIbYoXQDejEDnonHt+QUTFrejaAxdv7h352/PWQBJ2eKsbzw1khvbIXKrpG1n2ZABX0A34oBGZXB2w=="],
|
||||
|
||||
"tiny-parse-argv": ["tiny-parse-argv@2.8.2", "", {}, "sha512-RnIDHQ+r9zMuslQWVoRxfKVOumteeheQqbwNYJyQxzM2vzx/vdN5xAeL64F3rQOpfbVdxFkhM4zPDyfq7SxsBQ=="],
|
||||
|
||||
"tiny-readdir": ["tiny-readdir@2.7.4", "", { "dependencies": { "promise-make-counter": "^1.0.2" } }, "sha512-721U+zsYwDirjr8IM6jqpesD/McpZooeFi3Zc6mcjy1pse2C+v19eHPFRqz4chGXZFw7C3KITDjAtHETc2wj7Q=="],
|
||||
|
||||
"tiny-readdir-glob": ["tiny-readdir-glob@1.23.1", "", { "dependencies": { "tiny-readdir": "^2.7.0", "zeptomatch": "^1.2.2", "zeptomatch-explode": "^1.0.0", "zeptomatch-is-static": "^1.0.0", "zeptomatch-unescape": "^1.0.0" } }, "sha512-UJB7alIB+lSmIfVGKLxNyErlo5mto1luldvXW+s+NSO5gyleU/Ut9P4QKghPEenCHqVZhW0j6OggDkmattVhKw=="],
|
||||
|
||||
"tiny-spinner": ["tiny-spinner@2.0.5", "", { "dependencies": { "stdin-blocker": "^2.0.1", "tiny-colors": "^2.2.2", "tiny-cursor": "^2.0.1", "tiny-truncate": "^1.0.3" } }, "sha512-OIGogtfEbA2IQdCBgF0zI3EjpFyiUEd6Uj5j0q5jhIPPq8pgNR83D0t9WIckbD2FzPann8lH/uLf1vX0YIu04w=="],
|
||||
|
||||
"tiny-truncate": ["tiny-truncate@1.0.3", "", { "dependencies": { "ansi-truncate": "^1.2.0" } }, "sha512-ZdCMtUg6N5VgYAInid90lnA4R720w5iU7raqPspAoYxOSMyzp132b8DeKZGrO2yC3tvoJMUDaymY3XFN3Zr5sQ=="],
|
||||
|
||||
"tiny-updater": ["tiny-updater@3.5.3", "", { "dependencies": { "ionstore": "^1.0.1", "tiny-colors": "^2.2.2", "when-exit": "^2.1.4" } }, "sha512-wEUssfOOkVLg2raSaRbyZDHpVCDj6fnp7UjynpNE4XGuF+Gkj8GRRMoHdfk73VzLQs/AHKsbY8fCxXNz8Hx4Qg=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
|
||||
|
||||
"webworker-shim": ["webworker-shim@1.1.1", "", {}, "sha512-XCWuBjJH3Xn/7SbyUF1WrrCbe6ZEsgaD7kxlFhxIwdkljGYX3BqP/dhG6ge0NBT+V7ZPjR4/BXq5BvbdaxrpKg=="],
|
||||
|
||||
"when-exit": ["when-exit@2.1.4", "", {}, "sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg=="],
|
||||
|
||||
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
|
||||
|
||||
"worktank": ["worktank@2.7.3", "", { "dependencies": { "promise-make-naked": "^2.0.0", "webworker-shim": "^1.1.0" } }, "sha512-M0fesnpttBPdvNYBdzRvLDsacN0na9RYWFxwmM/x1+/6mufjduv9/9vBObK8EXDqxRMX/SOYJabpo0UCYYBUdQ=="],
|
||||
|
||||
"zeptomatch": ["zeptomatch@2.0.1", "", { "dependencies": { "grammex": "^3.1.10" } }, "sha512-nbnIYF2n3o3EqV36HkIhEMLIDFbG3M6RUjhkdKIn6qqIJkdkL7bgVSfTTCEXBJpk1T45tLfEYfStndJc2lUEnA=="],
|
||||
|
||||
"zeptomatch-escape": ["zeptomatch-escape@1.0.1", "", {}, "sha512-kAc5HzvnF66djCYDqpsS46Y/FKi+4pe/KJRmTmm/hwmoaNYzmm6bBY07cdkxmJCdY018S5UeQn4yP+9X2x1MbQ=="],
|
||||
|
||||
"zeptomatch-explode": ["zeptomatch-explode@1.0.1", "", {}, "sha512-7cUQASLLRGZ20+zEQcEgQ9z/gH1+jSfrNg4KfRJSxF1QU2fpymAwWvnAxl69GD5pr3IV0V9vo3ke2np//Nh4tQ=="],
|
||||
|
||||
"zeptomatch-is-static": ["zeptomatch-is-static@1.0.1", "", {}, "sha512-bN9q7H/UdXhkub01WE7b7Grg07jLldNnIWG2T1IpBq5NtvcQ4DwFbNiGGapnbKHUdWiCNjg/bIvixV88nj9gog=="],
|
||||
|
||||
"zeptomatch-unescape": ["zeptomatch-unescape@1.0.1", "", {}, "sha512-xhSFkKV0aQ03e/eiN4VhOTwJhcqfH7SMiGHrWKw9gXi+0EVJAxJ8Gt4ehozYsYLhUXL1JFbP1g3EE6ZmkStB0g=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
|
||||
|
||||
"promise-make-counter/promise-make-naked": ["promise-make-naked@3.0.2", "", {}, "sha512-B+b+kQ1YrYS7zO7P7bQcoqqMUizP06BOyNSBEnB5VJKDSWo8fsVuDkfSmwdjF0JsRtaNh83so5MMFJ95soH5jg=="],
|
||||
|
||||
"tiny-editorconfig/zeptomatch": ["zeptomatch@1.2.2", "", { "dependencies": { "grammex": "^3.1.1" } }, "sha512-0ETdzEO0hdYmT8aXHHf5aMjpX+FHFE61sG4qKFAoJD2Umt3TWdCmH7ADxn2oUiWTlqBGC+SGr8sYMfr+37J8pQ=="],
|
||||
|
||||
"tiny-readdir-glob/zeptomatch": ["zeptomatch@1.2.2", "", { "dependencies": { "grammex": "^3.1.1" } }, "sha512-0ETdzEO0hdYmT8aXHHf5aMjpX+FHFE61sG4qKFAoJD2Umt3TWdCmH7ADxn2oUiWTlqBGC+SGr8sYMfr+37J8pQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
|
||||
}
|
||||
}
|
5
bunfig.toml
Normal file
5
bunfig.toml
Normal file
|
@ -0,0 +1,5 @@
|
|||
[install.scopes]
|
||||
"@jsr" = "https://npm.jsr.io"
|
||||
|
||||
[serve.static]
|
||||
plugins = ["bun-plugin-tailwind"]
|
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
7
drizzle.config.ts
Normal file
7
drizzle.config.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import type { Config } from "drizzle-kit";
|
||||
|
||||
export default {
|
||||
schema: 'src/db/schema.ts',
|
||||
out: './drizzle',
|
||||
dialect: 'sqlite',
|
||||
} satisfies Config;
|
10
drizzle/0000_neat_marvel_boy.sql
Normal file
10
drizzle/0000_neat_marvel_boy.sql
Normal file
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE `entry` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`href` text NOT NULL,
|
||||
`finished` integer DEFAULT false NOT NULL,
|
||||
`created_at` integer DEFAULT (unixepoch('subsec') NOT NULL,
|
||||
`updated_at` integer DEFAULT (unixepoch('subsec') NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `entry_name_unique` ON `entry` (`name`);
|
81
drizzle/meta/0000_snapshot.json
Normal file
81
drizzle/meta/0000_snapshot.json
Normal file
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "5b7c56dc-4c5d-444a-9c66-9da5c7e06977",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"entry": {
|
||||
"name": "entry",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"href": {
|
||||
"name": "href",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"finished": {
|
||||
"name": "finished",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch('subsec')"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(unixepoch('subsec')"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"entry_name_unique": {
|
||||
"name": "entry_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
13
drizzle/meta/_journal.json
Normal file
13
drizzle/meta/_journal.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1743898098259,
|
||||
"tag": "0000_neat_marvel_boy",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
36
package.json
Normal file
36
package.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "progress-tracker-api",
|
||||
"version": "1.0.50",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"module": "src/server.ts",
|
||||
"scripts": {
|
||||
"migrate": "bun --bun run ./src/db/migrate.ts",
|
||||
"generate": "bunx --bun drizzle-kit generate --config=./drizzle.config.ts",
|
||||
"studio": "bunx --bun drizzle-kit studio --config=./drizzle.config.ts",
|
||||
"up": "drizzle-kit up --config=./drizzle.config.ts",
|
||||
"start": "bun run src/server.ts",
|
||||
"dev": "bun run --watch src/server.ts",
|
||||
"lint": "oxlint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"bun-plugin-tailwind": "^0.0.15",
|
||||
"drizzle-kit": "^0.30.6",
|
||||
"drizzle-orm": "^0.41.0",
|
||||
"tailwindcss": "^4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"oxlint": "latest",
|
||||
"prettier": "^4.0.0-alpha.12",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"esbuild",
|
||||
"es5-ext"
|
||||
]
|
||||
}
|
47
src/db/index.ts
Normal file
47
src/db/index.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { Database } from 'bun:sqlite';
|
||||
import { env } from 'bun';
|
||||
import { drizzle } from 'drizzle-orm/bun-sqlite';
|
||||
import { migrate } from 'drizzle-orm/bun-sqlite/migrator';
|
||||
import { createWrappedTimer } from '../wrapped-timer';
|
||||
|
||||
function initDb() {
|
||||
global.db.exec('PRAGMA journal_mode = delete');
|
||||
global.db.exec('PRAGMA journal_mode = WAL');
|
||||
global.db.exec('PRAGMA synchronous = NORMAL');
|
||||
global.db.exec('PRAGMA auto_vacuum = INCREMENTAL');
|
||||
global.db.exec('PRAGMA wal_autocheckpoint = 1000');
|
||||
}
|
||||
|
||||
function incrementalVacuumDb() {
|
||||
global.db.exec('PRAGMA incremental_vacuum');
|
||||
}
|
||||
|
||||
function optimizeDb() {
|
||||
global.db.exec('PRAGMA optimize');
|
||||
}
|
||||
|
||||
function vacuumDb() {
|
||||
global.db.exec('vacuum');
|
||||
}
|
||||
|
||||
if (global.db === undefined || global.drizzleDB === undefined) {
|
||||
global.db = new Database(`${env.SQLITE_DB_PATH}/${env.SQLITE_DB_NAME}`, { create: true });
|
||||
initDb();
|
||||
global.drizzleDB = drizzle(global.db);
|
||||
migrate(global.drizzleDB, { migrationsFolder: './drizzle' });
|
||||
}
|
||||
|
||||
const incrementalVacuumInterval = 1000 * 30; // 30 seconds
|
||||
const incrementalVacuumRunnable = createWrappedTimer('databaseIncrementalVacuum', incrementalVacuumDb, incrementalVacuumInterval);
|
||||
|
||||
setTimeout(incrementalVacuumRunnable.callback, 0);
|
||||
const optimizeInterval = 1000 * 60 * 30; // 30 minutes
|
||||
const optimizeRunnable = createWrappedTimer('databaseOptimize', optimizeDb, optimizeInterval);
|
||||
setTimeout(optimizeRunnable.callback, 0);
|
||||
|
||||
const vacuumInterval = 1000 * 60 * 60 * 24; // 24 hours
|
||||
const vacuumRunnable = createWrappedTimer('databaseVacuum', vacuumDb, vacuumInterval);
|
||||
setTimeout(vacuumRunnable.callback, 0);
|
||||
|
||||
export const db = global.db;
|
||||
export const drizzleDB = global.drizzleDB;
|
10
src/db/migrate.ts
Normal file
10
src/db/migrate.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Database } from 'bun:sqlite';
|
||||
import { env } from 'bun';
|
||||
import { drizzle } from 'drizzle-orm/bun-sqlite';
|
||||
import { migrate } from 'drizzle-orm/bun-sqlite/migrator';
|
||||
|
||||
const sqlite = new Database(`${env.SQLITE_DB_PATH}/${env.SQLITE_DB_NAME}`, { create: true });
|
||||
|
||||
const db = drizzle(sqlite);
|
||||
|
||||
migrate(db, { migrationsFolder: './drizzle' });
|
25
src/db/schema.ts
Normal file
25
src/db/schema.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { sql, type InferSelectModel } from 'drizzle-orm';
|
||||
import { index, integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||
|
||||
const createdAt = integer('created_at', { mode: 'timestamp_ms' })
|
||||
.notNull()
|
||||
.default(sql`(unixepoch('subsec')`)
|
||||
.$defaultFn(() => new Date());
|
||||
const updatedAt = integer('updated_at', { mode: 'timestamp_ms' })
|
||||
.notNull()
|
||||
.default(sql`(unixepoch('subsec')`)
|
||||
.$onUpdateFn(() => new Date());
|
||||
|
||||
export const entry = sqliteTable(
|
||||
'entry',
|
||||
{
|
||||
id: integer('id', { mode: 'number' }).primaryKey({ autoIncrement: true }),
|
||||
name: text('name').notNull().unique(),
|
||||
href: text('href').notNull(),
|
||||
finished: integer('finished', { mode: 'boolean' }).notNull().default(false),
|
||||
createdAt,
|
||||
updatedAt,
|
||||
}
|
||||
);
|
||||
|
||||
type SelectEntry = InferSelectModel<typeof entry>;
|
23
src/index.css
Normal file
23
src/index.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
@import 'tailwindcss' source('.');
|
||||
|
||||
@theme {
|
||||
--breakout-size: calc((var(--breakpoint-xl) - var(--breakpoint-lg)) / 2);
|
||||
--ultrawide-val: minmax(calc(var(--spacing) * 4), 1fr);
|
||||
--breakout-val: minmax(0, var(--breakout-size));
|
||||
--content-val: min(100% - calc(var(--spacing) * 8), var(--breakpoint-lg));
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-template-columns:
|
||||
[ultrawide-start] var(--ultrawide-val) [breakout-start] var(--breakout-val) [content-start] var(--content-val) [content-end] var(--breakout-val) [breakout-end] var(--ultrawide-val) [ultrawide-end];
|
||||
}
|
||||
|
||||
.content>* {
|
||||
grid-column: content;
|
||||
}
|
||||
}
|
9
src/index.d.ts
vendored
Normal file
9
src/index.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import type { Database } from 'bun:sqlite';
|
||||
import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite';
|
||||
|
||||
declare global {
|
||||
var db: Database;
|
||||
var drizzleDB: BunSQLiteDatabase;
|
||||
var performanceObserver: PerformanceObserver;
|
||||
var wrappedTimers: Map<string, import('../wrapped-timer').WrappedTimer>;
|
||||
}
|
21
src/index.html
Normal file
21
src/index.html
Normal file
File diff suppressed because one or more lines are too long
153
src/server.ts
Normal file
153
src/server.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
import { env } from "bun";
|
||||
import homepage from './index.html';
|
||||
import robotsTxt from './static/robots.txt';
|
||||
import sitemapTxt from './static/sitemap.txt';
|
||||
// @ts-ignore ts2307
|
||||
import icon from './static/favicon.png' with { type: 'file' };
|
||||
import { entry } from "./db/schema";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
const favicon = await Bun.file(icon).bytes();
|
||||
|
||||
const development = env.NODE_ENV !== 'production';
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
'/': homepage,
|
||||
'/robots.txt': new Response(robotsTxt, {
|
||||
headers: { 'Content-Type': 'text/plain' },
|
||||
}),
|
||||
'/sitemap.txt': new Response(sitemapTxt, {
|
||||
headers: { 'Content-Type': 'text/plain' },
|
||||
}),
|
||||
'/favicon.ico': new Response(favicon, {
|
||||
headers: { 'Content-Type': 'image/png' },
|
||||
}),
|
||||
'/health': new Response('OK'),
|
||||
'/api/entries': {
|
||||
async GET(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const entries = await drizzleDB.select().from(entry).orderBy(desc(entry.updatedAt));
|
||||
|
||||
return new Response(JSON.stringify(entries), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
},
|
||||
async POST(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const body = await getEntryFromReq(req);
|
||||
if (!body) return new Response('Invalid data', { status: 400 });
|
||||
|
||||
const result = await drizzleDB.select({ id: entry.id }).from(entry).where(eq(entry.name, body.name));
|
||||
|
||||
let created = true;
|
||||
|
||||
if (result.length === 0) {
|
||||
await drizzleDB.insert(entry).values(body).execute();
|
||||
} else if (result.length === 1) {
|
||||
const row = result[0];
|
||||
created = false;
|
||||
await drizzleDB.update(entry).set(body).where(eq(entry.id, row.id)).execute();
|
||||
} else {
|
||||
return new Response('Invalid data, multiple matches?', { status: 400 });
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ created }), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
},
|
||||
},
|
||||
'/api/entries/:id': {
|
||||
async GET(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const id = Number.parseInt(req.params.id, 10);
|
||||
if (Number.isNaN(id)) return new Response('Invalid id', { status: 400 });
|
||||
|
||||
const result = await drizzleDB.select().from(entry).where(eq(entry.id, id));
|
||||
|
||||
return new Response(JSON.stringify(result), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
},
|
||||
async PUT(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const id = Number.parseInt(req.params.id, 10);
|
||||
if (Number.isNaN(id)) return new Response('Invalid id', { status: 400 });
|
||||
|
||||
const body = await getEntryFromReq(req);
|
||||
if (!body) return new Response('Invalid data', { status: 400 });
|
||||
|
||||
await drizzleDB.update(entry).set(body).where(eq(entry.id, id)).execute();
|
||||
|
||||
let created = false;
|
||||
return new Response(JSON.stringify({ created: false }), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
},
|
||||
async DELETE(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const id = Number.parseInt(req.params.id, 10);
|
||||
if (Number.isNaN(id)) return new Response('Invalid id', { status: 400 });
|
||||
|
||||
await drizzleDB.delete(entry).where(eq(entry.id, id)).execute();
|
||||
|
||||
return new Response('OK');
|
||||
},
|
||||
},
|
||||
'/api/entries/:id/check/:finished': {
|
||||
async PUT(req) {
|
||||
if (!isAuthenticated(req)) return unauthorizedResp();
|
||||
|
||||
const id = Number.parseInt(req.params.id, 10);
|
||||
if (Number.isNaN(id)) return new Response('Invalid id', { status: 400 });
|
||||
const finished = req.params.finished === 'true';
|
||||
|
||||
await drizzleDB
|
||||
.update(entry)
|
||||
.set({ finished: finished })
|
||||
.where(eq(entry.id, id))
|
||||
.execute();
|
||||
|
||||
return new Response('OK');
|
||||
},
|
||||
},
|
||||
},
|
||||
development,
|
||||
reusePort: true,
|
||||
port: env.PORT || 3000,
|
||||
// async fetch(req, server) {
|
||||
// return new Response("Not found", { status: 404 });
|
||||
// },
|
||||
});
|
||||
|
||||
async function getEntryFromReq(req: Request) {
|
||||
const json = await req.json();
|
||||
const body = json as { name: string, href: string }
|
||||
if (!body.name || !body.href || typeof body.name !== 'string' || typeof body.href !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Trim and lowercase the name to ensure consistency and uniqueness
|
||||
body.name = body.name.trim().toLocaleLowerCase();
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function isAuthenticated(req: Request) {
|
||||
const bearer = req.headers.get('Bearer');
|
||||
if (!bearer) return false;
|
||||
|
||||
return bearer === env.BEARER_TOKEN;
|
||||
}
|
||||
|
||||
const unauthorizedHeaders = new Headers({
|
||||
'WWW-Authenticate': `Bearer realm='sign', error="invalid_request"`
|
||||
});
|
||||
|
||||
function unauthorizedResp() {
|
||||
return new Response('Unauthorized', { status: 401, headers: unauthorizedHeaders });
|
||||
}
|
BIN
src/static/favicon.png
Normal file
BIN
src/static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
10
src/static/manifest.json
Normal file
10
src/static/manifest.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "Progress tracker api by skaarup.dev",
|
||||
"short_name": "progress-tracker-api",
|
||||
"display": "browser",
|
||||
"background_color": "#141141",
|
||||
"theme_color": "#371D85",
|
||||
"description": "Progress tracker api by skaarup.dev",
|
||||
"icons": [],
|
||||
"related_applications": []
|
||||
}
|
4
src/static/robots.txt
Normal file
4
src/static/robots.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://pt-api.skaarup.dev/sitemap.txt
|
1
src/static/sitemap.txt
Normal file
1
src/static/sitemap.txt
Normal file
|
@ -0,0 +1 @@
|
|||
https://pt-api.skaarup.dev/
|
78
src/wrapped-timer.ts
Normal file
78
src/wrapped-timer.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
if (global.wrappedTimers === undefined) {
|
||||
global.wrappedTimers = new Map();
|
||||
}
|
||||
|
||||
type WrappedTimer = { timer: Timer | undefined; running: boolean; };
|
||||
type WrappedTimerResult = { callback: ReturnType<typeof getCallbackHandler>; wrappedTimer: WrappedTimer; };
|
||||
|
||||
/**
|
||||
* Create a callback handler for a wrapped timer that prevents the callback from running if it is already running
|
||||
* and prevents the callback from running if it is already running.
|
||||
* @template TArgs
|
||||
* @param {string} key unique identifier for the timer
|
||||
* @param {(...args: Array<TArgs>) => (Promise<void> | void)} callback function to run
|
||||
* @param {Array<TArgs>} args arguments to pass to the callback
|
||||
* @returns {() => Promise<void>}
|
||||
*/
|
||||
function getCallbackHandler<TArgs>(key: string, callback: (...args: Array<TArgs>) => (Promise<void> | void), ...args: Array<TArgs>): () => Promise<void> {
|
||||
return async () => {
|
||||
const thisTimer = global.wrappedTimers.get(key);
|
||||
if (thisTimer === undefined) {
|
||||
console.debug(`Wrapped timer ${key} does not exist`);
|
||||
return;
|
||||
}
|
||||
if (thisTimer.running) {
|
||||
console.debug(`Wrapped timer ${key} is already running`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
thisTimer.running = true;
|
||||
await callback(...args);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
thisTimer.running = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a wrapped timer aka interval
|
||||
* @template TArgs
|
||||
* @param {string} key unique identifier for the timer
|
||||
* @param {number} interval in milliseconds
|
||||
* @param {(...args: Array<TArgs>) => (Promise<void> | void)} callback function to run
|
||||
* @param {Array<TArgs>} args arguments to pass to the callback
|
||||
* @returns {WrappedTimerResult}
|
||||
*/
|
||||
export function createWrappedTimer<TArgs>(key: string, callback: (...args: Array<TArgs>) => (Promise<void> | void), interval: number, ...args: Array<TArgs>): WrappedTimerResult {
|
||||
const thisTimer = global.wrappedTimers.get(key);
|
||||
const handler = getCallbackHandler(key, callback, ...args);
|
||||
|
||||
if (thisTimer !== undefined) {
|
||||
console.debug(`Wrapped timer ${key} already exists, clearing timer`);
|
||||
clearInterval(thisTimer.timer);
|
||||
console.debug(`Wrapped timer ${key} set with interval ${interval}ms`);
|
||||
thisTimer.timer = setInterval(handler, interval);
|
||||
|
||||
return {
|
||||
callback: handler,
|
||||
wrappedTimer: thisTimer,
|
||||
};
|
||||
}
|
||||
|
||||
console.debug(`Wrapped timer ${key} created with interval ${interval}ms`);
|
||||
|
||||
const wrappedTimer: WrappedTimer = {
|
||||
timer: setInterval(handler, interval),
|
||||
running: false,
|
||||
};
|
||||
|
||||
global.wrappedTimers.set(key, wrappedTimer);
|
||||
|
||||
return {
|
||||
callback: handler,
|
||||
wrappedTimer,
|
||||
};
|
||||
}
|
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Enable latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": true,
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
Loading…
Add table
Reference in a new issue