From b7031bbd9da0c88808baf785be99731740faddf0 Mon Sep 17 00:00:00 2001 From: Ryan Pandya Date: Fri, 31 Jan 2025 18:09:27 -0800 Subject: [PATCH] Switch to Postgres --- .direnv/bin/nix-direnv-reload | 19 + .../r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source | 1 + .../xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source | 1 + .../yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source | 1 + .../yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source | 1 + .direnv/flake-profile | 1 - .direnv/flake-profile-2-link | 1 - ...e-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa | 1 + ...5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc | 2008 +++++++++++++++++ Dockerfile | 8 + apps/cli/bin/index.js | 2 +- apps/web/app/api/db/download/route.ts | 13 +- apps/web/app/api/db/upload/route.ts | 41 +- apps/web/app/dashboard/admin/page.tsx | 2 +- apps/web/app/layout.tsx | 2 +- .../dashboard/admin/DatabaseSettings.tsx | 8 +- .../dashboard/analytics/AnalyticsView.tsx | 34 +- .../dashboard/categories/CategoriesView.tsx | 4 +- .../dashboard/hours/EditableHour.tsx | 9 +- .../hours/HourMeasurementsDialog.tsx | 4 +- apps/web/package.json | 1 + apps/web/public/sw.js | 2 +- apps/web/uploads/uploaded.sql | Bin 0 -> 109477 bytes flake.nix | 3 +- package.json | 1 + packages/db/drizzle-sqlite.ts | 16 + packages/db/drizzle.config.ts | 22 +- packages/db/drizzle.ts | 37 +- packages/db/index.ts | 29 +- packages/db/lifetracker.db | Bin 77824 -> 0 bytes packages/db/migrate-to-postgres.ts | 63 + packages/db/migrate.ts | 17 +- packages/db/migrations/0000_moaning_thor.sql | 137 -- .../db/migrations/0000_redundant_glorian.sql | 215 ++ .../migrations/0001_modify_hour_datetime.sql | 18 + .../db/migrations/0002_seed_ryan_user.sql | 54 + packages/db/migrations/0003_silky_mongu.sql | 6 + .../db/migrations/0004_tan_justin_hammer.sql | 1 + .../db/migrations/meta/0000_snapshot.json | 460 ++-- .../db/migrations/meta/0001_snapshot.json | 901 ++++++++ .../db/migrations/meta/0002_snapshot.json | 901 ++++++++ .../db/migrations/meta/0003_snapshot.json | 901 ++++++++ .../db/migrations/meta/0004_snapshot.json | 895 ++++++++ packages/db/migrations/meta/_journal.json | 36 +- packages/db/package.json | 12 +- packages/db/schema.ts | 56 +- packages/shared/config.ts | 6 +- packages/shared/types/days.ts | 3 +- packages/trpc/routers/_app.ts | 1 - packages/trpc/routers/categories.ts | 6 +- packages/trpc/routers/colors.ts | 6 +- packages/trpc/routers/days.ts | 29 +- packages/trpc/routers/hours.ts | 64 +- packages/trpc/routers/measurements.ts | 49 +- packages/trpc/routers/metrics.ts | 6 +- packages/trpc/routers/users.ts | 6 +- pnpm-lock.yaml | 742 ++++-- 57 files changed, 7131 insertions(+), 732 deletions(-) create mode 100755 .direnv/bin/nix-direnv-reload create mode 120000 .direnv/flake-inputs/r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source create mode 120000 .direnv/flake-inputs/xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source create mode 120000 .direnv/flake-inputs/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source create mode 120000 .direnv/flake-inputs/yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source delete mode 120000 .direnv/flake-profile delete mode 120000 .direnv/flake-profile-2-link create mode 120000 .direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa create mode 100644 .direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc create mode 100644 apps/web/uploads/uploaded.sql create mode 100644 packages/db/drizzle-sqlite.ts delete mode 100644 packages/db/lifetracker.db create mode 100644 packages/db/migrate-to-postgres.ts delete mode 100644 packages/db/migrations/0000_moaning_thor.sql create mode 100644 packages/db/migrations/0000_redundant_glorian.sql create mode 100644 packages/db/migrations/0001_modify_hour_datetime.sql create mode 100644 packages/db/migrations/0002_seed_ryan_user.sql create mode 100644 packages/db/migrations/0003_silky_mongu.sql create mode 100644 packages/db/migrations/0004_tan_justin_hammer.sql create mode 100644 packages/db/migrations/meta/0001_snapshot.json create mode 100644 packages/db/migrations/meta/0002_snapshot.json create mode 100644 packages/db/migrations/meta/0003_snapshot.json create mode 100644 packages/db/migrations/meta/0004_snapshot.json diff --git a/.direnv/bin/nix-direnv-reload b/.direnv/bin/nix-direnv-reload new file mode 100755 index 0000000..575a929 --- /dev/null +++ b/.direnv/bin/nix-direnv-reload @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e +if [[ ! -d "/home/ryan/Documents/Code/lifetracker" ]]; then + echo "Cannot find source directory; Did you move it?" + echo "(Looking for "/home/ryan/Documents/Code/lifetracker")" + echo 'Cannot force reload with this script - use "direnv reload" manually and then try again' + exit 1 +fi + +# rebuild the cache forcefully +_nix_direnv_force_reload=1 direnv exec "/home/ryan/Documents/Code/lifetracker" true + +# Update the mtime for .envrc. +# This will cause direnv to reload again - but without re-building. +touch "/home/ryan/Documents/Code/lifetracker/.envrc" + +# Also update the timestamp of whatever profile_rc we have. +# This makes sure that we know we are up to date. +touch -r "/home/ryan/Documents/Code/lifetracker/.envrc" "/home/ryan/Documents/Code/lifetracker/.direnv"/*.rc diff --git a/.direnv/flake-inputs/r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source b/.direnv/flake-inputs/r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source new file mode 120000 index 0000000..3083fc4 --- /dev/null +++ b/.direnv/flake-inputs/r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source @@ -0,0 +1 @@ +/nix/store/r3pr5wyvfdi4h1b3wja7jcdwqjrfk9px-source \ No newline at end of file diff --git a/.direnv/flake-inputs/xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source b/.direnv/flake-inputs/xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source new file mode 120000 index 0000000..083370b --- /dev/null +++ b/.direnv/flake-inputs/xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source @@ -0,0 +1 @@ +/nix/store/xpkysrb9pn0yqrm1bkll4dr2gqahj43x-source \ No newline at end of file diff --git a/.direnv/flake-inputs/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source b/.direnv/flake-inputs/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source new file mode 120000 index 0000000..f17959f --- /dev/null +++ b/.direnv/flake-inputs/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source @@ -0,0 +1 @@ +/nix/store/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source \ No newline at end of file diff --git a/.direnv/flake-inputs/yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source b/.direnv/flake-inputs/yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source new file mode 120000 index 0000000..3b8fd00 --- /dev/null +++ b/.direnv/flake-inputs/yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source @@ -0,0 +1 @@ +/nix/store/yp0xr7fzkk7rjgp564pn28r7f2mpdcj1-source \ No newline at end of file diff --git a/.direnv/flake-profile b/.direnv/flake-profile deleted file mode 120000 index c7ae5b7..0000000 --- a/.direnv/flake-profile +++ /dev/null @@ -1 +0,0 @@ -flake-profile-2-link \ No newline at end of file diff --git a/.direnv/flake-profile-2-link b/.direnv/flake-profile-2-link deleted file mode 120000 index d6e9d0a..0000000 --- a/.direnv/flake-profile-2-link +++ /dev/null @@ -1 +0,0 @@ -/nix/store/w46qqqb484a76v5k0lzv524yp9s89vly-nix-shell-env \ No newline at end of file diff --git a/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa b/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa new file mode 120000 index 0000000..5cb5b42 --- /dev/null +++ b/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa @@ -0,0 +1 @@ +/nix/store/11hqs52hdjhxhcb8idddn312grl1hr5i-nix-shell-env \ No newline at end of file diff --git a/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc b/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc new file mode 100644 index 0000000..f105665 --- /dev/null +++ b/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc @@ -0,0 +1,2008 @@ +unset shellHook +PATH=${PATH:-} +nix_saved_PATH="$PATH" +XDG_DATA_DIRS=${XDG_DATA_DIRS:-} +nix_saved_XDG_DATA_DIRS="$XDG_DATA_DIRS" +AR='ar' +export AR +AS='as' +export AS +BASH='/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin/bash' +CC='gcc' +export CC +CONFIG_SHELL='/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin/bash' +export CONFIG_SHELL +CXX='g++' +export CXX +HOSTTYPE='x86_64' +HOST_PATH='/nix/store/qqz0gj9iaidabp7g34r2fb9mds6ahk8i-bash-interactive-5.2p32/bin:/nix/store/0l63mqr7qx1asjxfz86j4zbs4758gn98-git-2.46.0/bin:/nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4/bin:/nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0/bin:/nix/store/8zlqhgw5hbakbk2850wvky9x2vqbsqyw-pnpm-9.10.0/bin:/nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/bin:/nix/store/1gax5xs6h1b70gk7z274kx4qh04hsn96-postgresql-16.4/bin:/nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/bin:/nix/store/0kg70swgpg45ipcz3pr2siidq9fn6d77-coreutils-9.5/bin:/nix/store/fnq94lw19pnwdl9p8zhfrad4jmlgxlbr-findutils-4.10.0/bin:/nix/store/7jk4jrd99ngnm9iczcf63mfxqba0ak2y-diffutils-3.10/bin:/nix/store/gjlh1zvckhz0qv795lnzgw2zciklbzj2-gnused-4.9/bin:/nix/store/vsyc8jhsr4d9lm2r8yqq9n3j4i66inlj-gnugrep-3.11/bin:/nix/store/9hifsxkcrkvvb712ghnr3gy5g1aiym2d-gawk-5.2.2/bin:/nix/store/l2l5xr2zczq19gqpqz4j8vxxia1j41s1-gnutar-1.35/bin:/nix/store/164s7a7yscnicprzrr78bvk45d77a3yg-gzip-1.13/bin:/nix/store/f8p74dj4r4my8sw5prmm3y4ddkz7591j-bzip2-1.0.8-bin/bin:/nix/store/axrdky652lsmif6m5i8b55q91v4ly4gy-gnumake-4.4.1/bin:/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin:/nix/store/7wg4bz2sika3wd7541rndbnwcq6k9h8v-patch-2.7.6/bin:/nix/store/02mf752h7f5fn7989awzca4ygy94k7w7-xz-5.6.2-bin/bin:/nix/store/fv56zpi80jpakbfmv16r60xvyqwzff6r-file-5.45/bin' +export HOST_PATH +IFS=' +' +IN_NIX_SHELL='impure' +export IN_NIX_SHELL +LD='ld' +export LD +LINENO='76' +LOCALE_ARCHIVE='/nix/store/rhjqirbv6p5r6qaiill2k30bqdx84c62-glibc-locales-2.39-52/lib/locale/locale-archive' +export LOCALE_ARCHIVE +MACHTYPE='x86_64-pc-linux-gnu' +NIX_BINTOOLS='/nix/store/b74nxf0yn2dzha02mgdxyklaqjaijzqp-binutils-wrapper-2.42' +export NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1' +export NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES='16' +export NIX_BUILD_CORES +NIX_CC='/nix/store/zznja5f8v3jafffyah1rk46vpfcn38dv-gcc-wrapper-13.3.0' +export NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1' +export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE=' -frandom-seed=11hqs52hdj -isystem /nix/store/vh3vhwg8s5v1n019svwi6xzrn4jds047-bash-interactive-5.2p32-dev/include -isystem /nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4/include -isystem /nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0/include -isystem /nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/include -isystem /nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/include -isystem /nix/store/vh3vhwg8s5v1n019svwi6xzrn4jds047-bash-interactive-5.2p32-dev/include -isystem /nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4/include -isystem /nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0/include -isystem /nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/include -isystem /nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/include' +export NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE='1' +export NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE='bindnow format fortify fortify3 pic relro stackprotector strictoverflow zerocallusedregs' +export NIX_HARDENING_ENABLE +NIX_LDFLAGS='-rpath /home/ryan/Documents/Code/lifetracker/outputs/out/lib -L/nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/lib -L/nix/store/l54jqbzqhghvy3g9kqhmcha9z3vzzrxr-postgresql-16.4-lib/lib -L/nix/store/1gax5xs6h1b70gk7z274kx4qh04hsn96-postgresql-16.4/lib -L/nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/lib -L/nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/lib -L/nix/store/l54jqbzqhghvy3g9kqhmcha9z3vzzrxr-postgresql-16.4-lib/lib -L/nix/store/1gax5xs6h1b70gk7z274kx4qh04hsn96-postgresql-16.4/lib -L/nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/lib' +export NIX_LDFLAGS +NIX_NO_SELF_RPATH='1' +NIX_STORE='/nix/store' +export NIX_STORE +NM='nm' +export NM +NODE_PATH='/nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0/lib/node_modules' +export NODE_PATH +OBJCOPY='objcopy' +export OBJCOPY +OBJDUMP='objdump' +export OBJDUMP +OLDPWD='' +export OLDPWD +OPTERR='1' +OSTYPE='linux-gnu' +PATH='/nix/store/k97fic16vmpf9z6vjx5dgd6rxcvv5wwh-patchelf-0.15.0/bin:/nix/store/zznja5f8v3jafffyah1rk46vpfcn38dv-gcc-wrapper-13.3.0/bin:/nix/store/x8rg4vhgd20i8vzykm1196f9qdb8klhh-gcc-13.3.0/bin:/nix/store/k4jv8fr725amxalmplzhnlyik93wvk3z-glibc-2.39-52-bin/bin:/nix/store/0kg70swgpg45ipcz3pr2siidq9fn6d77-coreutils-9.5/bin:/nix/store/b74nxf0yn2dzha02mgdxyklaqjaijzqp-binutils-wrapper-2.42/bin:/nix/store/81xsp348yfgmaan9r5055mcdjfw7a8wc-binutils-2.42/bin:/nix/store/qqz0gj9iaidabp7g34r2fb9mds6ahk8i-bash-interactive-5.2p32/bin:/nix/store/0l63mqr7qx1asjxfz86j4zbs4758gn98-git-2.46.0/bin:/nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4/bin:/nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0/bin:/nix/store/8zlqhgw5hbakbk2850wvky9x2vqbsqyw-pnpm-9.10.0/bin:/nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev/bin:/nix/store/1gax5xs6h1b70gk7z274kx4qh04hsn96-postgresql-16.4/bin:/nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0/bin:/nix/store/0kg70swgpg45ipcz3pr2siidq9fn6d77-coreutils-9.5/bin:/nix/store/fnq94lw19pnwdl9p8zhfrad4jmlgxlbr-findutils-4.10.0/bin:/nix/store/7jk4jrd99ngnm9iczcf63mfxqba0ak2y-diffutils-3.10/bin:/nix/store/gjlh1zvckhz0qv795lnzgw2zciklbzj2-gnused-4.9/bin:/nix/store/vsyc8jhsr4d9lm2r8yqq9n3j4i66inlj-gnugrep-3.11/bin:/nix/store/9hifsxkcrkvvb712ghnr3gy5g1aiym2d-gawk-5.2.2/bin:/nix/store/l2l5xr2zczq19gqpqz4j8vxxia1j41s1-gnutar-1.35/bin:/nix/store/164s7a7yscnicprzrr78bvk45d77a3yg-gzip-1.13/bin:/nix/store/f8p74dj4r4my8sw5prmm3y4ddkz7591j-bzip2-1.0.8-bin/bin:/nix/store/axrdky652lsmif6m5i8b55q91v4ly4gy-gnumake-4.4.1/bin:/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin:/nix/store/7wg4bz2sika3wd7541rndbnwcq6k9h8v-patch-2.7.6/bin:/nix/store/02mf752h7f5fn7989awzca4ygy94k7w7-xz-5.6.2-bin/bin:/nix/store/fv56zpi80jpakbfmv16r60xvyqwzff6r-file-5.45/bin' +export PATH +PS4='+ ' +RANLIB='ranlib' +export RANLIB +READELF='readelf' +export READELF +SHELL='/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin/bash' +export SHELL +SIZE='size' +export SIZE +SOURCE_DATE_EPOCH='315532800' +export SOURCE_DATE_EPOCH +STRINGS='strings' +export STRINGS +STRIP='strip' +export STRIP +XDG_DATA_DIRS='/nix/store/k97fic16vmpf9z6vjx5dgd6rxcvv5wwh-patchelf-0.15.0/share' +export XDG_DATA_DIRS +__structuredAttrs='' +export __structuredAttrs +_substituteStream_has_warned_replace_deprecation='false' +buildInputs='/nix/store/vh3vhwg8s5v1n019svwi6xzrn4jds047-bash-interactive-5.2p32-dev /nix/store/rhjqirbv6p5r6qaiill2k30bqdx84c62-glibc-locales-2.39-52 /nix/store/0l63mqr7qx1asjxfz86j4zbs4758gn98-git-2.46.0 /nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4 /nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0 /nix/store/8zlqhgw5hbakbk2850wvky9x2vqbsqyw-pnpm-9.10.0 /nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev /nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0' +export buildInputs +buildPhase='{ echo "------------------------------------------------------------"; + echo " WARNING: the existence of this path is not guaranteed."; + echo " It is an internal implementation detail for pkgs.mkShell."; + echo "------------------------------------------------------------"; + echo; + # Record all build inputs as runtime dependencies + export; +} >> "$out" +' +export buildPhase +builder='/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin/bash' +export builder +cmakeFlags='' +export cmakeFlags +configureFlags='' +export configureFlags +defaultBuildInputs='' +defaultNativeBuildInputs='/nix/store/k97fic16vmpf9z6vjx5dgd6rxcvv5wwh-patchelf-0.15.0 /nix/store/9l3havpzc3w1xggd19l5c395az4yh449-update-autotools-gnu-config-scripts-hook /nix/store/h9lc1dpi14z7is86ffhl3ld569138595-audit-tmpdir.sh /nix/store/m54bmrhj6fqz8nds5zcj97w9s9bckc9v-compress-man-pages.sh /nix/store/wgrbkkaldkrlrni33ccvm3b6vbxzb656-make-symlinks-relative.sh /nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh /nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh /nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh /nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh /nix/store/jivxp510zxakaaic7qkrb7v1dd2rdbw9-multiple-outputs.sh /nix/store/12lvf0c7xric9cny7slvf9cmhypl1p67-patch-shebangs.sh /nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh /nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh /nix/store/aazf105snicrlvyzzbdj85sx4179rpfp-set-source-date-epoch-to-latest.sh /nix/store/gps9qrh99j7g02840wv5x78ykmz30byp-strip.sh /nix/store/zznja5f8v3jafffyah1rk46vpfcn38dv-gcc-wrapper-13.3.0' +depsBuildBuild='' +export depsBuildBuild +depsBuildBuildPropagated='' +export depsBuildBuildPropagated +depsBuildTarget='' +export depsBuildTarget +depsBuildTargetPropagated='' +export depsBuildTargetPropagated +depsHostHost='' +export depsHostHost +depsHostHostPropagated='' +export depsHostHostPropagated +depsTargetTarget='' +export depsTargetTarget +depsTargetTargetPropagated='' +export depsTargetTargetPropagated +doCheck='' +export doCheck +doInstallCheck='' +export doInstallCheck +dontAddDisableDepTrack='1' +export dontAddDisableDepTrack +declare -a envBuildBuildHooks=() +declare -a envBuildHostHooks=() +declare -a envBuildTargetHooks=() +declare -a envHostHostHooks=('ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' 'addNodePath' ) +declare -a envHostTargetHooks=('ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' 'addNodePath' ) +declare -a envTargetTargetHooks=() +declare -a fixupOutputHooks=('if [ -z "${dontPatchELF-}" ]; then patchELF "$prefix"; fi' 'if [[ -z "${noAuditTmpdir-}" && -e "$prefix" ]]; then auditTmpdir "$prefix"; fi' 'if [ -z "${dontGzipMan-}" ]; then compressManPages "$prefix"; fi' '_moveLib64' '_moveSbin' '_moveSystemdUserUnits' 'patchShebangsAuto' '_pruneLibtoolFiles' '_doStrip' ) +guess='16' +initialPath='/nix/store/0kg70swgpg45ipcz3pr2siidq9fn6d77-coreutils-9.5 /nix/store/fnq94lw19pnwdl9p8zhfrad4jmlgxlbr-findutils-4.10.0 /nix/store/7jk4jrd99ngnm9iczcf63mfxqba0ak2y-diffutils-3.10 /nix/store/gjlh1zvckhz0qv795lnzgw2zciklbzj2-gnused-4.9 /nix/store/vsyc8jhsr4d9lm2r8yqq9n3j4i66inlj-gnugrep-3.11 /nix/store/9hifsxkcrkvvb712ghnr3gy5g1aiym2d-gawk-5.2.2 /nix/store/l2l5xr2zczq19gqpqz4j8vxxia1j41s1-gnutar-1.35 /nix/store/164s7a7yscnicprzrr78bvk45d77a3yg-gzip-1.13 /nix/store/f8p74dj4r4my8sw5prmm3y4ddkz7591j-bzip2-1.0.8-bin /nix/store/axrdky652lsmif6m5i8b55q91v4ly4gy-gnumake-4.4.1 /nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32 /nix/store/7wg4bz2sika3wd7541rndbnwcq6k9h8v-patch-2.7.6 /nix/store/02mf752h7f5fn7989awzca4ygy94k7w7-xz-5.6.2-bin /nix/store/fv56zpi80jpakbfmv16r60xvyqwzff6r-file-5.45' +mesonFlags='' +export mesonFlags +name='nix-shell-env' +export name +nativeBuildInputs='' +export nativeBuildInputs +out='/home/ryan/Documents/Code/lifetracker/outputs/out' +export out +outputBin='out' +outputDev='out' +outputDevdoc='REMOVE' +outputDevman='out' +outputDoc='out' +outputInclude='out' +outputInfo='out' +outputLib='out' +outputMan='out' +outputs='out' +export outputs +patches='' +export patches +phases='buildPhase' +export phases +pkg='/nix/store/zznja5f8v3jafffyah1rk46vpfcn38dv-gcc-wrapper-13.3.0' +declare -a pkgsBuildBuild=() +declare -a pkgsBuildHost=('/nix/store/k97fic16vmpf9z6vjx5dgd6rxcvv5wwh-patchelf-0.15.0' '/nix/store/9l3havpzc3w1xggd19l5c395az4yh449-update-autotools-gnu-config-scripts-hook' '/nix/store/h9lc1dpi14z7is86ffhl3ld569138595-audit-tmpdir.sh' '/nix/store/m54bmrhj6fqz8nds5zcj97w9s9bckc9v-compress-man-pages.sh' '/nix/store/wgrbkkaldkrlrni33ccvm3b6vbxzb656-make-symlinks-relative.sh' '/nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh' '/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh' '/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh' '/nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh' '/nix/store/jivxp510zxakaaic7qkrb7v1dd2rdbw9-multiple-outputs.sh' '/nix/store/12lvf0c7xric9cny7slvf9cmhypl1p67-patch-shebangs.sh' '/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh' '/nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh' '/nix/store/aazf105snicrlvyzzbdj85sx4179rpfp-set-source-date-epoch-to-latest.sh' '/nix/store/gps9qrh99j7g02840wv5x78ykmz30byp-strip.sh' '/nix/store/zznja5f8v3jafffyah1rk46vpfcn38dv-gcc-wrapper-13.3.0' '/nix/store/b74nxf0yn2dzha02mgdxyklaqjaijzqp-binutils-wrapper-2.42' ) +declare -a pkgsBuildTarget=() +declare -a pkgsHostHost=() +declare -a pkgsHostTarget=('/nix/store/vh3vhwg8s5v1n019svwi6xzrn4jds047-bash-interactive-5.2p32-dev' '/nix/store/qqz0gj9iaidabp7g34r2fb9mds6ahk8i-bash-interactive-5.2p32' '/nix/store/rhjqirbv6p5r6qaiill2k30bqdx84c62-glibc-locales-2.39-52' '/nix/store/0l63mqr7qx1asjxfz86j4zbs4758gn98-git-2.46.0' '/nix/store/2gcih2fhiam3bpkpfbnb2d088brwpcnm-emacs-nox-29.4' '/nix/store/w78sh036dyn14f29w8za9ni9syrmwm3q-nodejs-20.17.0' '/nix/store/8zlqhgw5hbakbk2850wvky9x2vqbsqyw-pnpm-9.10.0' '/nix/store/45if5nl708nhayxnaqh7h2scz9pn4mn8-postgresql-16.4-dev' '/nix/store/l54jqbzqhghvy3g9kqhmcha9z3vzzrxr-postgresql-16.4-lib' '/nix/store/1gax5xs6h1b70gk7z274kx4qh04hsn96-postgresql-16.4' '/nix/store/c7lxmwsnnh3865advh3vj2z3qdcrkcv1-inotify-tools-4.23.9.0' ) +declare -a pkgsTargetTarget=() +declare -a postFixupHooks=('_makeSymlinksRelativeInAllOutputs' '_multioutPropagateDev' ) +declare -a postUnpackHooks=('_updateSourceDateEpochFromSourceRoot' ) +declare -a preConfigureHooks=('_multioutConfig' ) +preConfigurePhases=' updateAutotoolsGnuConfigScriptsPhase' +declare -a preFixupHooks=('_moveToShare' '_multioutDocs' '_multioutDevs' ) +preferLocalBuild='1' +export preferLocalBuild +prefix='/home/ryan/Documents/Code/lifetracker/outputs/out' +declare -a propagatedBuildDepFiles=('propagated-build-build-deps' 'propagated-native-build-inputs' 'propagated-build-target-deps' ) +propagatedBuildInputs='' +export propagatedBuildInputs +declare -a propagatedHostDepFiles=('propagated-host-host-deps' 'propagated-build-inputs' ) +propagatedNativeBuildInputs='' +export propagatedNativeBuildInputs +declare -a propagatedTargetDepFiles=('propagated-target-target-deps' ) +shell='/nix/store/izpf49b74i15pcr9708s3xdwyqs4jxwl-bash-5.2p32/bin/bash' +export shell +shellHook='' +export shellHook +stdenv='/nix/store/91d27rjqlhkzx7mhzxrir1jcr40nyc7p-stdenv-linux' +export stdenv +strictDeps='' +export strictDeps +system='x86_64-linux' +export system +declare -a unpackCmdHooks=('_defaultUnpack' ) +_activatePkgs () +{ + + local hostOffset targetOffset; + local pkg; + for hostOffset in "${allPlatOffsets[@]}"; + do + local pkgsVar="${pkgAccumVarVars[hostOffset + 1]}"; + for targetOffset in "${allPlatOffsets[@]}"; + do + (( hostOffset <= targetOffset )) || continue; + local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]"; + local pkgsSlice="${!pkgsRef}[@]"; + for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; + do + activatePackage "$pkg" "$hostOffset" "$targetOffset"; + done; + done; + done +} +_addRpathPrefix () +{ + + if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then + export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}"; + fi +} +_addToEnv () +{ + + local depHostOffset depTargetOffset; + local pkg; + for depHostOffset in "${allPlatOffsets[@]}"; + do + local hookVar="${pkgHookVarVars[depHostOffset + 1]}"; + local pkgsVar="${pkgAccumVarVars[depHostOffset + 1]}"; + for depTargetOffset in "${allPlatOffsets[@]}"; + do + (( depHostOffset <= depTargetOffset )) || continue; + local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"; + if [[ -z "${strictDeps-}" ]]; then + local visitedPkgs=""; + for pkg in "${pkgsBuildBuild[@]}" "${pkgsBuildHost[@]}" "${pkgsBuildTarget[@]}" "${pkgsHostHost[@]}" "${pkgsHostTarget[@]}" "${pkgsTargetTarget[@]}"; + do + if [[ "$visitedPkgs" = *"$pkg"* ]]; then + continue; + fi; + runHook "${!hookRef}" "$pkg"; + visitedPkgs+=" $pkg"; + done; + else + local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]"; + local pkgsSlice="${!pkgsRef}[@]"; + for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; + do + runHook "${!hookRef}" "$pkg"; + done; + fi; + done; + done +} +_allFlags () +{ + + export system pname name version; + while IFS='' read -r varName; do + nixTalkativeLog "@${varName}@ -> ${!varName}"; + args+=("--subst-var" "$varName"); + done < <(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }') +} +_assignFirst () +{ + + local varName="$1"; + local _var; + local REMOVE=REMOVE; + shift; + for _var in "$@"; + do + if [ -n "${!_var-}" ]; then + eval "${varName}"="${_var}"; + return; + fi; + done; + echo; + echo "error: _assignFirst: could not find a non-empty variable whose name to assign to ${varName}."; + echo " The following variables were all unset or empty:"; + echo " $*"; + if [ -z "${out:-}" ]; then + echo ' If you do not want an "out" output in your derivation, make sure to define'; + echo ' the other specific required outputs. This can be achieved by picking one'; + echo " of the above as an output."; + echo ' You do not have to remove "out" if you want to have a different default'; + echo ' output, because the first output is taken as a default.'; + echo; + fi; + return 1 +} +_callImplicitHook () +{ + + local def="$1"; + local hookName="$2"; + if declare -F "$hookName" > /dev/null; then + nixTalkativeLog "calling implicit '$hookName' function hook"; + "$hookName"; + else + if type -p "$hookName" > /dev/null; then + nixTalkativeLog "sourcing implicit '$hookName' script hook"; + source "$hookName"; + else + if [ -n "${!hookName:-}" ]; then + nixTalkativeLog "evaling implicit '$hookName' string hook"; + eval "${!hookName}"; + else + return "$def"; + fi; + fi; + fi +} +_defaultUnpack () +{ + + local fn="$1"; + local destination; + if [ -d "$fn" ]; then + destination="$(stripHash "$fn")"; + if [ -e "$destination" ]; then + echo "Cannot copy $fn to $destination: destination already exists!"; + echo "Did you specify two \"srcs\" with the same \"name\"?"; + return 1; + fi; + cp -pr --reflink=auto -- "$fn" "$destination"; + else + case "$fn" in + *.tar.xz | *.tar.lzma | *.txz) + ( XZ_OPT="--threads=$NIX_BUILD_CORES" xz -d < "$fn"; + true ) | tar xf - --mode=+w --warning=no-timestamp + ;; + *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz) + tar xf "$fn" --mode=+w --warning=no-timestamp + ;; + *) + return 1 + ;; + esac; + fi +} +_doStrip () +{ + + local -ra flags=(dontStripHost dontStripTarget); + local -ra debugDirs=(stripDebugList stripDebugListTarget); + local -ra allDirs=(stripAllList stripAllListTarget); + local -ra stripCmds=(STRIP STRIP_FOR_TARGET); + local -ra ranlibCmds=(RANLIB RANLIB_FOR_TARGET); + stripDebugList=${stripDebugList[*]:-lib lib32 lib64 libexec bin sbin}; + stripDebugListTarget=${stripDebugListTarget[*]:-}; + stripAllList=${stripAllList[*]:-}; + stripAllListTarget=${stripAllListTarget[*]:-}; + local i; + for i in ${!stripCmds[@]}; + do + local -n flag="${flags[$i]}"; + local -n debugDirList="${debugDirs[$i]}"; + local -n allDirList="${allDirs[$i]}"; + local -n stripCmd="${stripCmds[$i]}"; + local -n ranlibCmd="${ranlibCmds[$i]}"; + if [[ -n "${dontStrip-}" || -n "${flag-}" ]] || ! type -f "${stripCmd-}" 2> /dev/null 1>&2; then + continue; + fi; + stripDirs "$stripCmd" "$ranlibCmd" "$debugDirList" "${stripDebugFlags[*]:--S -p}"; + stripDirs "$stripCmd" "$ranlibCmd" "$allDirList" "${stripAllFlags[*]:--s -p}"; + done +} +_eval () +{ + + if declare -F "$1" > /dev/null 2>&1; then + "$@"; + else + eval "$1"; + fi +} +_logHook () +{ + + if [[ -z ${NIX_LOG_FD-} ]]; then + return; + fi; + local hookKind="$1"; + local hookExpr="$2"; + shift 2; + if declare -F "$hookExpr" > /dev/null 2>&1; then + nixTalkativeLog "calling '$hookKind' function hook '$hookExpr'" "$@"; + else + if type -p "$hookExpr" > /dev/null; then + nixTalkativeLog "sourcing '$hookKind' script hook '$hookExpr'"; + else + if [[ "$hookExpr" != "_callImplicitHook"* ]]; then + local exprToOutput; + if [[ ${NIX_DEBUG:-0} -ge 5 ]]; then + exprToOutput="$hookExpr"; + else + local hookExprLine; + while IFS= read -r hookExprLine; do + hookExprLine="${hookExprLine#"${hookExprLine%%[![:space:]]*}"}"; + if [[ -n "$hookExprLine" ]]; then + exprToOutput+="$hookExprLine\\n "; + fi; + done <<< "$hookExpr"; + exprToOutput="${exprToOutput%%\\n }"; + fi; + nixTalkativeLog "evaling '$hookKind' string hook '$exprToOutput'"; + fi; + fi; + fi +} +_makeSymlinksRelative () +{ + + local symlinkTarget; + if [ "${dontRewriteSymlinks-}" ] || [ ! -e "$prefix" ]; then + return; + fi; + while IFS= read -r -d '' f; do + symlinkTarget=$(readlink "$f"); + if [[ "$symlinkTarget"/ != "$prefix"/* ]]; then + continue; + fi; + if [ ! -e "$symlinkTarget" ]; then + echo "the symlink $f is broken, it points to $symlinkTarget (which is missing)"; + fi; + echo "rewriting symlink $f to be relative to $prefix"; + ln -snrf "$symlinkTarget" "$f"; + done < <(find $prefix -type l -print0) +} +_makeSymlinksRelativeInAllOutputs () +{ + + local output; + for output in $(getAllOutputNames); + do + prefix="${!output}" _makeSymlinksRelative; + done +} +_moveLib64 () +{ + + if [ "${dontMoveLib64-}" = 1 ]; then + return; + fi; + if [ ! -e "$prefix/lib64" -o -L "$prefix/lib64" ]; then + return; + fi; + echo "moving $prefix/lib64/* to $prefix/lib"; + mkdir -p $prefix/lib; + shopt -s dotglob; + for i in $prefix/lib64/*; + do + mv --no-clobber "$i" $prefix/lib; + done; + shopt -u dotglob; + rmdir $prefix/lib64; + ln -s lib $prefix/lib64 +} +_moveSbin () +{ + + if [ "${dontMoveSbin-}" = 1 ]; then + return; + fi; + if [ ! -e "$prefix/sbin" -o -L "$prefix/sbin" ]; then + return; + fi; + echo "moving $prefix/sbin/* to $prefix/bin"; + mkdir -p $prefix/bin; + shopt -s dotglob; + for i in $prefix/sbin/*; + do + mv "$i" $prefix/bin; + done; + shopt -u dotglob; + rmdir $prefix/sbin; + ln -s bin $prefix/sbin +} +_moveSystemdUserUnits () +{ + + if [ "${dontMoveSystemdUserUnits:-0}" = 1 ]; then + return; + fi; + if [ ! -e "${prefix:?}/lib/systemd/user" ]; then + return; + fi; + local source="$prefix/lib/systemd/user"; + local target="$prefix/share/systemd/user"; + echo "moving $source/* to $target"; + mkdir -p "$target"; + ( shopt -s dotglob; + for i in "$source"/*; + do + mv "$i" "$target"; + done ); + rmdir "$source"; + ln -s "$target" "$source" +} +_moveToShare () +{ + + if [ -n "$__structuredAttrs" ]; then + if [ -z "${forceShare-}" ]; then + forceShare=(man doc info); + fi; + else + forceShare=(${forceShare:-man doc info}); + fi; + if [[ -z "$out" ]]; then + return; + fi; + for d in "${forceShare[@]}"; + do + if [ -d "$out/$d" ]; then + if [ -d "$out/share/$d" ]; then + echo "both $d/ and share/$d/ exist!"; + else + echo "moving $out/$d to $out/share/$d"; + mkdir -p $out/share; + mv $out/$d $out/share/; + fi; + fi; + done +} +_multioutConfig () +{ + + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${setOutputFlags-1}" ]; then + return; + fi; + if [ -z "${shareDocName:-}" ]; then + local confScript="${configureScript:-}"; + if [ -z "$confScript" ] && [ -x ./configure ]; then + confScript=./configure; + fi; + if [ -f "$confScript" ]; then + local shareDocName="$(sed -n "s/^PACKAGE_TARNAME='\(.*\)'$/\1/p" < "$confScript")"; + fi; + if [ -z "$shareDocName" ] || echo "$shareDocName" | grep -q '[^a-zA-Z0-9_-]'; then + shareDocName="$(echo "$name" | sed 's/-[^a-zA-Z].*//')"; + fi; + fi; + prependToVar configureFlags --bindir="${!outputBin}"/bin --sbindir="${!outputBin}"/sbin --includedir="${!outputInclude}"/include --oldincludedir="${!outputInclude}"/include --mandir="${!outputMan}"/share/man --infodir="${!outputInfo}"/share/info --docdir="${!outputDoc}"/share/doc/"${shareDocName}" --libdir="${!outputLib}"/lib --libexecdir="${!outputLib}"/libexec --localedir="${!outputLib}"/share/locale; + prependToVar installFlags pkgconfigdir="${!outputDev}"/lib/pkgconfig m4datadir="${!outputDev}"/share/aclocal aclocaldir="${!outputDev}"/share/aclocal +} +_multioutDevs () +{ + + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${moveToDev-1}" ]; then + return; + fi; + moveToOutput include "${!outputInclude}"; + moveToOutput lib/pkgconfig "${!outputDev}"; + moveToOutput share/pkgconfig "${!outputDev}"; + moveToOutput lib/cmake "${!outputDev}"; + moveToOutput share/aclocal "${!outputDev}"; + for f in "${!outputDev}"/{lib,share}/pkgconfig/*.pc; + do + echo "Patching '$f' includedir to output ${!outputInclude}"; + sed -i "/^includedir=/s,=\${prefix},=${!outputInclude}," "$f"; + done +} +_multioutDocs () +{ + + local REMOVE=REMOVE; + moveToOutput share/info "${!outputInfo}"; + moveToOutput share/doc "${!outputDoc}"; + moveToOutput share/gtk-doc "${!outputDevdoc}"; + moveToOutput share/devhelp/books "${!outputDevdoc}"; + moveToOutput share/man "${!outputMan}"; + moveToOutput share/man/man3 "${!outputDevman}" +} +_multioutPropagateDev () +{ + + if [ "$(getAllOutputNames)" = "out" ]; then + return; + fi; + local outputFirst; + for outputFirst in $(getAllOutputNames); + do + break; + done; + local propagaterOutput="$outputDev"; + if [ -z "$propagaterOutput" ]; then + propagaterOutput="$outputFirst"; + fi; + if [ -z "${propagatedBuildOutputs+1}" ]; then + local po_dirty="$outputBin $outputInclude $outputLib"; + set +o pipefail; + propagatedBuildOutputs=`echo "$po_dirty" | tr -s ' ' '\n' | grep -v -F "$propagaterOutput" | sort -u | tr '\n' ' ' `; + set -o pipefail; + fi; + if [ -z "$propagatedBuildOutputs" ]; then + return; + fi; + mkdir -p "${!propagaterOutput}"/nix-support; + for output in $propagatedBuildOutputs; + do + echo -n " ${!output}" >> "${!propagaterOutput}"/nix-support/propagated-build-inputs; + done +} +_overrideFirst () +{ + + if [ -z "${!1-}" ]; then + _assignFirst "$@"; + fi +} +_pruneLibtoolFiles () +{ + + if [ "${dontPruneLibtoolFiles-}" ] || [ ! -e "$prefix" ]; then + return; + fi; + find "$prefix" -type f -name '*.la' -exec grep -q '^# Generated by .*libtool' {} \; -exec grep -q "^old_library=''" {} \; -exec sed -i {} -e "/^dependency_libs='[^']/ c dependency_libs='' #pruned" \; +} +_updateSourceDateEpochFromSourceRoot () +{ + + if [ -n "$sourceRoot" ]; then + updateSourceDateEpoch "$sourceRoot"; + fi +} +activatePackage () +{ + + local pkg="$1"; + local -r hostOffset="$2"; + local -r targetOffset="$3"; + (( hostOffset <= targetOffset )) || exit 1; + if [ -f "$pkg" ]; then + nixTalkativeLog "sourcing setup hook '$pkg'"; + source "$pkg"; + fi; + if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then + addToSearchPath _PATH "$pkg/bin"; + fi; + if (( hostOffset <= -1 )); then + addToSearchPath _XDG_DATA_DIRS "$pkg/share"; + fi; + if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then + addToSearchPath _HOST_PATH "$pkg/bin"; + fi; + if [[ -f "$pkg/nix-support/setup-hook" ]]; then + nixTalkativeLog "sourcing setup hook '$pkg/nix-support/setup-hook'"; + source "$pkg/nix-support/setup-hook"; + fi +} +addEnvHooks () +{ + + local depHostOffset="$1"; + shift; + local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]"; + local pkgHookVar; + for pkgHookVar in "${!pkgHookVarsSlice}"; + do + eval "${pkgHookVar}s"'+=("$@")'; + done +} +addNodePath () +{ + + addToSearchPath NODE_PATH "$1/lib/node_modules" +} +addToSearchPath () +{ + + addToSearchPathWithCustomDelimiter ":" "$@" +} +addToSearchPathWithCustomDelimiter () +{ + + local delimiter="$1"; + local varName="$2"; + local dir="$3"; + if [[ -d "$dir" && "${!varName:+${delimiter}${!varName}${delimiter}}" != *"${delimiter}${dir}${delimiter}"* ]]; then + export "${varName}=${!varName:+${!varName}${delimiter}}${dir}"; + fi +} +appendToVar () +{ + + local -n nameref="$1"; + local useArray type; + if [ -n "$__structuredAttrs" ]; then + useArray=true; + else + useArray=false; + fi; + if type=$(declare -p "$1" 2> /dev/null); then + case "${type#* }" in + -A*) + echo "appendToVar(): ERROR: trying to use appendToVar on an associative array, use variable+=([\"X\"]=\"Y\") instead." 1>&2; + return 1 + ;; + -a*) + useArray=true + ;; + *) + useArray=false + ;; + esac; + fi; + shift; + if $useArray; then + nameref=(${nameref+"${nameref[@]}"} "$@"); + else + nameref="${nameref-} $*"; + fi +} +auditTmpdir () +{ + + local dir="$1"; + [ -e "$dir" ] || return 0; + echo "checking for references to $TMPDIR/ in $dir..."; + local i; + find "$dir" -type f -print0 | while IFS= read -r -d '' i; do + if [[ "$i" =~ .build-id ]]; then + continue; + fi; + if isELF "$i"; then + if { + printf :; + patchelf --print-rpath "$i" + } | grep -q -F ":$TMPDIR/"; then + echo "RPATH of binary $i contains a forbidden reference to $TMPDIR/"; + exit 1; + fi; + fi; + if isScript "$i"; then + if [ -e "$(dirname "$i")/.$(basename "$i")-wrapped" ]; then + if grep -q -F "$TMPDIR/" "$i"; then + echo "wrapper script $i contains a forbidden reference to $TMPDIR/"; + exit 1; + fi; + fi; + fi; + done +} +bintoolsWrapper_addLDVars () +{ + + local role_post; + getHostRoleEnvHook; + if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then + export NIX_LDFLAGS${role_post}+=" -L$1/lib64"; + fi; + if [[ -d "$1/lib" ]]; then + local -a glob=($1/lib/lib*); + if [ "${#glob[*]}" -gt 0 ]; then + export NIX_LDFLAGS${role_post}+=" -L$1/lib"; + fi; + fi +} +buildPhase () +{ + + runHook preBuild; + if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then + echo "no Makefile or custom buildPhase, doing nothing"; + else + foundMakefile=1; + local flagsArray=(${enableParallelBuilding:+-j${NIX_BUILD_CORES}} SHELL="$SHELL"); + concatTo flagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray; + echoCmd 'build flags' "${flagsArray[@]}"; + make ${makefile:+-f $makefile} "${flagsArray[@]}"; + unset flagsArray; + fi; + runHook postBuild +} +ccWrapper_addCVars () +{ + + local role_post; + getHostRoleEnvHook; + if [ -d "$1/include" ]; then + export NIX_CFLAGS_COMPILE${role_post}+=" -isystem $1/include"; + fi; + if [ -d "$1/Library/Frameworks" ]; then + export NIX_CFLAGS_COMPILE${role_post}+=" -iframework $1/Library/Frameworks"; + fi +} +checkPhase () +{ + + runHook preCheck; + if [[ -z "${foundMakefile:-}" ]]; then + echo "no Makefile or custom checkPhase, doing nothing"; + runHook postCheck; + return; + fi; + if [[ -z "${checkTarget:-}" ]]; then + if make -n ${makefile:+-f $makefile} check > /dev/null 2>&1; then + checkTarget="check"; + else + if make -n ${makefile:+-f $makefile} test > /dev/null 2>&1; then + checkTarget="test"; + fi; + fi; + fi; + if [[ -z "${checkTarget:-}" ]]; then + echo "no check/test target in ${makefile:-Makefile}, doing nothing"; + else + local flagsArray=(${enableParallelChecking:+-j${NIX_BUILD_CORES}} SHELL="$SHELL"); + concatTo flagsArray makeFlags makeFlagsArray checkFlags=VERBOSE=y checkFlagsArray checkTarget; + echoCmd 'check flags' "${flagsArray[@]}"; + make ${makefile:+-f $makefile} "${flagsArray[@]}"; + unset flagsArray; + fi; + runHook postCheck +} +compressManPages () +{ + + local dir="$1"; + if [ -L "$dir"/share ] || [ -L "$dir"/share/man ] || [ ! -d "$dir/share/man" ]; then + return; + fi; + echo "gzipping man pages under $dir/share/man/"; + find "$dir"/share/man/ -type f -a '!' -regex '.*\.\(bz2\|gz\|xz\)$' -print0 | while IFS= read -r -d '' f; do + if gzip -c -n "$f" > "$f".gz; then + rm "$f"; + else + rm "$f".gz; + fi; + done; + find "$dir"/share/man/ -type l -a '!' -regex '.*\.\(bz2\|gz\|xz\)$' -print0 | sort -z | while IFS= read -r -d '' f; do + local target; + target="$(readlink -f "$f")"; + if [ -f "$target".gz ]; then + ln -sf "$target".gz "$f".gz && rm "$f"; + fi; + done +} +concatStringsSep () +{ + + local sep="$1"; + local name="$2"; + local type oldifs; + if type=$(declare -p "$name" 2> /dev/null); then + local -n nameref="$name"; + case "${type#* }" in + -A*) + echo "concatStringsSep(): ERROR: trying to use concatStringsSep on an associative array." 1>&2; + return 1 + ;; + -a*) + local IFS="$sep"; + echo -n "${nameref[*]}" + ;; + *) + echo -n "${nameref// /"${sep}"}" + ;; + esac; + fi +} +concatTo () +{ + + local -n targetref="$1"; + shift; + local arg default name type; + for arg in "$@"; + do + IFS="=" read -r name default <<< "$arg"; + local -n nameref="$name"; + if [[ ! -n "${nameref[@]}" && -n "$default" ]]; then + targetref+=("$default"); + else + if type=$(declare -p "$name" 2> /dev/null); then + case "${type#* }" in + -A*) + echo "concatTo(): ERROR: trying to use concatTo on an associative array." 1>&2; + return 1 + ;; + -a*) + targetref+=("${nameref[@]}") + ;; + *) + if [[ "$name" = *"Array" ]]; then + nixErrorLog "concatTo(): $name is not declared as array, treating as a singleton. This will become an error in future"; + targetref+=(${nameref+"${nameref[@]}"}); + else + targetref+=(${nameref-}); + fi + ;; + esac; + fi; + fi; + done +} +configurePhase () +{ + + runHook preConfigure; + : "${configureScript=}"; + if [[ -z "$configureScript" && -x ./configure ]]; then + configureScript=./configure; + fi; + if [ -z "${dontFixLibtool:-}" ]; then + export lt_cv_deplibs_check_method="${lt_cv_deplibs_check_method-pass_all}"; + local i; + find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do + echo "fixing libtool script $i"; + fixLibtool "$i"; + done; + CONFIGURE_MTIME_REFERENCE=$(mktemp configure.mtime.reference.XXXXXX); + find . -executable -type f -name configure -exec grep -l 'GNU Libtool is free software; you can redistribute it and/or modify' {} \; -exec touch -r {} "$CONFIGURE_MTIME_REFERENCE" \; -exec sed -i s_/usr/bin/file_file_g {} \; -exec touch -r "$CONFIGURE_MTIME_REFERENCE" {} \;; + rm -f "$CONFIGURE_MTIME_REFERENCE"; + fi; + if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then + prependToVar configureFlags "${prefixKey:---prefix=}$prefix"; + fi; + if [[ -f "$configureScript" ]]; then + if [ -z "${dontAddDisableDepTrack:-}" ]; then + if grep -q dependency-tracking "$configureScript"; then + prependToVar configureFlags --disable-dependency-tracking; + fi; + fi; + if [ -z "${dontDisableStatic:-}" ]; then + if grep -q enable-static "$configureScript"; then + prependToVar configureFlags --disable-static; + fi; + fi; + if [ -z "${dontPatchShebangsInConfigure:-}" ]; then + patchShebangs --build "$configureScript"; + fi; + fi; + if [ -n "$configureScript" ]; then + local -a flagsArray; + concatTo flagsArray configureFlags configureFlagsArray; + echoCmd 'configure flags' "${flagsArray[@]}"; + $configureScript "${flagsArray[@]}"; + unset flagsArray; + else + echo "no configure script, doing nothing"; + fi; + runHook postConfigure +} +consumeEntire () +{ + + if IFS='' read -r -d '' "$1"; then + echo "consumeEntire(): ERROR: Input null bytes, won't process" 1>&2; + return 1; + fi +} +distPhase () +{ + + runHook preDist; + local flagsArray=(); + concatTo flagsArray distFlags distFlagsArray distTarget=dist; + echo 'dist flags: %q' "${flagsArray[@]}"; + make ${makefile:+-f $makefile} "${flagsArray[@]}"; + if [ "${dontCopyDist:-0}" != 1 ]; then + mkdir -p "$out/tarballs"; + cp -pvd ${tarballs[*]:-*.tar.gz} "$out/tarballs"; + fi; + runHook postDist +} +dumpVars () +{ + + if [ "${noDumpEnvVars:-0}" != 1 ]; then + { + install -m 0600 /dev/null "$NIX_BUILD_TOP/env-vars" && export 2> /dev/null >| "$NIX_BUILD_TOP/env-vars" + } || true; + fi +} +echoCmd () +{ + + printf "%s:" "$1"; + shift; + printf ' %q' "$@"; + echo +} +exitHandler () +{ + + exitCode="$?"; + set +e; + if [ -n "${showBuildStats:-}" ]; then + read -r -d '' -a buildTimes < <(times); + echo "build times:"; + echo "user time for the shell ${buildTimes[0]}"; + echo "system time for the shell ${buildTimes[1]}"; + echo "user time for all child processes ${buildTimes[2]}"; + echo "system time for all child processes ${buildTimes[3]}"; + fi; + if (( "$exitCode" != 0 )); then + runHook failureHook; + if [ -n "${succeedOnFailure:-}" ]; then + echo "build failed with exit code $exitCode (ignored)"; + mkdir -p "$out/nix-support"; + printf "%s" "$exitCode" > "$out/nix-support/failed"; + exit 0; + fi; + else + runHook exitHook; + fi; + return "$exitCode" +} +findInputs () +{ + + local -r pkg="$1"; + local -r hostOffset="$2"; + local -r targetOffset="$3"; + (( hostOffset <= targetOffset )) || exit 1; + local varVar="${pkgAccumVarVars[hostOffset + 1]}"; + local varRef="$varVar[$((targetOffset - hostOffset))]"; + local var="${!varRef}"; + unset -v varVar varRef; + local varSlice="$var[*]"; + case "${!varSlice-}" in + *" $pkg "*) + return 0 + ;; + esac; + unset -v varSlice; + eval "$var"'+=("$pkg")'; + if ! [ -e "$pkg" ]; then + echo "build input $pkg does not exist" 1>&2; + exit 1; + fi; + function mapOffset () + { + local -r inputOffset="$1"; + local -n outputOffset="$2"; + if (( inputOffset <= 0 )); then + outputOffset=$((inputOffset + hostOffset)); + else + outputOffset=$((inputOffset - 1 + targetOffset)); + fi + }; + local relHostOffset; + for relHostOffset in "${allPlatOffsets[@]}"; + do + local files="${propagatedDepFilesVars[relHostOffset + 1]}"; + local hostOffsetNext; + mapOffset "$relHostOffset" hostOffsetNext; + (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue; + local relTargetOffset; + for relTargetOffset in "${allPlatOffsets[@]}"; + do + (( "$relHostOffset" <= "$relTargetOffset" )) || continue; + local fileRef="${files}[$relTargetOffset - $relHostOffset]"; + local file="${!fileRef}"; + unset -v fileRef; + local targetOffsetNext; + mapOffset "$relTargetOffset" targetOffsetNext; + (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue; + [[ -f "$pkg/nix-support/$file" ]] || continue; + local pkgNext; + read -r -d '' pkgNext < "$pkg/nix-support/$file" || true; + for pkgNext in $pkgNext; + do + findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext"; + done; + done; + done +} +fixLibtool () +{ + + local search_path; + for flag in $NIX_LDFLAGS; + do + case $flag in + -L*) + search_path+=" ${flag#-L}" + ;; + esac; + done; + sed -i "$1" -e "s^eval \(sys_lib_search_path=\).*^\1'${search_path:-}'^" -e 's^eval sys_lib_.+search_path=.*^^' +} +fixupPhase () +{ + + local output; + for output in $(getAllOutputNames); + do + if [ -e "${!output}" ]; then + chmod -R u+w,u-s,g-s "${!output}"; + fi; + done; + runHook preFixup; + local output; + for output in $(getAllOutputNames); + do + prefix="${!output}" runHook fixupOutput; + done; + recordPropagatedDependencies; + if [ -n "${setupHook:-}" ]; then + mkdir -p "${!outputDev}/nix-support"; + substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook"; + fi; + if [ -n "${setupHooks:-}" ]; then + mkdir -p "${!outputDev}/nix-support"; + local hook; + for hook in ${setupHooks[@]}; + do + local content; + consumeEntire content < "$hook"; + substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook"; + unset -v content; + done; + unset -v hook; + fi; + if [ -n "${propagatedUserEnvPkgs:-}" ]; then + mkdir -p "${!outputBin}/nix-support"; + printWords $propagatedUserEnvPkgs > "${!outputBin}/nix-support/propagated-user-env-packages"; + fi; + runHook postFixup +} +genericBuild () +{ + + export GZIP_NO_TIMESTAMPS=1; + if [ -f "${buildCommandPath:-}" ]; then + source "$buildCommandPath"; + return; + fi; + if [ -n "${buildCommand:-}" ]; then + eval "$buildCommand"; + return; + fi; + if [ -z "${phases[*]:-}" ]; then + phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase ${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase ${preDistPhases[*]:-} distPhase ${postPhases[*]:-}"; + fi; + for curPhase in ${phases[*]}; + do + runPhase "$curPhase"; + done +} +getAllOutputNames () +{ + + if [ -n "$__structuredAttrs" ]; then + echo "${!outputs[*]}"; + else + echo "$outputs"; + fi +} +getHostRole () +{ + + getRole "$hostOffset" +} +getHostRoleEnvHook () +{ + + getRole "$depHostOffset" +} +getRole () +{ + + case $1 in + -1) + role_post='_FOR_BUILD' + ;; + 0) + role_post='' + ;; + 1) + role_post='_FOR_TARGET' + ;; + *) + echo "binutils-wrapper-2.42: used as improper sort of dependency" 1>&2; + return 1 + ;; + esac +} +getTargetRole () +{ + + getRole "$targetOffset" +} +getTargetRoleEnvHook () +{ + + getRole "$depTargetOffset" +} +getTargetRoleWrapper () +{ + + case $targetOffset in + -1) + export NIX_BINTOOLS_WRAPPER_TARGET_BUILD_x86_64_unknown_linux_gnu=1 + ;; + 0) + export NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu=1 + ;; + 1) + export NIX_BINTOOLS_WRAPPER_TARGET_TARGET_x86_64_unknown_linux_gnu=1 + ;; + *) + echo "binutils-wrapper-2.42: used as improper sort of dependency" 1>&2; + return 1 + ;; + esac +} +installCheckPhase () +{ + + runHook preInstallCheck; + if [[ -z "${foundMakefile:-}" ]]; then + echo "no Makefile or custom installCheckPhase, doing nothing"; + else + if [[ -z "${installCheckTarget:-}" ]] && ! make -n ${makefile:+-f $makefile} "${installCheckTarget:-installcheck}" > /dev/null 2>&1; then + echo "no installcheck target in ${makefile:-Makefile}, doing nothing"; + else + local flagsArray=(${enableParallelChecking:+-j${NIX_BUILD_CORES}} SHELL="$SHELL"); + concatTo flagsArray makeFlags makeFlagsArray installCheckFlags installCheckFlagsArray installCheckTarget=installcheck; + echoCmd 'installcheck flags' "${flagsArray[@]}"; + make ${makefile:+-f $makefile} "${flagsArray[@]}"; + unset flagsArray; + fi; + fi; + runHook postInstallCheck +} +installPhase () +{ + + runHook preInstall; + if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then + echo "no Makefile or custom installPhase, doing nothing"; + runHook postInstall; + return; + else + foundMakefile=1; + fi; + if [ -n "$prefix" ]; then + mkdir -p "$prefix"; + fi; + local flagsArray=(${enableParallelInstalling:+-j${NIX_BUILD_CORES}} SHELL="$SHELL"); + concatTo flagsArray makeFlags makeFlagsArray installFlags installFlagsArray installTargets=install; + echoCmd 'install flags' "${flagsArray[@]}"; + make ${makefile:+-f $makefile} "${flagsArray[@]}"; + unset flagsArray; + runHook postInstall +} +isELF () +{ + + local fn="$1"; + local fd; + local magic; + exec {fd}< "$fn"; + read -r -n 4 -u "$fd" magic; + exec {fd}>&-; + if [ "$magic" = 'ELF' ]; then + return 0; + else + return 1; + fi +} +isMachO () +{ + + local fn="$1"; + local fd; + local magic; + exec {fd}< "$fn"; + read -r -n 4 -u "$fd" magic; + exec {fd}>&-; + if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xcf") || "$magic" = $(echo -ne "\xcf\xfa\xed\xfe") ]]; then + return 0; + else + if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xce") || "$magic" = $(echo -ne "\xce\xfa\xed\xfe") ]]; then + return 0; + else + if [[ "$magic" = $(echo -ne "\xca\xfe\xba\xbe") || "$magic" = $(echo -ne "\xbe\xba\xfe\xca") ]]; then + return 0; + else + return 1; + fi; + fi; + fi +} +isScript () +{ + + local fn="$1"; + local fd; + local magic; + exec {fd}< "$fn"; + read -r -n 2 -u "$fd" magic; + exec {fd}>&-; + if [[ "$magic" =~ \#! ]]; then + return 0; + else + return 1; + fi +} +mapOffset () +{ + + local -r inputOffset="$1"; + local -n outputOffset="$2"; + if (( inputOffset <= 0 )); then + outputOffset=$((inputOffset + hostOffset)); + else + outputOffset=$((inputOffset - 1 + targetOffset)); + fi +} +moveToOutput () +{ + + local patt="$1"; + local dstOut="$2"; + local output; + for output in $(getAllOutputNames); + do + if [ "${!output}" = "$dstOut" ]; then + continue; + fi; + local srcPath; + for srcPath in "${!output}"/$patt; + do + if [ ! -e "$srcPath" ] && [ ! -L "$srcPath" ]; then + continue; + fi; + if [ "$dstOut" = REMOVE ]; then + echo "Removing $srcPath"; + rm -r "$srcPath"; + else + local dstPath="$dstOut${srcPath#${!output}}"; + echo "Moving $srcPath to $dstPath"; + if [ -d "$dstPath" ] && [ -d "$srcPath" ]; then + rmdir "$srcPath" --ignore-fail-on-non-empty; + if [ -d "$srcPath" ]; then + mv -t "$dstPath" "$srcPath"/*; + rmdir "$srcPath"; + fi; + else + mkdir -p "$(readlink -m "$dstPath/..")"; + mv "$srcPath" "$dstPath"; + fi; + fi; + local srcParent="$(readlink -m "$srcPath/..")"; + if [ -n "$(find "$srcParent" -maxdepth 0 -type d -empty 2> /dev/null)" ]; then + echo "Removing empty $srcParent/ and (possibly) its parents"; + rmdir -p --ignore-fail-on-non-empty "$srcParent" 2> /dev/null || true; + fi; + done; + done +} +nixChattyLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 5 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixDebugLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 6 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixErrorLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 0 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixInfoLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 3 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixNoticeLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 2 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixTalkativeLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 4 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixVomitLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 7 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +nixWarnLog () +{ + + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 1 ]]; then + return; + fi; + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} +patchELF () +{ + + local dir="$1"; + [ -e "$dir" ] || return 0; + echo "shrinking RPATHs of ELF executables and libraries in $dir"; + local i; + while IFS= read -r -d '' i; do + if [[ "$i" =~ .build-id ]]; then + continue; + fi; + if ! isELF "$i"; then + continue; + fi; + echo "shrinking $i"; + patchelf --shrink-rpath "$i" || true; + done < <(find "$dir" -type f -print0) +} +patchPhase () +{ + + runHook prePatch; + local -a patchesArray; + concatTo patchesArray patches; + for i in "${patchesArray[@]}"; + do + echo "applying patch $i"; + local uncompress=cat; + case "$i" in + *.gz) + uncompress="gzip -d" + ;; + *.bz2) + uncompress="bzip2 -d" + ;; + *.xz) + uncompress="xz -d" + ;; + *.lzma) + uncompress="lzma -d" + ;; + esac; + local -a flagsArray; + concatTo flagsArray patchFlags=-p1; + $uncompress < "$i" 2>&1 | patch "${flagsArray[@]}"; + done; + runHook postPatch +} +patchShebangs () +{ + + local pathName; + local update; + while [[ $# -gt 0 ]]; do + case "$1" in + --host) + pathName=HOST_PATH; + shift + ;; + --build) + pathName=PATH; + shift + ;; + --update) + update=true; + shift + ;; + --) + shift; + break + ;; + -* | --*) + echo "Unknown option $1 supplied to patchShebangs" 1>&2; + return 1 + ;; + *) + break + ;; + esac; + done; + echo "patching script interpreter paths in $@"; + local f; + local oldPath; + local newPath; + local arg0; + local args; + local oldInterpreterLine; + local newInterpreterLine; + if [[ $# -eq 0 ]]; then + echo "No arguments supplied to patchShebangs" 1>&2; + return 0; + fi; + local f; + while IFS= read -r -d '' f; do + isScript "$f" || continue; + read -r oldInterpreterLine < "$f" || [ "$oldInterpreterLine" ]; + read -r oldPath arg0 args <<< "${oldInterpreterLine:2}"; + if [[ -z "${pathName:-}" ]]; then + if [[ -n $strictDeps && $f == "$NIX_STORE"* ]]; then + pathName=HOST_PATH; + else + pathName=PATH; + fi; + fi; + if [[ "$oldPath" == *"/bin/env" ]]; then + if [[ $arg0 == "-S" ]]; then + arg0=${args%% *}; + args=${args#* }; + newPath="$(PATH="${!pathName}" type -P "env" || true)"; + args="-S $(PATH="${!pathName}" type -P "$arg0" || true) $args"; + else + if [[ $arg0 == "-"* || $arg0 == *"="* ]]; then + echo "$f: unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)" 1>&2; + exit 1; + else + newPath="$(PATH="${!pathName}" type -P "$arg0" || true)"; + fi; + fi; + else + if [[ -z $oldPath ]]; then + oldPath="/bin/sh"; + fi; + newPath="$(PATH="${!pathName}" type -P "$(basename "$oldPath")" || true)"; + args="$arg0 $args"; + fi; + newInterpreterLine="$newPath $args"; + newInterpreterLine=${newInterpreterLine%${newInterpreterLine##*[![:space:]]}}; + if [[ -n "$oldPath" && ( "$update" == true || "${oldPath:0:${#NIX_STORE}}" != "$NIX_STORE" ) ]]; then + if [[ -n "$newPath" && "$newPath" != "$oldPath" ]]; then + echo "$f: interpreter directive changed from \"$oldInterpreterLine\" to \"$newInterpreterLine\""; + escapedInterpreterLine=${newInterpreterLine//\\/\\\\}; + timestamp=$(stat --printf "%y" "$f"); + sed -i -e "1 s|.*|#\!$escapedInterpreterLine|" "$f"; + touch --date "$timestamp" "$f"; + fi; + fi; + done < <(find "$@" -type f -perm -0100 -print0) +} +patchShebangsAuto () +{ + + if [[ -z "${dontPatchShebangs-}" && -e "$prefix" ]]; then + if [[ "$output" != out && "$output" = "$outputDev" ]]; then + patchShebangs --build "$prefix"; + else + patchShebangs --host "$prefix"; + fi; + fi +} +prependToVar () +{ + + local -n nameref="$1"; + local useArray type; + if [ -n "$__structuredAttrs" ]; then + useArray=true; + else + useArray=false; + fi; + if type=$(declare -p "$1" 2> /dev/null); then + case "${type#* }" in + -A*) + echo "prependToVar(): ERROR: trying to use prependToVar on an associative array." 1>&2; + return 1 + ;; + -a*) + useArray=true + ;; + *) + useArray=false + ;; + esac; + fi; + shift; + if $useArray; then + nameref=("$@" ${nameref+"${nameref[@]}"}); + else + nameref="$* ${nameref-}"; + fi +} +printLines () +{ + + (( "$#" > 0 )) || return 0; + printf '%s\n' "$@" +} +printWords () +{ + + (( "$#" > 0 )) || return 0; + printf '%s ' "$@" +} +recordPropagatedDependencies () +{ + + declare -ra flatVars=(depsBuildBuildPropagated propagatedNativeBuildInputs depsBuildTargetPropagated depsHostHostPropagated propagatedBuildInputs depsTargetTargetPropagated); + declare -ra flatFiles=("${propagatedBuildDepFiles[@]}" "${propagatedHostDepFiles[@]}" "${propagatedTargetDepFiles[@]}"); + local propagatedInputsIndex; + for propagatedInputsIndex in "${!flatVars[@]}"; + do + local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]"; + local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}"; + [[ -n "${!propagatedInputsSlice}" ]] || continue; + mkdir -p "${!outputDev}/nix-support"; + printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile"; + done +} +runHook () +{ + + local hookName="$1"; + shift; + local hooksSlice="${hookName%Hook}Hooks[@]"; + local hook; + for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; + do + _logHook "$hookName" "$hook" "$@"; + _eval "$hook" "$@"; + done; + return 0 +} +runOneHook () +{ + + local hookName="$1"; + shift; + local hooksSlice="${hookName%Hook}Hooks[@]"; + local hook ret=1; + for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; + do + _logHook "$hookName" "$hook" "$@"; + if _eval "$hook" "$@"; then + ret=0; + break; + fi; + done; + return "$ret" +} +runPhase () +{ + + local curPhase="$*"; + if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then + return; + fi; + if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then + return; + fi; + if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then + return; + fi; + if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then + return; + fi; + if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then + return; + fi; + if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then + return; + fi; + if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then + return; + fi; + if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then + return; + fi; + if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then + return; + fi; + showPhaseHeader "$curPhase"; + dumpVars; + local startTime endTime; + startTime=$(date +"%s"); + eval "${!curPhase:-$curPhase}"; + endTime=$(date +"%s"); + showPhaseFooter "$curPhase" "$startTime" "$endTime"; + if [ "$curPhase" = unpackPhase ]; then + [ -n "${sourceRoot:-}" ] && chmod +x -- "${sourceRoot}"; + cd -- "${sourceRoot:-.}"; + fi +} +showPhaseFooter () +{ + + local phase="$1"; + local startTime="$2"; + local endTime="$3"; + local delta=$(( endTime - startTime )); + (( delta < 30 )) && return; + local H=$((delta/3600)); + local M=$((delta%3600/60)); + local S=$((delta%60)); + echo -n "$phase completed in "; + (( H > 0 )) && echo -n "$H hours "; + (( M > 0 )) && echo -n "$M minutes "; + echo "$S seconds" +} +showPhaseHeader () +{ + + local phase="$1"; + echo "Running phase: $phase"; + if [[ -z ${NIX_LOG_FD-} ]]; then + return; + fi; + printf "@nix { \"action\": \"setPhase\", \"phase\": \"%s\" }\n" "$phase" >&"$NIX_LOG_FD" +} +stripDirs () +{ + + local cmd="$1"; + local ranlibCmd="$2"; + local paths="$3"; + local stripFlags="$4"; + local excludeFlags=(); + local pathsNew=; + [ -z "$cmd" ] && echo "stripDirs: Strip command is empty" 1>&2 && exit 1; + [ -z "$ranlibCmd" ] && echo "stripDirs: Ranlib command is empty" 1>&2 && exit 1; + local pattern; + if [ -n "${stripExclude:-}" ]; then + for pattern in "${stripExclude[@]}"; + do + excludeFlags+=(-a '!' '(' -name "$pattern" -o -wholename "$prefix/$pattern" ')'); + done; + fi; + local p; + for p in ${paths}; + do + if [ -e "$prefix/$p" ]; then + pathsNew="${pathsNew} $prefix/$p"; + fi; + done; + paths=${pathsNew}; + if [ -n "${paths}" ]; then + echo "stripping (with command $cmd and flags $stripFlags) in $paths"; + local striperr; + striperr="$(mktemp --tmpdir="$TMPDIR" 'striperr.XXXXXX')"; + find $paths -type f "${excludeFlags[@]}" -a '!' -path "$prefix/lib/debug/*" -printf '%D-%i,%p\0' | sort -t, -k1,1 -u -z | cut -d, -f2- -z | xargs -r -0 -n1 -P "$NIX_BUILD_CORES" -- $cmd $stripFlags 2> "$striperr" || exit_code=$?; + [[ "$exit_code" = 123 || -z "$exit_code" ]] || ( cat "$striperr" 1>&2 && exit 1 ); + rm "$striperr"; + find $paths -name '*.a' -type f -exec $ranlibCmd '{}' \; 2> /dev/null; + fi +} +stripHash () +{ + + local strippedName casematchOpt=0; + strippedName="$(basename -- "$1")"; + shopt -q nocasematch && casematchOpt=1; + shopt -u nocasematch; + if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then + echo "${strippedName:33}"; + else + echo "$strippedName"; + fi; + if (( casematchOpt )); then + shopt -s nocasematch; + fi +} +substitute () +{ + + local input="$1"; + local output="$2"; + shift 2; + if [ ! -f "$input" ]; then + echo "substitute(): ERROR: file '$input' does not exist" 1>&2; + return 1; + fi; + local content; + consumeEntire content < "$input"; + if [ -e "$output" ]; then + chmod +w "$output"; + fi; + substituteStream content "file '$input'" "$@" > "$output" +} +substituteAll () +{ + + local input="$1"; + local output="$2"; + local -a args=(); + _allFlags; + substitute "$input" "$output" "${args[@]}" +} +substituteAllInPlace () +{ + + local fileName="$1"; + shift; + substituteAll "$fileName" "$fileName" "$@" +} +substituteAllStream () +{ + + local -a args=(); + _allFlags; + substituteStream "$1" "$2" "${args[@]}" +} +substituteInPlace () +{ + + local -a fileNames=(); + for arg in "$@"; + do + if [[ "$arg" = "--"* ]]; then + break; + fi; + fileNames+=("$arg"); + shift; + done; + for file in "${fileNames[@]}"; + do + substitute "$file" "$file" "$@"; + done +} +substituteStream () +{ + + local var=$1; + local description=$2; + shift 2; + while (( "$#" )); do + local replace_mode="$1"; + case "$1" in + --replace) + if ! "$_substituteStream_has_warned_replace_deprecation"; then + echo "substituteStream() in derivation $name: WARNING: '--replace' is deprecated, use --replace-{fail,warn,quiet}. ($description)" 1>&2; + _substituteStream_has_warned_replace_deprecation=true; + fi; + replace_mode='--replace-warn' + ;& + --replace-quiet | --replace-warn | --replace-fail) + pattern="$2"; + replacement="$3"; + shift 3; + local savedvar; + savedvar="${!var}"; + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'; + if [ "$pattern" != "$replacement" ]; then + if [ "${!var}" == "$savedvar" ]; then + if [ "$replace_mode" == --replace-warn ]; then + printf "substituteStream() in derivation $name: WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" 1>&2; + else + if [ "$replace_mode" == --replace-fail ]; then + printf "substituteStream() in derivation $name: ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" 1>&2; + return 1; + fi; + fi; + fi; + fi + ;; + --subst-var) + local varName="$2"; + shift 2; + if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then + echo "substituteStream() in derivation $name: ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." 1>&2; + return 1; + fi; + if [ -z ${!varName+x} ]; then + echo "substituteStream() in derivation $name: ERROR: variable \$$varName is unset" 1>&2; + return 1; + fi; + pattern="@$varName@"; + replacement="${!varName}"; + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + ;; + --subst-var-by) + pattern="@$2@"; + replacement="$3"; + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'; + shift 3 + ;; + *) + echo "substituteStream() in derivation $name: ERROR: Invalid command line argument: $1" 1>&2; + return 1 + ;; + esac; + done; + printf "%s" "${!var}" +} +unpackFile () +{ + + curSrc="$1"; + echo "unpacking source archive $curSrc"; + if ! runOneHook unpackCmd "$curSrc"; then + echo "do not know how to unpack source archive $curSrc"; + exit 1; + fi +} +unpackPhase () +{ + + runHook preUnpack; + if [ -z "${srcs:-}" ]; then + if [ -z "${src:-}" ]; then + echo 'variable $src or $srcs should point to the source'; + exit 1; + fi; + srcs="$src"; + fi; + local -a srcsArray; + concatTo srcsArray srcs; + local dirsBefore=""; + for i in *; + do + if [ -d "$i" ]; then + dirsBefore="$dirsBefore $i "; + fi; + done; + for i in "${srcsArray[@]}"; + do + unpackFile "$i"; + done; + : "${sourceRoot=}"; + if [ -n "${setSourceRoot:-}" ]; then + runOneHook setSourceRoot; + else + if [ -z "$sourceRoot" ]; then + for i in *; + do + if [ -d "$i" ]; then + case $dirsBefore in + *\ $i\ *) + + ;; + *) + if [ -n "$sourceRoot" ]; then + echo "unpacker produced multiple directories"; + exit 1; + fi; + sourceRoot="$i" + ;; + esac; + fi; + done; + fi; + fi; + if [ -z "$sourceRoot" ]; then + echo "unpacker appears to have produced no directories"; + exit 1; + fi; + echo "source root is $sourceRoot"; + if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then + chmod -R u+w -- "$sourceRoot"; + fi; + runHook postUnpack +} +updateAutotoolsGnuConfigScriptsPhase () +{ + + if [ -n "${dontUpdateAutotoolsGnuConfigScripts-}" ]; then + return; + fi; + for script in config.sub config.guess; + do + for f in $(find . -type f -name "$script"); + do + echo "Updating Autotools / GNU config script to a newer upstream version: $f"; + cp -f "/nix/store/q6x5ag0rns4swggcyvcgd1x5i488ws6c-gnu-config-2024-01-01/$script" "$f"; + done; + done +} +updateSourceDateEpoch () +{ + + local path="$1"; + [[ $path == -* ]] && path="./$path"; + local -a res=($(find "$path" -type f -not -newer "$NIX_BUILD_TOP/.." -printf '%T@ %p\0' | sort -n --zero-terminated | tail -n1 --zero-terminated | head -c -1)); + local time="${res[0]//\.[0-9]*/}"; + local newestFile="${res[1]}"; + if [ "${time:-0}" -gt "$SOURCE_DATE_EPOCH" ]; then + echo "setting SOURCE_DATE_EPOCH to timestamp $time of file $newestFile"; + export SOURCE_DATE_EPOCH="$time"; + local now="$(date +%s)"; + if [ "$time" -gt $((now - 60)) ]; then + echo "warning: file $newestFile may be generated; SOURCE_DATE_EPOCH may be non-deterministic"; + fi; + fi +} +PATH="$PATH${nix_saved_PATH:+:$nix_saved_PATH}" +XDG_DATA_DIRS="$XDG_DATA_DIRS${nix_saved_XDG_DATA_DIRS:+:$nix_saved_XDG_DATA_DIRS}" +export NIX_BUILD_TOP="$(mktemp -d -t nix-shell.XXXXXX)" +export TMP="$NIX_BUILD_TOP" +export TMPDIR="$NIX_BUILD_TOP" +export TEMP="$NIX_BUILD_TOP" +export TEMPDIR="$NIX_BUILD_TOP" +eval "${shellHook:-}" diff --git a/Dockerfile b/Dockerfile index fd70d24..c0298c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,7 @@ RUN pnpm turbo run build FROM base AS runner WORKDIR /app +RUN corepack enable # Don't run production as root RUN addgroup --system --gid 1001 nodejs @@ -47,5 +48,12 @@ COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public +# Handle db migrations +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json +COPY --from=builder --chown=nextjs:nodejs /app/packages/db ./packages/db + +RUN ["pnpm", "db:generate"] +RUN ["pnpm", "db:migrate"] + EXPOSE 3000 CMD node apps/web/server.js diff --git a/apps/cli/bin/index.js b/apps/cli/bin/index.js index e35ca2f..958e404 100644 --- a/apps/cli/bin/index.js +++ b/apps/cli/bin/index.js @@ -12188,7 +12188,7 @@ const timezones$1 = { "America/Los_Angeles": "Pacific Time", // "Atlantic/Azores": "Azores", // "Atlantic/Cape_Verde": "Cape Verde Islands", - // GMT: "UTC", + "Etc/UTC": "UTC", "Europe/London": "The UK", "Europe/Dublin": "Ireland", // "Europe/Lisbon": "Lisbon", diff --git a/apps/web/app/api/db/download/route.ts b/apps/web/app/api/db/download/route.ts index 68186b9..4192b05 100644 --- a/apps/web/app/api/db/download/route.ts +++ b/apps/web/app/api/db/download/route.ts @@ -2,17 +2,24 @@ import { NextRequest, NextResponse } from 'next/server'; import fs from 'fs'; import path from 'path'; import serverConfig from '@lifetracker/shared/config'; +import { getConnectionDetails } from '@lifetracker/db/drizzle'; +import { pgDump } from 'pg-dump-restore'; -const DB_PATH = path.join(serverConfig.dataDir, 'lifetracker.db'); + +const dbPath = path.join(serverConfig.dataDir, `lifetracker-${new Date().getTime()}.sql`); + +const returnVal = (await pgDump(getConnectionDetails(), { + filePath: dbPath, +})); export async function GET(req: NextRequest) { try { // Read the production database file - const dbFile = fs.readFileSync(DB_PATH); + const dbFile = fs.readFileSync(dbPath); return new NextResponse(dbFile, { headers: { 'Content-Type': 'application/octet-stream', - 'Content-Disposition': 'attachment; filename="lifetracker.db"' + 'Content-Disposition': `attachment; filename="lifetracker-${new Date().getTime()}.sql"` } }); diff --git a/apps/web/app/api/db/upload/route.ts b/apps/web/app/api/db/upload/route.ts index e8a28dd..4944a5b 100644 --- a/apps/web/app/api/db/upload/route.ts +++ b/apps/web/app/api/db/upload/route.ts @@ -2,10 +2,13 @@ import { NextRequest, NextResponse } from 'next/server'; import fs from 'fs'; import path from 'path'; import serverConfig from '@lifetracker/shared/config'; +import { pgDump, pgRestore } from 'pg-dump-restore'; +import { db, getConnectionDetails } from '@lifetracker/db/drizzle'; +import { sql } from 'drizzle-orm'; // Define paths for uploaded files and the production DB const UPLOAD_DIR = path.join(process.cwd(), 'uploads'); -const DB_PATH = path.join(serverConfig.dataDir, 'lifetracker.db'); +const DB_PATH = path.join(serverConfig.dataDir, `lifetracker-${new Date().getTime()}.sql`); // Ensure upload directory exists if (!fs.existsSync(UPLOAD_DIR)) { @@ -35,25 +38,31 @@ export async function POST(req: NextRequest) { const fileContent = bodyBuffer.slice(start, end); // Save the uploaded file to the upload directory - const uploadedFilePath = path.join(UPLOAD_DIR, 'uploaded.db'); + const uploadedFilePath = path.join(UPLOAD_DIR, 'uploaded.sql'); fs.writeFileSync(uploadedFilePath, fileContent); - // Validate the uploaded file extension - if (!uploadedFilePath.endsWith('.db')) { - return NextResponse.json({ message: 'Invalid file type. Please upload a .db file.' }, { status: 400 }); - } + // Back up the existing production database + const backupPath = `${serverConfig.dataDir}/pg-backup-${new Date().getTime()}.sql`; + const { stdout, stderr } = await pgDump(getConnectionDetails(), { + filePath: `${backupPath}`, + }); - // Backup the current production database - const backupPath = path.join( - serverConfig.dataDir, - `backup_${Date.now()}.db` - ); - if (fs.existsSync(DB_PATH)) { - fs.copyFileSync(DB_PATH, backupPath); - } + console.log("Backed up existing data to ", backupPath); + console.log(stdout); - // Replace the production database with the uploaded file - fs.renameSync(uploadedFilePath, DB_PATH); + // If it's a SQL file, restore the production database from the uploaded file + if (uploadedFilePath.endsWith('.sql')) { + const { stdout: restoreStdout, stderr: restoreStderr } = await pgRestore(getConnectionDetails(), { + clean: true, + filePath: uploadedFilePath, + }); + } + // If it ends in .db, assume it's a sqlite + else if (uploadedFilePath.endsWith('.db')) { + // TODO, if ever + return NextResponse.json({ message: 'Invalid file type. Please upload a .sql file.' }, { status: 400 }); + } + else { return NextResponse.json({ message: 'Invalid file type. Please upload a .sql file.' }, { status: 400 }); } return NextResponse.json({ message: 'Database uploaded and replaced successfully!' }, { status: 200 }); } catch (error) { diff --git a/apps/web/app/dashboard/admin/page.tsx b/apps/web/app/dashboard/admin/page.tsx index 5f40c64..e0f5aaa 100644 --- a/apps/web/app/dashboard/admin/page.tsx +++ b/apps/web/app/dashboard/admin/page.tsx @@ -14,7 +14,7 @@ export default async function AdminPage() { return ( <>
- + {/* */} {/* */} diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 1d92260..64fd5ef 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -19,7 +19,7 @@ import { import { getServerAuthSession } from "@/server/auth"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { clientConfig } from "@lifetracker/shared/config"; +import serverConfig, { clientConfig } from "@lifetracker/shared/config"; import { useTimezone } from "@lifetracker/shared-react/hooks/timezones"; import { getUserLocalSettings } from "@/lib/userLocalSettings/userLocalSettings"; diff --git a/apps/web/components/dashboard/admin/DatabaseSettings.tsx b/apps/web/components/dashboard/admin/DatabaseSettings.tsx index 9eb7253..84d7caa 100644 --- a/apps/web/components/dashboard/admin/DatabaseSettings.tsx +++ b/apps/web/components/dashboard/admin/DatabaseSettings.tsx @@ -47,7 +47,7 @@ export default function DatabaseSettings() { const dbData = await download.blob(); const formData = new FormData(); - formData.append('sqliteFile', dbData, 'remoteDB-file.db'); + formData.append('sqlFile', dbData, 'remoteDB-file.sql'); uploadDB(formData, setRemoteCopyStatus); // try { @@ -71,12 +71,12 @@ export default function DatabaseSettings() { return ( <>
- Upload SQLite Database + Upload Postgres SQL
- +
{uploadStatus &&

{uploadStatus}

} @@ -85,7 +85,7 @@ export default function DatabaseSettings() {
- Download SQLite Database + Download Postgres SQL
diff --git a/apps/web/components/dashboard/analytics/AnalyticsView.tsx b/apps/web/components/dashboard/analytics/AnalyticsView.tsx index b8e71b8..ded9ce8 100644 --- a/apps/web/components/dashboard/analytics/AnalyticsView.tsx +++ b/apps/web/components/dashboard/analytics/AnalyticsView.tsx @@ -48,8 +48,8 @@ export default function AnalyticsView() { } return [ // spacetime.now().subtract(1, "week").toNativeDate(), - spacetime.now(useTimezone()).toNativeDate(), - spacetime.now(useTimezone()).toNativeDate() + parseISO(spacetime.now(useTimezone()).format("iso-short")), + parseISO(spacetime.now(useTimezone()).format("iso-short")), ]; })(); @@ -75,6 +75,12 @@ export default function AnalyticsView() { timezone: useTimezone(), }).data ?? []; + const weightData = api.measurements.getTimeseries.useQuery({ + dateRange, + timezone: useTimezone(), + metricName: "weight" + }).data ?? []; + return (
@@ -176,7 +182,27 @@ export default function AnalyticsView() { }
- +
+

Weight

+
+ { + !weightData ? : +
    + {weightData.map((measurement) => ( +
  • + {measurement.value} {measurement.unit} +  ,  + { + spacetime(measurement.datetime) + .goto(useTimezone()) + .format("{iso-short} at {hour} {ampm}") + } +
  • + ))} +
+ } +
+

Drugs

@@ -192,6 +218,6 @@ export default function AnalyticsView() { }
-
+
); } \ No newline at end of file diff --git a/apps/web/components/dashboard/categories/CategoriesView.tsx b/apps/web/components/dashboard/categories/CategoriesView.tsx index 7dc831d..b8dbe3e 100644 --- a/apps/web/components/dashboard/categories/CategoriesView.tsx +++ b/apps/web/components/dashboard/categories/CategoriesView.tsx @@ -22,7 +22,7 @@ import Link from "next/link"; export default function CategoriesView() { const { data: session } = useSession(); const { data: categories } = api.categories.list.useQuery(); - const { data: categoryStats } = api.categories.categoryStats.useQuery(); + // const { data: categoryStats } = api.categories.categoryStats.useQuery(); const invalidateCategoryList = api.useUtils().categories.list.invalidate; const { mutate: deleteCategory, isPending: isDeletionPending } = @@ -57,7 +57,7 @@ export default function CategoriesView() { {c.name} {c.description} - {categoryStats[c.id].numEntries} + categoryStats[c.id].numEntries { - return spacetime(h.date).add(h.time + tzOffset, "hour").format('{hour} {ampm}'); + return spacetime(h.datetime).format('{hour} {ampm}'); } - hour.datetime = localDateTime(hour); - - useEffect(() => { // console.log(hour.categoryDesc); @@ -133,12 +130,12 @@ export default function EditableHour({ {hourGroup.length > 1 ? (
- {hour.datetime} + {format(hour.datetime, "hh")} | {localDateTime(hourGroup[hourGroup.length - 1])}
) - :
{hour.datetime}
+ :
{spacetime(hour.datetime).format('{hour} {ampm}')}
}
diff --git a/apps/web/components/dashboard/hours/HourMeasurementsDialog.tsx b/apps/web/components/dashboard/hours/HourMeasurementsDialog.tsx index 679d331..3d5722a 100644 --- a/apps/web/components/dashboard/hours/HourMeasurementsDialog.tsx +++ b/apps/web/components/dashboard/hours/HourMeasurementsDialog.tsx @@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { TRPCClientError } from "@trpc/client"; import { useForm } from "react-hook-form"; import { z } from "zod"; -import { zMeasurementSchema, ZMetric } from "@lifetracker/shared/types/metrics"; +import { ZMeasurement, zMeasurementSchema, ZMetric } from "@lifetracker/shared/types/metrics"; import { ZHour } from "@lifetracker/shared/types/days"; import { Icon } from "@/components/ui/icon"; @@ -37,7 +37,7 @@ export default function HourMeasurementsDialog({ }) { const [hour, setHour] = useState(initialHour); const [isOpen, onOpenChange] = useState(false); - const [pendingMeasurement, setPendingMeasurement] = useState(false); + const [pendingMeasurement, setPendingMeasurement] = useState(false); const pendingRef = useRef(null); useEffect(() => { diff --git a/apps/web/package.json b/apps/web/package.json index 8a96700..6597518 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -78,6 +78,7 @@ "next-auth": "^4.24.5", "next-pwa": "^5.6.0", "next-themes": "^0.3.0", + "pg-dump-restore": "^1.0.12", "prettier": "^3.2.5", "react": "^18.2.0", "react-colorful": "^5.6.1", diff --git a/apps/web/public/sw.js b/apps/web/public/sw.js index 79db2c4..dacc388 100644 --- a/apps/web/public/sw.js +++ b/apps/web/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,n={};const s=(s,i)=>(s=new URL(s+".js",i).href,n[s]||new Promise((n=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=n,document.head.appendChild(e)}else e=s,importScripts(s),n()})).then((()=>{let e=n[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e})));self.define=(i,a)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(n[t])return;let u={};const c=e=>s(e,t),r={module:{uri:t},exports:u,require:c};n[t]=Promise.all(i.map((e=>r[e]||c(e)))).then((e=>(a(...e),u)))}}define(["./workbox-01fd22c6"],(function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"c896ae2ce4746ae29a6b3d44a1adceb4"},{url:"/_next/static/84EuupUp4qnK5mnuiJSM9/_buildManifest.js",revision:"bc3a3ea1418035231ef7dcc4ae31f2c4"},{url:"/_next/static/84EuupUp4qnK5mnuiJSM9/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/112-3896b4c5da37081c.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/334-4ca845535978c25d.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/355-b0484ef7ed7587c8.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/420-cb296f2c2540d988.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/48a55697-54a0f084edc64f80.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/539-63eddf60729cee5e.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/565-56de9415c62a0cfe.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/583-309b90b740372f43.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/690-952c36bbd581db34.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/720-9e109c5fe4289e60.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/736-61fc5fbdd2a567cc.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/765-b914e2ac5bdcd4cd.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/809-397aae2b09bda43a.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/83-1a7a82417443604f.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/842-0af3c92c1a39e786.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/862-9b0948f6a492b473.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/874-7df68caed845efb2.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/897-5c5363d71f2f382f.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/927-fb97569bd0507f8d.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/928-5f3808421ddaae7e.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/967-41c22e48b2661482.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/_not-found/page-2d78ffdb77fb1ad6.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/api/auth/%5B...nextauth%5D/route-b3664948804b7054.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/api/health/route-d14806ae7c285863.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/api/trpc/%5Btrpc%5D/route-fd871f1925786e6f.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/admin/page-2ce806163f6d83a5.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/categories/page-ce27fc06f9abf43f.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/day/%5BdateQuery%5D/page-f3488ed64f807575.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/day/page-5613ccd12b77f645.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/error-77f90c1e2feed4cc.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/layout-90288bfcb970a981.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/metrics/page-378015bb5d09efbe.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/not-found-755c9a89a09dbd60.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/dashboard/timeline/page-2b248bb40496aae5.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/layout-78145d633f9c99a9.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/page-fdcd3a32be380da8.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/api-keys/page-c73d1d47d662570c.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/app/page-9ff790b0a73293f2.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/colors/page-34ac6cedde57ddef.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/info/page-dc8c7ea0dbc6deb1.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/layout-3f0bd1d48f01c925.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/settings/page-3e2b10bce2f21f3b.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/app/signin/page-62d6c882c309f850.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/framework-9adb083686e94c4e.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/main-58b7665c8e4fd83f.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/main-app-7e2bff1688ff4191.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/pages/_app-7486b486666c0829.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/pages/_error-dd760f50b13086bf.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-ae2a795241142997.js",revision:"84EuupUp4qnK5mnuiJSM9"},{url:"/_next/static/css/c5ccd7e138025fa2.css",revision:"c5ccd7e138025fa2"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/6d93bde91c0c2823-s.woff2",revision:"621a07228c8ccbfd647918f1021b4868"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/a34f9d1faa5f3315-s.p.woff2",revision:"d4fe31e6a2aebc06b8d6e558c9141119"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/blur.avif",revision:"39fa4c532f5f840a29197d53a4e72fe1"},{url:"/icons/logo-128.png",revision:"547f30628d92a5cafdc1d8713cf995bc"},{url:"/icons/logo-16.png",revision:"bb2bd28d2a3e8df4abc71818d0185a5e"},{url:"/icons/logo-48.png",revision:"7a2e7ee8e48d2b20fa9974530d4cac5d"},{url:"/icons/logo-full.svg",revision:"a9d0c720d0ca4aa295a1c3e28b61f224"},{url:"/icons/logo-icon.svg",revision:"ca869c6318fde3ff221aa33b283221eb"},{url:"/icons/logo-text.svg",revision:"4a3938661457c886f109541646e6ac58"},{url:"/manifest.json",revision:"8063bef3057655e31117b32add245dbd"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:n,event:s,state:i})=>n&&"opaqueredirect"===n.type?new Response(n.body,{status:200,statusText:"OK",headers:n.headers}):n}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;const n=e.pathname;return!n.startsWith("/api/auth/")&&!!n.startsWith("/api/")}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")}),new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((({url:e})=>!(self.origin===e.origin)),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); +if(!self.define){let s,a={};const e=(e,t)=>(e=new URL(e+".js",t).href,a[e]||new Promise((a=>{if("document"in self){const s=document.createElement("script");s.src=e,s.onload=a,document.head.appendChild(s)}else s=e,importScripts(e),a()})).then((()=>{let s=a[e];if(!s)throw new Error(`Module ${e} didn’t register its module`);return s})));self.define=(t,i)=>{const n=s||("document"in self?document.currentScript.src:"")||location.href;if(a[n])return;let c={};const u=s=>e(s,n),r={module:{uri:n},exports:c,require:u};a[n]=Promise.all(t.map((s=>r[s]||u(s)))).then((s=>(i(...s),c)))}}define(["./workbox-01fd22c6"],(function(s){"use strict";importScripts(),self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"a829dca93041ba607c9ca225032f21c5"},{url:"/_next/static/aZspmizttnNwl5cZuaWiZ/_buildManifest.js",revision:"6c9d06caf97bc7ed715b14499a83d4d9"},{url:"/_next/static/aZspmizttnNwl5cZuaWiZ/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/1190-1bbf80b720c09149.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/1355-caafc66cd35f56f7.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/1991-d1948e41ec3beb5c.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3011-151dd930d5615c9b.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3279-1bd1f80699d904d7.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3298-762412cdf8b3a513.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3375-0fdefb9796668119.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3629-091dc2b9dd55e918.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/3794-5af08ac694450608.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/4339-f72529885018b1de.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/4341-a9d26bdc24b03dac.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/482-5b7c27ab5df8fec2.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/5230-7936532057530905.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/5317-436dbc29e4dc416d.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/5763-5f686dc321d8bf96.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/6302-48fae2ba772b65aa.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7265-be4aa29e569cc593.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7390-d2af2ac2d1a66bc7.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7624-41b2892939ade7ea.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7711-7bb2b959ec1460a4.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7880-83d61aea9fdb0fa3.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7885-286ab3fce6a22366.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/7899-027304c8aa10c198.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/8125-b3a12115d1ada735.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/886-560153677f93a235.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/_not-found/page-108098b20c5fa08e.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/auth/%5B...nextauth%5D/route-ae0196542250d075.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/db/download/route-5a66aee5baae826f.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/db/upload/route-3bb12abfa0474d04.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/health/route-48e3ac6831890179.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/trpc/%5Btrpc%5D/route-40a314ba841140bc.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/api/v1/measurements/route-e6649fd0776c5135.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/admin/page-5ba63683dc2e5e7d.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/analytics/page-444cde84c3284dd5.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/categories/page-11bfe706eb836285.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/day/%5BdateQuery%5D/page-426be5ccee634baa.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/day/page-189dbd8bc491353c.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/error-369e6f2be944201b.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/layout-a035798b25d45194.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/metrics/page-b53e2421a3c9459e.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/not-found-8b9fdc3e948cdeee.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/dashboard/timeline/page-411dc8b7092ab359.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/layout-f42bc52e8bdaf9e8.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/page-b52f350efd4c8f7d.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/api-keys/page-2f551282255780dd.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/app/page-6593c64d092733fb.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/colors/page-96f5b163826c5074.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/database/page-5590887ca6ae83af.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/info/page-d1d174de41d98d66.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/layout-dea6a01443d7fb2c.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/settings/page-1675bc05c1272ccd.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/app/signin/page-717255d78e099fe1.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/d27283b4-dff70ffe001e7ed3.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/f8cb9cba-6629a11a2c2de967.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/framework-0387496e70e49165.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/main-95aa079cdd30e4a9.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/main-app-5219bb1ee0fccb90.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/pages/_app-9f228b47d94b5d9d.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/pages/_error-a41bff6b46fb8309.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-b2b69ca3f3a6ca63.js",revision:"aZspmizttnNwl5cZuaWiZ"},{url:"/_next/static/css/0f1843278811ea82.css",revision:"0f1843278811ea82"},{url:"/_next/static/css/3ed81ce3668ecb5d.css",revision:"3ed81ce3668ecb5d"},{url:"/_next/static/css/a3160e048330d9cb.css",revision:"a3160e048330d9cb"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/6d93bde91c0c2823-s.woff2",revision:"621a07228c8ccbfd647918f1021b4868"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/a34f9d1faa5f3315-s.p.woff2",revision:"d4fe31e6a2aebc06b8d6e558c9141119"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/blur.avif",revision:"39fa4c532f5f840a29197d53a4e72fe1"},{url:"/icons/logo-128.png",revision:"547f30628d92a5cafdc1d8713cf995bc"},{url:"/icons/logo-16.png",revision:"bb2bd28d2a3e8df4abc71818d0185a5e"},{url:"/icons/logo-48.png",revision:"7a2e7ee8e48d2b20fa9974530d4cac5d"},{url:"/icons/logo-full.svg",revision:"a9d0c720d0ca4aa295a1c3e28b61f224"},{url:"/icons/logo-icon.svg",revision:"ca869c6318fde3ff221aa33b283221eb"},{url:"/icons/logo-text.svg",revision:"4a3938661457c886f109541646e6ac58"},{url:"/manifest.json",revision:"8063bef3057655e31117b32add245dbd"}],{ignoreURLParametersMatching:[]}),s.cleanupOutdatedCaches(),s.registerRoute("/",new s.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:s,response:a,event:e,state:t})=>a&&"opaqueredirect"===a.type?new Response(a.body,{status:200,statusText:"OK",headers:a.headers}):a}]}),"GET"),s.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new s.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new s.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),s.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new s.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new s.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new s.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new s.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),s.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new s.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new s.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\/_next\/image\?url=.+$/i,new s.StaleWhileRevalidate({cacheName:"next-image",plugins:[new s.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\.(?:mp3|wav|ogg)$/i,new s.CacheFirst({cacheName:"static-audio-assets",plugins:[new s.RangeRequestsPlugin,new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\.(?:mp4)$/i,new s.CacheFirst({cacheName:"static-video-assets",plugins:[new s.RangeRequestsPlugin,new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\.(?:js)$/i,new s.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\.(?:css|less)$/i,new s.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new s.StaleWhileRevalidate({cacheName:"next-data",plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute(/\.(?:json|xml|csv)$/i,new s.NetworkFirst({cacheName:"static-data-assets",plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute((({url:s})=>{if(!(self.origin===s.origin))return!1;const a=s.pathname;return!a.startsWith("/api/auth/")&&!!a.startsWith("/api/")}),new s.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new s.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),s.registerRoute((({url:s})=>{if(!(self.origin===s.origin))return!1;return!s.pathname.startsWith("/api/")}),new s.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),s.registerRoute((({url:s})=>!(self.origin===s.origin)),new s.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new s.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); diff --git a/apps/web/uploads/uploaded.sql b/apps/web/uploads/uploaded.sql new file mode 100644 index 0000000000000000000000000000000000000000..bc29b7e43bd069a42811ab7c3ab556c189571291 GIT binary patch literal 109477 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 z%0D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�lsD!QU$=J37LnjT?Ee)Jr&R&Jo##P5WTdKJQKUex!6${8XFj3aVV}=N@3T{VybocCa|b2h(tVkS-|h7- zhkqQ;rCrV8tL3yMs_T?pTMN*=&~ck3{{q@O;(xp+@3xi5TsOHccv3~r2s6^O&St)@c1dUEf)1I>32-N+N5}8LUNw8r(>e|d#kHfcgf!d~xZK4IRlay* z;OR$V*bpw#UMLTDi+0xg-+{d&vX2c#3jPQGRd*45%w!>h9608;X8S@2Z`Om1!-8E$ zVN12cqj zRg^v6eTaLD@0#w&K}TGY!=} zu@pvD+itz4{hHdn@6TFVeUZf9ykUmhrwi*P9{seP(cBYZ>?&SdG`sW#uvgU^e!65( zkg}0uAWZFMB;4-j*m6clV<*+NK`h;g18VzI+B?Qm&wmyC-GfkEE*O%yk1=_;wsfI+ z-1t&e+?r1&w5ñPD^!7U#vi@yVVRV3l3yOVZ0Z((-E5HlV9fUK#XwXJjGh>Wrp z9kef9e0UW7~7ZU=O%WcYE5yt1M zEM=|17X!zgVlZ`L6PLaG(T)wT=DXa_B_wU2c^mSycLS)$^{?#p^d46`Tj4oRuE;h| z(x3Wfv5k!ow?2wY77gQM&Cd&%?TQNeD|n+ zFD>>!7YkrYg}79Kb3)jGWLGPuur$`k#L-$dU`7Saxk|xX!H(a7y`zhd)22VNXJTWD zMa@-{`5tt6^!L7Z`3qq0nEz?6E$ws7+C7@pB|X$(woI;+bj_Wqt7Or#%M1XR;U61B6VWg6!7K#0@EcUURPTQK2c11ecJBB!3 z!>Qe1U>DtFzkv2m_&oK~GxPG8l#rc0Y-i?7G)aQQFP!-j*h7^R(;74PY(yv&V*5ZZ z=x9J+SnM5>JuSSL;B@w2+tIt3`Jbvc`o~Kog|2jTh{vf3t;b((&HBC+o^iA$%Ucj z1DFD$DQ-f10qmtKA7V^0SO3i&D8Gq9b6FQ$F1K_|I<8#qX?KHw)2?|}mA0n0{40w+ zjnFW22h*;B?#Yc#V^V)^Y{M70-Wlv^--TgI2|Mn*>1%RK>qs!ac4WQ)_D(52wXMB` z0{97ad^y?LWqX5#s-(VPi&ro4;>Ud#s_Vl-84?UipE-6*Jpd_vVX=4e;%STYIf!Mv zk6`y3XSJrqO0rMm`g3zqAyA)s6G^2#tAdZzTKi|fo*oOrtrsZyTRYHQ2SPUSZtO|p zd&SUA7Z>nQP`6351n0yDVDDn=sRbL_V`x*EXpa3s2QZS`-T_Wu0DH$4Ppb%cNYwf; zZRVUyfs<3)_9KHDdB-80)w6RU^L-?C;*(YN_D30sd|V6r-vHUZB-Ya{=)^ohJWuQ5 zE&O?lnR|o`JX?P#mnlCz80|TCf8`D2t+}A|a4%tnXa@|7@aDWTd3OG$fm{fVHbcJ~t_Jic4OE4xXf)G;H@Mxm?}JNf99R4RT}7*m z!T33sbeO1F(>G;ZNX3> z&_8+wgXcSeBM(<@!$@>aPqByk?4`>VK4z3rs@&9}uezmOXoNtYbu-)hP!~ELkgAAX zE~be60*z}rolu%oRbCR0UI1G3jgCR8+F<)C+7;ey;m>NNO3|7h^sr1LNy{QT$D$35 zGQFC(IbAHBIQjyPO0EFCXfFI2S$R1&ROx2n;{ep)j^%(BglsJX1r6YVkg zdE5E07n@=m!VrL)dAuI#a0vJ}40beNt-iAb*K4<C|n}d5}Gb#_jX*AJ_(qbJ4eSxu?h0gMBg{DE@pbxz_ zoGSE)B~XD^?if~jU%c0kpTMC)dUglwJc7+buYBkL^NxP1eo^Bq+BRyVmU%y!JmT zbX(c|Lc0ssQV0I2`~000010FVs; z005Q%004NL9fwg1f-o2WpSNGpgU{v$OMPo8gdk!jAtJ=mWm5YT*QEXXGB}Pq@GWSf z*^N+YnG6MMs{zNE&Di!uHJX&^DF l000000097z4FCWD4FCWDc$|yT@~004DM#f$&| literal 0 HcmV?d00001 diff --git a/flake.nix b/flake.nix index de616f8..1ed224b 100644 --- a/flake.nix +++ b/flake.nix @@ -22,8 +22,7 @@ emacs-nox nodejs pnpm - sqlite - + postgresql ] ++ optional stdenv.isLinux inotify-tools ++ optional stdenv.isDarwin terminal-notifier ++ optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [ diff --git a/package.json b/package.json index 842f9fa..0c7db00 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "devDependencies": { "prettier": "^3.3.3", + "tsx": "^4.19.2", "turbo": "^2.2.3", "typescript": "^5.6.3" }, diff --git a/packages/db/drizzle-sqlite.ts b/packages/db/drizzle-sqlite.ts new file mode 100644 index 0000000..b163a69 --- /dev/null +++ b/packages/db/drizzle-sqlite.ts @@ -0,0 +1,16 @@ +import "dotenv/config"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import Database from "better-sqlite3"; +import * as schema from "./schema"; +import serverConfig from "@lifetracker/shared/config"; + +export const databaseUrl = serverConfig.dataDir + ? `${serverConfig.dataDir}/lifetracker.db` + : "./lifetracker.db"; + + +const sqlite = new Database(databaseUrl); +export const db = drizzle(sqlite, { + schema, + logger: false, +}); \ No newline at end of file diff --git a/packages/db/drizzle.config.ts b/packages/db/drizzle.config.ts index e2f24d3..bf187ba 100644 --- a/packages/db/drizzle.config.ts +++ b/packages/db/drizzle.config.ts @@ -1,17 +1,17 @@ -import dotenv from "dotenv"; import type { Config } from "drizzle-kit"; import serverConfig from "@lifetracker/shared/config"; -const databaseURL = serverConfig.dataDir - ? `${serverConfig.dataDir}/lifetracker.db` - : "./lifetracker.db"; - - -export default { - dialect: "sqlite", +const dbInfo = { schema: "./schema.ts", out: "./migrations", + dialect: "postgresql", dbCredentials: { - url: databaseURL, - }, -} satisfies Config; \ No newline at end of file + url: process.env.NODE_ENV === "test" + ? serverConfig.testDatabaseUrl + : serverConfig.databaseUrl, + + } +} satisfies Config; + +export default dbInfo; + diff --git a/packages/db/drizzle.ts b/packages/db/drizzle.ts index f552037..4eb4b48 100644 --- a/packages/db/drizzle.ts +++ b/packages/db/drizzle.ts @@ -1,23 +1,34 @@ import "dotenv/config"; -import { drizzle } from "drizzle-orm/better-sqlite3"; -import Database from "better-sqlite3"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; import * as schema from "./schema"; -import { migrate } from "drizzle-orm/better-sqlite3/migrator"; -import path from "path"; +import serverConfig from "@lifetracker/shared/config"; -import dbConfig from "./drizzle.config"; +const pool = new Pool({ + connectionString: serverConfig.databaseUrl, +}); -const sqlite = new Database(dbConfig.dbCredentials.url); -export const db = drizzle(sqlite, { +export const db = drizzle(pool, { schema, logger: false, }); -export function getInMemoryDB(runMigrations: boolean) { - const mem = new Database(":memory:"); - const db = drizzle(mem, { schema, logger: true }); - if (runMigrations) { - migrate(db, { migrationsFolder: path.resolve(__dirname, "./migrations") }); + +export function getConnectionDetails() { + const sourceDb = serverConfig.databaseUrl + const sourceDbUrl = new URL(sourceDb) + return { + port: parseInt(sourceDbUrl.port), + host: sourceDbUrl.hostname, + database: sourceDbUrl.pathname.slice(1), + username: sourceDbUrl.username, + password: sourceDbUrl.password } - return db; +} +// Testing utility +export async function getTestDB() { + const testPool = new Pool({ + connectionString: serverConfig.testDatabaseUrl, + }); + return drizzle(testPool, { schema }); } \ No newline at end of file diff --git a/packages/db/index.ts b/packages/db/index.ts index d54067f..cba8c1c 100644 --- a/packages/db/index.ts +++ b/packages/db/index.ts @@ -1,17 +1,24 @@ -import Database from "better-sqlite3"; +import { Pool, QueryResult } from "pg"; import { ExtractTablesWithRelations } from "drizzle-orm"; -import { SQLiteTransaction } from "drizzle-orm/sqlite-core"; - +import { PgTransaction } from "drizzle-orm/pg-core"; import * as schema from "./schema"; +// Export the db instance from your drizzle setup (make sure your drizzle file is updated for Postgres) export { db } from "./drizzle"; export * as schema from "./schema"; -export { SqliteError } from "better-sqlite3"; -// This is exported here to avoid leaking better-sqlite types outside of this package. -export type LifetrackerDBTransaction = SQLiteTransaction< - "sync", - Database.RunResult, - typeof schema, - ExtractTablesWithRelations ->; +// If you need to export Postgres errors, you can export them from the pg package. +// (Optional – remove if not needed) +export { DatabaseError } from "pg"; +export const ErrorCodes = { + UNIQUE_VIOLATION: "23505", +}; + +/** + * This type alias is provided to avoid leaking pg types outside of this package. + * + * Note: + * - The first generic parameter is set to "async" because most PostgreSQL drivers (like pg) are asynchronous. + * - The second generic parameter uses pg's QueryResult type. + */ +export type LifetrackerDBTransaction = PgTransaction>; diff --git a/packages/db/lifetracker.db b/packages/db/lifetracker.db deleted file mode 100644 index fb3e8562f16ea2314948e2303d6c3e408f18678a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77824 zcmeI&&2t*(9l&wcNFY!o9BUj#bq_nb$oQpR#M{yyS{mVm5y7@Bwee&U*q3K*CIS>d zj+GoT*qvTFy)-kux3`{p==8tne~^Emms~o1JM_@!*LSkA8u-+ZNGZ!xV6~nOb+YM?#p#7c-+W!8lZRhy&fnL{jB4vr@SgUv zGPLX?@m%!VUfZ#T?Oykw_p#_+DoBM59#no@uj;K!`{huQiB{Vc-Jz^W^jrE+ycp_@ z2M2oNuwK6-cMes>Gs?w_<91&RT6()X6i-Ee@}!6Rwf8FfPxQU&lbe&Z-_gVBGRaIO z6-yu9(;~ju;FBYH(QjHO!=C@Sd8wz(?4_csqsMQ=)7P(SuM$3oin4mHO%GZXjmH^| zW1@eP-43F9nIOooIpsg`gCN{92!+<}SWiXJnEH5Z4F;d~`tlgXt4jL4qj0~zTfJX7 ztRLvxs-xS<%=TI={e$cCVAMg)ta@D^9VO%G8#lC9_x#}x#9$y3A$(h%MhHs-hwy`+ zGXFtDH6#;!#@JsI{`(L1tF?C;D*SS)gjHnp{p$Vdezoy-^>H|LRc^F0YAPQ-+*Px_ z+tV#aWwR>Vt=6lu%&`WJ<%(qH?rJPuxiQZr98)tJZoKjG)=E6RxvBju&Y2>LrC9p*ZS6_000tM4fso%Nx-!PoAD5?kePQQKbv?f$&&;I$8M*bj9Q3F1 zDK9OfN8^DHV_|#K-()Tv7hLCM zp`0MW7&G-`W|Yz5=|Vvpo%oG6n{L1T*=I+h*=axR`&awHtgrLIo|N+z9rJd^9ubUcFcaD|f-MDLz-hiBfo5=(zjn74Aw>O(U-t28QI zSCs9Vd@im3DU$j_%1dp^4IT&}fB*srAb3OS=- z7>?)JWi#t|PQfgdglFY#FDJ6ulH(Rig?wIQ%jKeJ?Fi2nrGn{NMn3OoUvB@cw6YiV zE3*rB*)0gyHuI+GSh<{S3bSl@rk&doL?aQ^_e6hQy`IR{$>j=j&vUypj;TW#r+VW_pRP~qAjVHsCu~)jYbmc{=fXEe;x=RfB*srAb statement-breakpoint -CREATE TABLE `apiKey` ( - `id` text PRIMARY KEY NOT NULL, - `name` text NOT NULL, - `createdAt` integer NOT NULL, - `keyId` text NOT NULL, - `keyHash` text NOT NULL, - `userId` text NOT NULL, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `category` ( - `id` text PRIMARY KEY NOT NULL, - `createdAt` integer NOT NULL, - `name` text NOT NULL, - `code` real NOT NULL, - `description` text, - `colorId` text NOT NULL, - `parentId` text, - `userId` text NOT NULL, - FOREIGN KEY (`colorId`) REFERENCES `color`(`id`) ON UPDATE no action ON DELETE no action, - FOREIGN KEY (`parentId`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE no action, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `color` ( - `id` text PRIMARY KEY NOT NULL, - `createdAt` integer NOT NULL, - `name` text NOT NULL, - `hexcode` text NOT NULL, - `inverse` text, - `userId` text NOT NULL, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `config` ( - `key` text PRIMARY KEY NOT NULL, - `value` text NOT NULL -); ---> statement-breakpoint -CREATE TABLE `day` ( - `id` text PRIMARY KEY NOT NULL, - `date` text NOT NULL, - `mood` integer, - `comment` text, - `userId` text NOT NULL, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `hour` ( - `id` text PRIMARY KEY NOT NULL, - `createdAt` integer NOT NULL, - `userId` text NOT NULL, - `comment` text, - `time` integer NOT NULL, - `dayId` text NOT NULL, - `categoryId` text, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (`dayId`) REFERENCES `day`(`id`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (`categoryId`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE no action -); ---> statement-breakpoint -CREATE TABLE `measurement` ( - `id` text PRIMARY KEY NOT NULL, - `hourId` text, - `dayId` text NOT NULL, - `metricId` text NOT NULL, - `createdAt` integer NOT NULL, - `userId` text NOT NULL, - `value` text NOT NULL, - FOREIGN KEY (`hourId`) REFERENCES `hour`(`id`) ON UPDATE no action ON DELETE no action, - FOREIGN KEY (`dayId`) REFERENCES `day`(`id`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (`metricId`) REFERENCES `metric`(`id`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `metric` ( - `id` text PRIMARY KEY NOT NULL, - `name` text NOT NULL, - `description` text, - `userId` text NOT NULL, - `type` text NOT NULL, - `unit` text, - `goal` real, - `icon` text NOT NULL, - `createdAt` integer NOT NULL, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `session` ( - `sessionToken` text PRIMARY KEY NOT NULL, - `userId` text NOT NULL, - `expires` integer NOT NULL, - FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE TABLE `user` ( - `id` text PRIMARY KEY NOT NULL, - `name` text NOT NULL, - `email` text NOT NULL, - `emailVerified` integer, - `image` text, - `password` text, - `role` text DEFAULT 'user', - `timezone` text DEFAULT 'America/Los_Angeles' NOT NULL -); ---> statement-breakpoint -CREATE TABLE `verificationToken` ( - `identifier` text NOT NULL, - `token` text NOT NULL, - `expires` integer NOT NULL, - PRIMARY KEY(`identifier`, `token`) -); ---> statement-breakpoint -CREATE UNIQUE INDEX `apiKey_keyId_unique` ON `apiKey` (`keyId`);--> statement-breakpoint -CREATE UNIQUE INDEX `apiKey_name_userId_unique` ON `apiKey` (`name`,`userId`);--> statement-breakpoint -CREATE UNIQUE INDEX `category_userId_code_unique` ON `category` (`userId`,`code`);--> statement-breakpoint -CREATE UNIQUE INDEX `color_userId_name_unique` ON `color` (`userId`,`name`);--> statement-breakpoint -CREATE UNIQUE INDEX `day_date_unique` ON `day` (`date`);--> statement-breakpoint -CREATE UNIQUE INDEX `hour_dayId_time_unique` ON `hour` (`dayId`,`time`);--> statement-breakpoint -CREATE UNIQUE INDEX `metric_userId_name_unique` ON `metric` (`userId`,`name`);--> statement-breakpoint -CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`); \ No newline at end of file diff --git a/packages/db/migrations/0000_redundant_glorian.sql b/packages/db/migrations/0000_redundant_glorian.sql new file mode 100644 index 0000000..4b7a30e --- /dev/null +++ b/packages/db/migrations/0000_redundant_glorian.sql @@ -0,0 +1,215 @@ +CREATE TABLE IF NOT EXISTS "account" ( + "userId" text NOT NULL, + "type" text NOT NULL, + "provider" text NOT NULL, + "providerAccountId" text NOT NULL, + "refresh_token" text, + "access_token" text, + "expires_at" integer, + "token_type" text, + "scope" text, + "id_token" text, + "session_state" text, + CONSTRAINT "account_provider_providerAccountId_pk" PRIMARY KEY("provider","providerAccountId") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "apiKey" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "keyId" text NOT NULL, + "keyHash" text NOT NULL, + "userId" text NOT NULL, + CONSTRAINT "apiKey_keyId_unique" UNIQUE("keyId"), + CONSTRAINT "apiKey_name_userId_unique" UNIQUE("name","userId") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "category" ( + "id" text PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "name" text NOT NULL, + "code" real NOT NULL, + "description" text, + "colorId" text NOT NULL, + "parentId" text, + "userId" text NOT NULL, + CONSTRAINT "category_userId_code_unique" UNIQUE("userId","code") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "color" ( + "id" text PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "name" text NOT NULL, + "hexcode" text NOT NULL, + "inverse" text, + "userId" text NOT NULL, + CONSTRAINT "color_userId_name_unique" UNIQUE("userId","name") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "config" ( + "key" text PRIMARY KEY NOT NULL, + "value" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "day" ( + "id" text PRIMARY KEY NOT NULL, + "date" text NOT NULL, + "mood" integer, + "comment" text, + "userId" text NOT NULL, + CONSTRAINT "day_date_unique" UNIQUE("date") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "hour" ( + "id" text PRIMARY KEY NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "userId" text NOT NULL, + "comment" text, + "time" integer NOT NULL, + "dayId" text NOT NULL, + "categoryId" text +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "measurement" ( + "id" text PRIMARY KEY NOT NULL, + "hourId" text, + "dayId" text NOT NULL, + "metricId" text NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "userId" text NOT NULL, + "value" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "metric" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "description" text, + "userId" text NOT NULL, + "type" text NOT NULL, + "unit" text, + "goal" real, + "icon" text NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "metric_userId_name_unique" UNIQUE("userId","name") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "session" ( + "sessionToken" text PRIMARY KEY NOT NULL, + "userId" text NOT NULL, + "expires" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "emailVerified" integer, + "image" text, + "password" text, + "role" text DEFAULT 'user', + "timezone" text DEFAULT 'America/Los_Angeles' NOT NULL, + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "verificationToken" ( + "identifier" text NOT NULL, + "token" text NOT NULL, + "expires" timestamp NOT NULL, + CONSTRAINT "verificationToken_identifier_token_pk" PRIMARY KEY("identifier","token") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "account" ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "apiKey" ADD CONSTRAINT "apiKey_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "category" ADD CONSTRAINT "category_colorId_color_id_fk" FOREIGN KEY ("colorId") REFERENCES "public"."color"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "category" ADD CONSTRAINT "category_parentId_category_id_fk" FOREIGN KEY ("parentId") REFERENCES "public"."category"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "category" ADD CONSTRAINT "category_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "color" ADD CONSTRAINT "color_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "day" ADD CONSTRAINT "day_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "hour" ADD CONSTRAINT "hour_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "hour" ADD CONSTRAINT "hour_dayId_day_id_fk" FOREIGN KEY ("dayId") REFERENCES "public"."day"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "hour" ADD CONSTRAINT "hour_categoryId_category_id_fk" FOREIGN KEY ("categoryId") REFERENCES "public"."category"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "measurement" ADD CONSTRAINT "measurement_hourId_hour_id_fk" FOREIGN KEY ("hourId") REFERENCES "public"."hour"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "measurement" ADD CONSTRAINT "measurement_dayId_day_id_fk" FOREIGN KEY ("dayId") REFERENCES "public"."day"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "measurement" ADD CONSTRAINT "measurement_metricId_metric_id_fk" FOREIGN KEY ("metricId") REFERENCES "public"."metric"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "measurement" ADD CONSTRAINT "measurement_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "metric" ADD CONSTRAINT "metric_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "session" ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/packages/db/migrations/0001_modify_hour_datetime.sql b/packages/db/migrations/0001_modify_hour_datetime.sql new file mode 100644 index 0000000..abc94e4 --- /dev/null +++ b/packages/db/migrations/0001_modify_hour_datetime.sql @@ -0,0 +1,18 @@ +-- Custom SQL migration file, put you code below! -- + -- Step 1: Add the new 'datetime' column + ALTER TABLE "hour" + ADD COLUMN "datetime" TIMESTAMPTZ; + + -- Step 2: Update 'datetime' by combining 'Day.date' and 'Hour.time' + UPDATE "hour" + SET "datetime" = ("day"."date"::timestamp + ("hour"."time" * INTERVAL '1 hour')) AT TIME ZONE 'UTC' + FROM "day" + WHERE "hour"."dayId" = "day"."id"; + + -- Step 3: Add a unique constraint to 'datetime' + ALTER TABLE "hour" + ADD CONSTRAINT "hour_datetime_unique" UNIQUE("datetime"); + + -- Step 3: Drop the old 'time' column + ALTER TABLE "hour" + DROP COLUMN "time"; diff --git a/packages/db/migrations/0002_seed_ryan_user.sql b/packages/db/migrations/0002_seed_ryan_user.sql new file mode 100644 index 0000000..ea5d72d --- /dev/null +++ b/packages/db/migrations/0002_seed_ryan_user.sql @@ -0,0 +1,54 @@ +INSERT INTO "user" ( + "id", + "name", + "email", + "emailVerified", + "image", + "password", + "role", + "timezone" +) +VALUES ( + 'n7yns1s5b122y5e8v0p6uyt8', + 'Ryan Pandya', + 'ryan@ryanpandya.com', + null, + null, + '$2a$10$ngv9752uxDT11hSPfdZmAe2D8VXLB9mcXkN7TRPI5GZQCuriIu1gC', + 'admin', + 'America/Los_Angeles' +); + +INSERT INTO "apiKey" ( + "id", + "name", + "createdAt", + "keyId", + "keyHash", + "userId" +) +VALUES ( + 'wxl62dg2n721tgzlz3spnjbu', + 'CLI App', + to_timestamp('1731634820') AT TIME ZONE 'UTC', + 'b9b17eb909ce0ecdbf33', + '$2a$10$NhOG42FjMbDycWHcJI4LH.Jp.aCV.op7llIP0zw/CBUmB3lO0HHQu', + 'n7yns1s5b122y5e8v0p6uyt8' +); + +INSERT INTO "apiKey" ( + "id", + "name", + "createdAt", + "keyId", + "keyHash", + "userId" +) +VALUES ( + 'i703hxfm1xoov08jc214jnoz', + 'Node-Red', + to_timestamp('1737068601') AT TIME ZONE 'UTC', + '820b8395dee76268b559', + '$2a$10$eUs4vYj2jr47LY6Rou4peudddpB/pyHRo2.cbomoUqNbAJf9RtZDS', + 'n7yns1s5b122y5e8v0p6uyt8' +); \ No newline at end of file diff --git a/packages/db/migrations/0003_silky_mongu.sql b/packages/db/migrations/0003_silky_mongu.sql new file mode 100644 index 0000000..25d5a40 --- /dev/null +++ b/packages/db/migrations/0003_silky_mongu.sql @@ -0,0 +1,6 @@ +ALTER TABLE "apiKey" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone;--> statement-breakpoint +ALTER TABLE "category" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone;--> statement-breakpoint +ALTER TABLE "color" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone;--> statement-breakpoint +ALTER TABLE "hour" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone;--> statement-breakpoint +ALTER TABLE "measurement" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone;--> statement-breakpoint +ALTER TABLE "metric" ALTER COLUMN "createdAt" SET DATA TYPE timestamp with time zone; \ No newline at end of file diff --git a/packages/db/migrations/0004_tan_justin_hammer.sql b/packages/db/migrations/0004_tan_justin_hammer.sql new file mode 100644 index 0000000..5e967cd --- /dev/null +++ b/packages/db/migrations/0004_tan_justin_hammer.sql @@ -0,0 +1 @@ +ALTER TABLE "hour" DROP COLUMN IF EXISTS "time"; \ No newline at end of file diff --git a/packages/db/migrations/meta/0000_snapshot.json b/packages/db/migrations/meta/0000_snapshot.json index f2bf3a2..63ab378 100644 --- a/packages/db/migrations/meta/0000_snapshot.json +++ b/packages/db/migrations/meta/0000_snapshot.json @@ -1,88 +1,78 @@ { - "version": "6", - "dialect": "sqlite", - "id": "9a832735-dcfa-42cc-ad15-6be5b898a160", + "id": "8809abd6-6301-4dba-9f67-13071abd3086", "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", "tables": { - "account": { + "public.account": { "name": "account", + "schema": "", "columns": { "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "type": { "name": "type", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "provider": { "name": "provider", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "providerAccountId": { "name": "providerAccountId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "refresh_token": { "name": "refresh_token", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "access_token": { "name": "access_token", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "expires_at": { "name": "expires_at", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "token_type": { "name": "token_type", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "scope": { "name": "scope", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "id_token": { "name": "id_token", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "session_state": { "name": "session_state", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false } }, "indexes": {}, @@ -103,78 +93,58 @@ }, "compositePrimaryKeys": { "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", "columns": [ "provider", "providerAccountId" - ], - "name": "account_provider_providerAccountId_pk" + ] } }, "uniqueConstraints": {} }, - "apiKey": { + "public.apiKey": { "name": "apiKey", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "name": { "name": "name", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false + "default": "now()" }, "keyId": { "name": "keyId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "keyHash": { "name": "keyHash", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "apiKey_keyId_unique": { - "name": "apiKey_keyId_unique", - "columns": [ - "keyId" - ], - "isUnique": true - }, - "apiKey_name_userId_unique": { - "name": "apiKey_name_userId_unique", - "columns": [ - "name", - "userId" - ], - "isUnique": true + "notNull": true } }, + "indexes": {}, "foreignKeys": { "apiKey_userId_user_id_fk": { "name": "apiKey_userId_user_id_fk", @@ -191,78 +161,79 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "apiKey_keyId_unique": { + "name": "apiKey_keyId_unique", + "nullsNotDistinct": false, + "columns": [ + "keyId" + ] + }, + "apiKey_name_userId_unique": { + "name": "apiKey_name_userId_unique", + "nullsNotDistinct": false, + "columns": [ + "name", + "userId" + ] + } + } }, - "category": { + "public.category": { "name": "category", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false + "default": "now()" }, "name": { "name": "name", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "code": { "name": "code", "type": "real", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "description": { "name": "description", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "colorId": { "name": "colorId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "parentId": { "name": "parentId", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "category_userId_code_unique": { - "name": "category_userId_code_unique", - "columns": [ - "userId", - "code" - ], - "isUnique": true + "notNull": true } }, + "indexes": {}, "foreignKeys": { "category_colorId_color_id_fk": { "name": "category_colorId_color_id_fk", @@ -305,64 +276,60 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "category_userId_code_unique": { + "name": "category_userId_code_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "code" + ] + } + } }, - "color": { + "public.color": { "name": "color", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false + "default": "now()" }, "name": { "name": "name", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "hexcode": { "name": "hexcode", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "inverse": { "name": "inverse", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "color_userId_name_unique": { - "name": "color_userId_name_unique", - "columns": [ - "userId", - "name" - ], - "isUnique": true + "notNull": true } }, + "indexes": {}, "foreignKeys": { "color_userId_user_id_fk": { "name": "color_userId_user_id_fk", @@ -379,24 +346,32 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "color_userId_name_unique": { + "name": "color_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } }, - "config": { + "public.config": { "name": "config", + "schema": "", "columns": { "key": { "name": "key", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "value": { "name": "value", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true } }, "indexes": {}, @@ -404,54 +379,42 @@ "compositePrimaryKeys": {}, "uniqueConstraints": {} }, - "day": { + "public.day": { "name": "day", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "date": { "name": "date", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "mood": { "name": "mood", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "comment": { "name": "comment", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "day_date_unique": { - "name": "day_date_unique", - "columns": [ - "date" - ], - "isUnique": true + "notNull": true } }, + "indexes": {}, "foreignKeys": { "day_userId_user_id_fk": { "name": "day_userId_user_id_fk", @@ -468,71 +431,71 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "day_date_unique": { + "name": "day_date_unique", + "nullsNotDistinct": false, + "columns": [ + "date" + ] + } + } }, - "hour": { + "public.hour": { "name": "hour", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false + "default": "now()" }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "comment": { "name": "comment", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "time": { "name": "time", "type": "integer", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true + }, + "datetime": { + "name": "datetime", + "type": "timestamp", + "primaryKey": false, + "notNull": true }, "dayId": { "name": "dayId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "categoryId": { "name": "categoryId", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "hour_dayId_time_unique": { - "name": "hour_dayId_time_unique", - "columns": [ - "dayId", - "time" - ], - "isUnique": true + "notNull": false } }, + "indexes": {}, "foreignKeys": { "hour_userId_user_id_fk": { "name": "hour_userId_user_id_fk", @@ -575,59 +538,63 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "hour_dayId_datetime_unique": { + "name": "hour_dayId_datetime_unique", + "nullsNotDistinct": false, + "columns": [ + "dayId", + "datetime" + ] + } + } }, - "measurement": { + "public.measurement": { "name": "measurement", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "hourId": { "name": "hourId", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "dayId": { "name": "dayId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "metricId": { "name": "metricId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false + "default": "now()" }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "value": { "name": "value", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true } }, "indexes": {}, @@ -688,83 +655,67 @@ "compositePrimaryKeys": {}, "uniqueConstraints": {} }, - "metric": { + "public.metric": { "name": "metric", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "name": { "name": "name", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "description": { "name": "description", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "type": { "name": "type", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "unit": { "name": "unit", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "goal": { "name": "goal", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "icon": { "name": "icon", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "createdAt": { "name": "createdAt", - "type": "integer", + "type": "timestamp", "primaryKey": false, "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "metric_userId_name_unique": { - "name": "metric_userId_name_unique", - "columns": [ - "userId", - "name" - ], - "isUnique": true + "default": "now()" } }, + "indexes": {}, "foreignKeys": { "metric_userId_user_id_fk": { "name": "metric_userId_user_id_fk", @@ -781,31 +732,38 @@ } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "metric_userId_name_unique": { + "name": "metric_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } }, - "session": { + "public.session": { "name": "session", + "schema": "", "columns": { "sessionToken": { "name": "sessionToken", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "userId": { "name": "userId", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "expires": { "name": "expires", - "type": "integer", + "type": "timestamp", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true } }, "indexes": {}, @@ -827,57 +785,51 @@ "compositePrimaryKeys": {}, "uniqueConstraints": {} }, - "user": { + "public.user": { "name": "user", + "schema": "", "columns": { "id": { "name": "id", "type": "text", "primaryKey": true, - "notNull": true, - "autoincrement": false + "notNull": true }, "name": { "name": "name", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "email": { "name": "email", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "emailVerified": { "name": "emailVerified", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "image": { "name": "image", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "password": { "name": "password", "type": "text", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "role": { "name": "role", "type": "text", "primaryKey": false, "notNull": false, - "autoincrement": false, "default": "'user'" }, "timezone": { @@ -885,69 +837,65 @@ "type": "text", "primaryKey": false, "notNull": true, - "autoincrement": false, "default": "'America/Los_Angeles'" } }, - "indexes": { - "user_email_unique": { - "name": "user_email_unique", - "columns": [ - "email" - ], - "isUnique": true - } - }, + "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } }, - "verificationToken": { + "public.verificationToken": { "name": "verificationToken", + "schema": "", "columns": { "identifier": { "name": "identifier", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "token": { "name": "token", "type": "text", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "expires": { "name": "expires", - "type": "integer", + "type": "timestamp", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true } }, "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", "columns": [ "identifier", "token" - ], - "name": "verificationToken_identifier_token_pk" + ] } }, "uniqueConstraints": {} } }, "enums": {}, + "schemas": {}, + "sequences": {}, "_meta": { + "columns": {}, "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} + "tables": {} } } \ No newline at end of file diff --git a/packages/db/migrations/meta/0001_snapshot.json b/packages/db/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..cc63263 --- /dev/null +++ b/packages/db/migrations/meta/0001_snapshot.json @@ -0,0 +1,901 @@ +{ + "id": "d1116059-9901-4852-9826-5a4458564eb5", + "prevId": "8809abd6-6301-4dba-9f67-13071abd3086", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "public.apiKey": { + "name": "apiKey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "keyId": { + "name": "keyId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyHash": { + "name": "keyHash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKey_keyId_unique": { + "name": "apiKey_keyId_unique", + "columns": [ + "keyId" + ], + "nullsNotDistinct": false + }, + "apiKey_name_userId_unique": { + "name": "apiKey_name_userId_unique", + "columns": [ + "name", + "userId" + ], + "nullsNotDistinct": false + } + } + }, + "public.category": { + "name": "category", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "colorId": { + "name": "colorId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parentId": { + "name": "parentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "category_colorId_color_id_fk": { + "name": "category_colorId_color_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "colorId" + ], + "tableTo": "color", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "category_parentId_category_id_fk": { + "name": "category_parentId_category_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "parentId" + ], + "tableTo": "category", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "category_userId_user_id_fk": { + "name": "category_userId_user_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "category_userId_code_unique": { + "name": "category_userId_code_unique", + "columns": [ + "userId", + "code" + ], + "nullsNotDistinct": false + } + } + }, + "public.color": { + "name": "color", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hexcode": { + "name": "hexcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inverse": { + "name": "inverse", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "color_userId_user_id_fk": { + "name": "color_userId_user_id_fk", + "tableFrom": "color", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "color_userId_name_unique": { + "name": "color_userId_name_unique", + "columns": [ + "userId", + "name" + ], + "nullsNotDistinct": false + } + } + }, + "public.config": { + "name": "config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.day": { + "name": "day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mood": { + "name": "mood", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "day_userId_user_id_fk": { + "name": "day_userId_user_id_fk", + "tableFrom": "day", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "day_date_unique": { + "name": "day_date_unique", + "columns": [ + "date" + ], + "nullsNotDistinct": false + } + } + }, + "public.hour": { + "name": "hour", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "time": { + "name": "time", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "datetime": { + "name": "datetime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoryId": { + "name": "categoryId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hour_userId_user_id_fk": { + "name": "hour_userId_user_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "hour_dayId_day_id_fk": { + "name": "hour_dayId_day_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "dayId" + ], + "tableTo": "day", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "hour_categoryId_category_id_fk": { + "name": "hour_categoryId_category_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "categoryId" + ], + "tableTo": "category", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hour_dayId_datetime_unique": { + "name": "hour_dayId_datetime_unique", + "columns": [ + "dayId", + "datetime" + ], + "nullsNotDistinct": false + } + } + }, + "public.measurement": { + "name": "measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "hourId": { + "name": "hourId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metricId": { + "name": "metricId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "measurement_hourId_hour_id_fk": { + "name": "measurement_hourId_hour_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "hourId" + ], + "tableTo": "hour", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "measurement_dayId_day_id_fk": { + "name": "measurement_dayId_day_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "dayId" + ], + "tableTo": "day", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "measurement_metricId_metric_id_fk": { + "name": "measurement_metricId_metric_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "metricId" + ], + "tableTo": "metric", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "measurement_userId_user_id_fk": { + "name": "measurement_userId_user_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.metric": { + "name": "metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal": { + "name": "goal", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "metric_userId_user_id_fk": { + "name": "metric_userId_user_id_fk", + "tableFrom": "metric", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "metric_userId_name_unique": { + "name": "metric_userId_name_unique", + "columns": [ + "userId", + "name" + ], + "nullsNotDistinct": false + } + } + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'America/Los_Angeles'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + } + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/0002_snapshot.json b/packages/db/migrations/meta/0002_snapshot.json new file mode 100644 index 0000000..dd2d442 --- /dev/null +++ b/packages/db/migrations/meta/0002_snapshot.json @@ -0,0 +1,901 @@ +{ + "id": "708d11dd-ccaa-48dd-b152-f012b2412704", + "prevId": "d1116059-9901-4852-9826-5a4458564eb5", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "public.apiKey": { + "name": "apiKey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "keyId": { + "name": "keyId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyHash": { + "name": "keyHash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKey_keyId_unique": { + "name": "apiKey_keyId_unique", + "columns": [ + "keyId" + ], + "nullsNotDistinct": false + }, + "apiKey_name_userId_unique": { + "name": "apiKey_name_userId_unique", + "columns": [ + "name", + "userId" + ], + "nullsNotDistinct": false + } + } + }, + "public.category": { + "name": "category", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "colorId": { + "name": "colorId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parentId": { + "name": "parentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "category_colorId_color_id_fk": { + "name": "category_colorId_color_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "colorId" + ], + "tableTo": "color", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "category_parentId_category_id_fk": { + "name": "category_parentId_category_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "parentId" + ], + "tableTo": "category", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "category_userId_user_id_fk": { + "name": "category_userId_user_id_fk", + "tableFrom": "category", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "category_userId_code_unique": { + "name": "category_userId_code_unique", + "columns": [ + "userId", + "code" + ], + "nullsNotDistinct": false + } + } + }, + "public.color": { + "name": "color", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hexcode": { + "name": "hexcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inverse": { + "name": "inverse", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "color_userId_user_id_fk": { + "name": "color_userId_user_id_fk", + "tableFrom": "color", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "color_userId_name_unique": { + "name": "color_userId_name_unique", + "columns": [ + "userId", + "name" + ], + "nullsNotDistinct": false + } + } + }, + "public.config": { + "name": "config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.day": { + "name": "day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mood": { + "name": "mood", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "day_userId_user_id_fk": { + "name": "day_userId_user_id_fk", + "tableFrom": "day", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "day_date_unique": { + "name": "day_date_unique", + "columns": [ + "date" + ], + "nullsNotDistinct": false + } + } + }, + "public.hour": { + "name": "hour", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "time": { + "name": "time", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "datetime": { + "name": "datetime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoryId": { + "name": "categoryId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hour_userId_user_id_fk": { + "name": "hour_userId_user_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "hour_dayId_day_id_fk": { + "name": "hour_dayId_day_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "dayId" + ], + "tableTo": "day", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "hour_categoryId_category_id_fk": { + "name": "hour_categoryId_category_id_fk", + "tableFrom": "hour", + "columnsFrom": [ + "categoryId" + ], + "tableTo": "category", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hour_dayId_datetime_unique": { + "name": "hour_dayId_datetime_unique", + "columns": [ + "dayId", + "datetime" + ], + "nullsNotDistinct": false + } + } + }, + "public.measurement": { + "name": "measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "hourId": { + "name": "hourId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metricId": { + "name": "metricId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "measurement_hourId_hour_id_fk": { + "name": "measurement_hourId_hour_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "hourId" + ], + "tableTo": "hour", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "measurement_dayId_day_id_fk": { + "name": "measurement_dayId_day_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "dayId" + ], + "tableTo": "day", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "measurement_metricId_metric_id_fk": { + "name": "measurement_metricId_metric_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "metricId" + ], + "tableTo": "metric", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "measurement_userId_user_id_fk": { + "name": "measurement_userId_user_id_fk", + "tableFrom": "measurement", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.metric": { + "name": "metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal": { + "name": "goal", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "metric_userId_user_id_fk": { + "name": "metric_userId_user_id_fk", + "tableFrom": "metric", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "metric_userId_name_unique": { + "name": "metric_userId_name_unique", + "columns": [ + "userId", + "name" + ], + "nullsNotDistinct": false + } + } + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "columnsFrom": [ + "userId" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'America/Los_Angeles'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + } + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/0003_snapshot.json b/packages/db/migrations/meta/0003_snapshot.json new file mode 100644 index 0000000..1908e00 --- /dev/null +++ b/packages/db/migrations/meta/0003_snapshot.json @@ -0,0 +1,901 @@ +{ + "id": "2e969918-73b6-4418-bb7b-76acda909a8a", + "prevId": "708d11dd-ccaa-48dd-b152-f012b2412704", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "public.apiKey": { + "name": "apiKey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "keyId": { + "name": "keyId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyHash": { + "name": "keyHash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKey_keyId_unique": { + "name": "apiKey_keyId_unique", + "nullsNotDistinct": false, + "columns": [ + "keyId" + ] + }, + "apiKey_name_userId_unique": { + "name": "apiKey_name_userId_unique", + "nullsNotDistinct": false, + "columns": [ + "name", + "userId" + ] + } + } + }, + "public.category": { + "name": "category", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "colorId": { + "name": "colorId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parentId": { + "name": "parentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "category_colorId_color_id_fk": { + "name": "category_colorId_color_id_fk", + "tableFrom": "category", + "tableTo": "color", + "columnsFrom": [ + "colorId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "category_parentId_category_id_fk": { + "name": "category_parentId_category_id_fk", + "tableFrom": "category", + "tableTo": "category", + "columnsFrom": [ + "parentId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "category_userId_user_id_fk": { + "name": "category_userId_user_id_fk", + "tableFrom": "category", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "category_userId_code_unique": { + "name": "category_userId_code_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "code" + ] + } + } + }, + "public.color": { + "name": "color", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hexcode": { + "name": "hexcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inverse": { + "name": "inverse", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "color_userId_user_id_fk": { + "name": "color_userId_user_id_fk", + "tableFrom": "color", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "color_userId_name_unique": { + "name": "color_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } + }, + "public.config": { + "name": "config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.day": { + "name": "day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mood": { + "name": "mood", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "day_userId_user_id_fk": { + "name": "day_userId_user_id_fk", + "tableFrom": "day", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "day_date_unique": { + "name": "day_date_unique", + "nullsNotDistinct": false, + "columns": [ + "date" + ] + } + } + }, + "public.hour": { + "name": "hour", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "time": { + "name": "time", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "datetime": { + "name": "datetime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoryId": { + "name": "categoryId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hour_userId_user_id_fk": { + "name": "hour_userId_user_id_fk", + "tableFrom": "hour", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "hour_dayId_day_id_fk": { + "name": "hour_dayId_day_id_fk", + "tableFrom": "hour", + "tableTo": "day", + "columnsFrom": [ + "dayId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "hour_categoryId_category_id_fk": { + "name": "hour_categoryId_category_id_fk", + "tableFrom": "hour", + "tableTo": "category", + "columnsFrom": [ + "categoryId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hour_dayId_datetime_unique": { + "name": "hour_dayId_datetime_unique", + "nullsNotDistinct": false, + "columns": [ + "dayId", + "datetime" + ] + } + } + }, + "public.measurement": { + "name": "measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "hourId": { + "name": "hourId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metricId": { + "name": "metricId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "measurement_hourId_hour_id_fk": { + "name": "measurement_hourId_hour_id_fk", + "tableFrom": "measurement", + "tableTo": "hour", + "columnsFrom": [ + "hourId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "measurement_dayId_day_id_fk": { + "name": "measurement_dayId_day_id_fk", + "tableFrom": "measurement", + "tableTo": "day", + "columnsFrom": [ + "dayId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "measurement_metricId_metric_id_fk": { + "name": "measurement_metricId_metric_id_fk", + "tableFrom": "measurement", + "tableTo": "metric", + "columnsFrom": [ + "metricId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "measurement_userId_user_id_fk": { + "name": "measurement_userId_user_id_fk", + "tableFrom": "measurement", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.metric": { + "name": "metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal": { + "name": "goal", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "metric_userId_user_id_fk": { + "name": "metric_userId_user_id_fk", + "tableFrom": "metric", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "metric_userId_name_unique": { + "name": "metric_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'America/Los_Angeles'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/0004_snapshot.json b/packages/db/migrations/meta/0004_snapshot.json new file mode 100644 index 0000000..0d5ab12 --- /dev/null +++ b/packages/db/migrations/meta/0004_snapshot.json @@ -0,0 +1,895 @@ +{ + "id": "37a5291a-eed6-4576-a240-2825abdff575", + "prevId": "2e969918-73b6-4418-bb7b-76acda909a8a", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "public.apiKey": { + "name": "apiKey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "keyId": { + "name": "keyId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyHash": { + "name": "keyHash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apiKey_keyId_unique": { + "name": "apiKey_keyId_unique", + "nullsNotDistinct": false, + "columns": [ + "keyId" + ] + }, + "apiKey_name_userId_unique": { + "name": "apiKey_name_userId_unique", + "nullsNotDistinct": false, + "columns": [ + "name", + "userId" + ] + } + } + }, + "public.category": { + "name": "category", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "colorId": { + "name": "colorId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parentId": { + "name": "parentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "category_colorId_color_id_fk": { + "name": "category_colorId_color_id_fk", + "tableFrom": "category", + "tableTo": "color", + "columnsFrom": [ + "colorId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "category_parentId_category_id_fk": { + "name": "category_parentId_category_id_fk", + "tableFrom": "category", + "tableTo": "category", + "columnsFrom": [ + "parentId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "category_userId_user_id_fk": { + "name": "category_userId_user_id_fk", + "tableFrom": "category", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "category_userId_code_unique": { + "name": "category_userId_code_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "code" + ] + } + } + }, + "public.color": { + "name": "color", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hexcode": { + "name": "hexcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inverse": { + "name": "inverse", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "color_userId_user_id_fk": { + "name": "color_userId_user_id_fk", + "tableFrom": "color", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "color_userId_name_unique": { + "name": "color_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } + }, + "public.config": { + "name": "config", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.day": { + "name": "day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mood": { + "name": "mood", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "day_userId_user_id_fk": { + "name": "day_userId_user_id_fk", + "tableFrom": "day", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "day_date_unique": { + "name": "day_date_unique", + "nullsNotDistinct": false, + "columns": [ + "date" + ] + } + } + }, + "public.hour": { + "name": "hour", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "datetime": { + "name": "datetime", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoryId": { + "name": "categoryId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hour_userId_user_id_fk": { + "name": "hour_userId_user_id_fk", + "tableFrom": "hour", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "hour_dayId_day_id_fk": { + "name": "hour_dayId_day_id_fk", + "tableFrom": "hour", + "tableTo": "day", + "columnsFrom": [ + "dayId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "hour_categoryId_category_id_fk": { + "name": "hour_categoryId_category_id_fk", + "tableFrom": "hour", + "tableTo": "category", + "columnsFrom": [ + "categoryId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hour_dayId_datetime_unique": { + "name": "hour_dayId_datetime_unique", + "nullsNotDistinct": false, + "columns": [ + "dayId", + "datetime" + ] + } + } + }, + "public.measurement": { + "name": "measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "hourId": { + "name": "hourId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dayId": { + "name": "dayId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metricId": { + "name": "metricId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "measurement_hourId_hour_id_fk": { + "name": "measurement_hourId_hour_id_fk", + "tableFrom": "measurement", + "tableTo": "hour", + "columnsFrom": [ + "hourId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "measurement_dayId_day_id_fk": { + "name": "measurement_dayId_day_id_fk", + "tableFrom": "measurement", + "tableTo": "day", + "columnsFrom": [ + "dayId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "measurement_metricId_metric_id_fk": { + "name": "measurement_metricId_metric_id_fk", + "tableFrom": "measurement", + "tableTo": "metric", + "columnsFrom": [ + "metricId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "measurement_userId_user_id_fk": { + "name": "measurement_userId_user_id_fk", + "tableFrom": "measurement", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.metric": { + "name": "metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal": { + "name": "goal", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "metric_userId_user_id_fk": { + "name": "metric_userId_user_id_fk", + "tableFrom": "metric", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "metric_userId_name_unique": { + "name": "metric_userId_name_unique", + "nullsNotDistinct": false, + "columns": [ + "userId", + "name" + ] + } + } + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'America/Los_Angeles'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index a772e87..cb03dca 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -1,12 +1,40 @@ { "version": "7", - "dialect": "sqlite", + "dialect": "postgresql", "entries": [ { "idx": 0, - "version": "6", - "when": 1733614471710, - "tag": "0000_moaning_thor", + "version": "7", + "when": 1738348952600, + "tag": "0000_redundant_glorian", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1738348955500, + "tag": "0001_modify_hour_datetime", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1738368573808, + "tag": "0002_seed_ryan_user", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1738369747329, + "tag": "0003_silky_mongu", + "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1738371187519, + "tag": "0004_tan_justin_hammer", "breakpoints": true } ] diff --git a/packages/db/package.json b/packages/db/package.json index aa0d016..93820ea 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -9,24 +9,26 @@ "generate": "drizzle-kit generate", "reset": "tsx reset.ts", "typecheck": "tsc --noEmit", - "migrate": "tsx migrate.ts", - "studio": "drizzle-kit studio" + "migrate": "drizzle-kit migrate", + "studio": "drizzle-kit studio", + "drizzle-kit": "drizzle-kit" }, "dependencies": { "@auth/core": "^0.37.3", "@paralleldrive/cuid2": "^2.2.2", - "better-sqlite3": "^11.3.0", "dotenv": "^16.4.1", "drizzle-orm": "^0.33.0", - "expo-sqlite": "^14.0.6", + "pg": "^8.11.3", "tsx": "^4.7.1" }, "devDependencies": { + "better-sqlite3": "^11.3.0", "@lifetracker/eslint-config": "workspace:*", "@lifetracker/typescript-config": "workspace:*", "@tsconfig/node21": "^21.0.1", - "@types/better-sqlite3": "^7.6.9", + "@types/pg": "^8.11.0", "drizzle-kit": "^0.24.2", + "pg-dump-restore": "^1.0.12", "sqlite3": "^5.1.7" }, "eslintConfig": { diff --git a/packages/db/schema.ts b/packages/db/schema.ts index e1ad64c..b6a7f5b 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -1,23 +1,19 @@ import type { AdapterAccount } from "@auth/core/adapters"; import { createId } from "@paralleldrive/cuid2"; import { relations, SQL, sql } from "drizzle-orm"; -import { date } from "drizzle-orm/mysql-core"; +import { time, timestamp } from "drizzle-orm/pg-core"; import { - AnySQLiteColumn, - index, + pgTable, integer, real, primaryKey, - sqliteTable, text, unique, -} from "drizzle-orm/sqlite-core"; +} from "drizzle-orm/pg-core"; function createdAtField() { - return integer("createdAt", { mode: "timestamp" }) - .notNull() - .$defaultFn(() => new Date()); + return timestamp("createdAt", { withTimezone: true }).notNull().defaultNow(); } export function calcInverseColor(hexcode: string): string { @@ -35,12 +31,12 @@ export function calcInverseColor(hexcode: string): string { -export const config = sqliteTable("config", { +export const config = pgTable("config", { key: text("key").notNull().primaryKey(), value: text("value").notNull(), }); -export const apiKeys = sqliteTable( +export const apiKeys = pgTable( "apiKey", { id: text("id") @@ -61,21 +57,21 @@ export const apiKeys = sqliteTable( ); -export const users = sqliteTable("user", { +export const users = pgTable("user", { id: text("id") .notNull() .primaryKey() .$defaultFn(() => createId()), name: text("name").notNull(), email: text("email").notNull().unique(), - emailVerified: integer("emailVerified", { mode: "timestamp_ms" }), + emailVerified: integer("emailVerified"), image: text("image"), password: text("password"), role: text("role", { enum: ["admin", "user"] }).default("user"), timezone: text("timezone").notNull().default("America/Los_Angeles"), }); -export const accounts = sqliteTable( +export const accounts = pgTable( "account", { userId: text("userId") @@ -99,7 +95,7 @@ export const accounts = sqliteTable( }), ); -export const sessions = sqliteTable("session", { +export const sessions = pgTable("session", { sessionToken: text("sessionToken") .notNull() .primaryKey() @@ -107,22 +103,22 @@ export const sessions = sqliteTable("session", { userId: text("userId") .notNull() .references(() => users.id, { onDelete: "cascade" }), - expires: integer("expires", { mode: "timestamp_ms" }).notNull(), + expires: timestamp("expires").notNull(), }); -export const verificationTokens = sqliteTable( +export const verificationTokens = pgTable( "verificationToken", { identifier: text("identifier").notNull(), token: text("token").notNull(), - expires: integer("expires", { mode: "timestamp_ms" }).notNull(), + expires: timestamp("expires").notNull(), }, (vt) => ({ compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), }), ); -export const metrics = sqliteTable("metric", { +export const metrics = pgTable("metric", { id: text("id") .notNull() .primaryKey() @@ -143,7 +139,7 @@ export const metrics = sqliteTable("metric", { }), ); -export const measurements = sqliteTable("measurement", { +export const measurements = pgTable("measurement", { id: text("id") .notNull() .primaryKey() @@ -162,7 +158,7 @@ export const measurements = sqliteTable("measurement", { }), ); -export const days = sqliteTable("day", { +export const days = pgTable("day", { id: text("id") .notNull() .primaryKey() @@ -175,7 +171,7 @@ export const days = sqliteTable("day", { .references(() => users.id, { onDelete: "cascade" }), }); -export const hours = sqliteTable( +export const hours = pgTable( "hour", { id: text("id") @@ -187,17 +183,17 @@ export const hours = sqliteTable( .notNull() .references(() => users.id, { onDelete: "cascade" }), comment: text("comment"), - time: integer("time").notNull(), + datetime: timestamp("datetime").notNull(), dayId: text("dayId").notNull().references(() => days.id, { onDelete: "cascade" }), categoryId: text("categoryId").references(() => categories.id), }, (e) => ({ - uniq: unique().on(e.dayId, e.time) + uniq: unique().on(e.dayId, e.datetime) }), ) -export const colors = sqliteTable( +export const colors = pgTable( "color", { id: text("id") @@ -220,7 +216,7 @@ export const colors = sqliteTable( // and fuck if the in built documentation makes any sense }), ); -export const categories = sqliteTable( +export const categories = pgTable( "category", { id: text("id") @@ -254,7 +250,11 @@ export const apiKeyRelations = relations(apiKeys, ({ one }) => ({ references: [users.id], }), })); -export const userRelations = relations(users, ({ many }) => ({ +export const userRelations = relations(users, ({ many, one }) => ({ + apiKeys: one(apiKeys, { + fields: [users.id], + references: [apiKeys.userId], + }), categories: many(categories), colors: many(colors), days: many(days), @@ -348,9 +348,9 @@ export const measurementsRelations = relations( fields: [measurements.dayId], references: [days.id], }), - hour: measurements.hourId ? one(hours, { + hour: one(hours, { fields: [measurements.hourId], references: [hours.id], - }) : undefined, + }), }), ); diff --git a/packages/shared/config.ts b/packages/shared/config.ts index e3c8117..73f7cb0 100644 --- a/packages/shared/config.ts +++ b/packages/shared/config.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import dotenv from "dotenv"; dotenv.config({ - path: ".env.local", + path: "../../.env.local", }); const stringBool = (defaultValue: string) => z @@ -55,6 +55,8 @@ const allEnv = z.object({ DEMO_MODE_EMAIL: z.string().optional(), DEMO_MODE_PASSWORD: z.string().optional(), DATA_DIR: z.string().default(""), + DATABASE_URL: z.string().default("postgres://lifetracker:pleasework@postgresql.home:5432/lifetracker"), + TEST_DATABASE_URL: z.string().default("postgres://lifetracker:pleasework@postgresql.home:5432/lifetracker_test"), MAX_ASSET_SIZE_MB: z.coerce.number().default(4), INFERENCE_LANG: z.string().default("english"), // Build only flag @@ -127,6 +129,8 @@ const serverConfigSchema = allEnv.transform((val) => { } : undefined, dataDir: val.DATA_DIR, + databaseUrl: val.DATABASE_URL, + testDatabaseUrl: val.TEST_DATABASE_URL, maxAssetSizeMb: val.MAX_ASSET_SIZE_MB, serverVersion: val.SERVER_VERSION, disableNewReleaseCheck: val.DISABLE_NEW_RELEASE_CHECK, diff --git a/packages/shared/types/days.ts b/packages/shared/types/days.ts index 4b41552..b29211a 100644 --- a/packages/shared/types/days.ts +++ b/packages/shared/types/days.ts @@ -6,8 +6,7 @@ export const zHourSchema = z.object({ id: z.string().optional(), dayId: z.string(), date: z.string().optional(), - time: z.number(), - datetime: z.string().optional(), + datetime: z.date(), categoryCode: z.coerce.number().nullish(), categoryId: z.string().nullish(), categoryName: z.string().nullish(), diff --git a/packages/trpc/routers/_app.ts b/packages/trpc/routers/_app.ts index 3492fd0..e2b03e6 100644 --- a/packages/trpc/routers/_app.ts +++ b/packages/trpc/routers/_app.ts @@ -1,4 +1,3 @@ -import { apiKeys } from "@lifetracker/db/schema"; import { router } from "../index"; import { usersAppRouter } from "./users"; import { apiKeysAppRouter } from "./apiKeys"; diff --git a/packages/trpc/routers/categories.ts b/packages/trpc/routers/categories.ts index 4f276cc..8f68ee6 100644 --- a/packages/trpc/routers/categories.ts +++ b/packages/trpc/routers/categories.ts @@ -2,7 +2,7 @@ import { experimental_trpcMiddleware, TRPCError } from "@trpc/server"; import { and, desc, eq, inArray, notExists } from "drizzle-orm"; import { z } from "zod"; -import { SqliteError } from "@lifetracker/db"; +import { DatabaseError } from "@lifetracker/db"; import { categories, colors } from "@lifetracker/db/schema"; import { ZCategories, @@ -54,8 +54,8 @@ async function createCategory( }; } catch (e) { - if (e instanceof SqliteError) { - if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { + if (e instanceof DatabaseError) { + if (e.code == "23505") { throw new TRPCError({ code: "BAD_REQUEST", message: "There's already a category with this code", diff --git a/packages/trpc/routers/colors.ts b/packages/trpc/routers/colors.ts index ac6f5d7..11b1359 100644 --- a/packages/trpc/routers/colors.ts +++ b/packages/trpc/routers/colors.ts @@ -2,7 +2,7 @@ import { experimental_trpcMiddleware, TRPCError } from "@trpc/server"; import { and, desc, eq, inArray, notExists } from "drizzle-orm"; import { z } from "zod"; -import { SqliteError } from "@lifetracker/db"; +import { DatabaseError, ErrorCodes } from "@lifetracker/db"; import { colors, calcInverseColor } from "@lifetracker/db/schema"; import { zColorSchema, ZColor @@ -37,8 +37,8 @@ async function createColor( }); return result[0]; } catch (e) { - if (e instanceof SqliteError) { - if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { + if (e instanceof DatabaseError) { + if (e.code == ErrorCodes.UNIQUE_VIOLATION) { throw new TRPCError({ code: "BAD_REQUEST", message: "This color already exists", diff --git a/packages/trpc/routers/days.ts b/packages/trpc/routers/days.ts index 103be92..5bfbee6 100644 --- a/packages/trpc/routers/days.ts +++ b/packages/trpc/routers/days.ts @@ -2,7 +2,7 @@ import { experimental_trpcMiddleware, TRPCError } from "@trpc/server"; import { and, desc, eq, inArray, notExists } from "drizzle-orm"; import { z } from "zod"; -import { db, SqliteError } from "@lifetracker/db"; +import { db, DatabaseError, ErrorCodes } from "@lifetracker/db"; import { categories, days, hours, users } from "@lifetracker/db/schema"; import { zDaySchema, ZDay, @@ -11,7 +11,7 @@ import { import type { Context } from "../index"; import { authedProcedure, router } from "../index"; import { dateFromInput, hoursListInUTC } from "@lifetracker/shared/utils/days"; -import { closestIndexTo, format } from "date-fns"; +import { addDays, closestIndexTo, format, parseISO } from "date-fns"; import { TZDate } from "@date-fns/tz"; import { hoursAppRouter, hourColors, hourJoinsQuery, getHours, createHour } from "./hours"; import spacetime from "spacetime"; @@ -36,8 +36,8 @@ export async function createDay(date: string, ctx: Context) { return dayRes[0]; } catch (e) { - if (e instanceof SqliteError) { - if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { + if (e instanceof DatabaseError) { + if (e.code == ErrorCodes.UNIQUE_VIOLATION) { throw new TRPCError({ code: "BAD_REQUEST", message: "This day already exists", @@ -75,6 +75,27 @@ export async function getDay(ctx: Context, input: { dateQuery: string, timezone: } } +export function listOfDates(dateRange: [Date, Date]) { + const [start, end] = dateRange.map((date) => dateFromInput({ + dateQuery: spacetime(date, "UTC").goto("UTC").format("iso-short"), + timezone: "Etc/UTC" + })); + const dates = []; + let currentDate = parseISO(start); + while (currentDate <= parseISO(end)) { + dates.push(format(currentDate, "yyyy-MM-dd")); + currentDate = addDays(currentDate, 1); + } + return dates.length === 0 ? [format(parseISO(start), "yyyy-MM-dd")] : dates; +} +export function listOfDayIds(dateRange: [Date, Date]) { + return listOfDates(dateRange).map((date) => + db.select({ id: days.id }) + .from(days) + .where(eq(days.date, date)) + ); +} + export const daysAppRouter = router({ get: authedProcedure .input(z.object({ diff --git a/packages/trpc/routers/hours.ts b/packages/trpc/routers/hours.ts index fe07f6d..992a9d2 100644 --- a/packages/trpc/routers/hours.ts +++ b/packages/trpc/routers/hours.ts @@ -1,27 +1,23 @@ -import { experimental_trpcMiddleware, TRPCError } from "@trpc/server"; +import { TRPCError } from "@trpc/server"; import { and, desc, eq, inArray, notExists } from "drizzle-orm"; -import { date, z } from "zod"; +import { z } from "zod"; -import { SqliteError } from "@lifetracker/db"; +import { DatabaseError } from "@lifetracker/db"; import { categories, days, hours, colors, measurements, metrics } from "@lifetracker/db/schema"; import { - zDaySchema, ZDay, ZHour, zHourSchema + ZDay, ZHour, zHourSchema } from "@lifetracker/shared/types/days"; import type { Context } from "../index"; import { authedProcedure, router } from "../index"; -import { addDays, format, parseISO } from "date-fns"; -import { TZDate } from "@date-fns/tz"; -import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; -import { zCategorySchema } from "@lifetracker/shared/types/categories"; import spacetime from "spacetime"; -import { dateFromInput, hoursListInUTC } from "@lifetracker/shared/utils/days"; -import { createDay, getDay } from "./days"; +import { hoursListInUTC } from "@lifetracker/shared/utils/days"; +import { createDay, listOfDates } from "./days"; -export async function createHour(day: ZDay | { id: string }, time: number, ctx: Context,) { +export async function createHour(day: { id: string }, datetime: Date, ctx: Context,) { const newHour = (await ctx.db.insert(hours).values({ - dayId: day.id!, - time: time, + dayId: day.id, + datetime: datetime, userId: ctx.user!.id, }).returning()); return newHour[0]; @@ -52,7 +48,7 @@ export async function hourColors(hour: ZHour, ctx: Context) { export async function hourJoinsQuery( ctx: Context, - time: number, + datetime: Date, dayId?: string, day?: ZDay, ) { @@ -67,7 +63,7 @@ export async function hourJoinsQuery( const res = await ctx.db.select({ id: hours.id, dayId: hours.dayId, - time: hours.time, + datetime: hours.datetime, categoryId: hours.categoryId, categoryCode: categories.code, categoryName: categories.name, @@ -78,11 +74,11 @@ export async function hourJoinsQuery( .leftJoin(categories, eq(categories.id, hours.categoryId)) .leftJoin(days, eq(days.id, hours.dayId)) .where(and( - eq(hours.time, time), + eq(hours.datetime, datetime), eq(hours.dayId, id) )); - const hourMatch = res[0] ?? createHour({ id: id }, time, ctx); + const hourMatch = res[0] ?? createHour({ id }, datetime, ctx); const hourMeasurements = await ctx.db.select({ @@ -131,33 +127,16 @@ export async function getHours(ctx: Context, input: { dateQuery: string | [Date, // Finally, use the two unique day IDs and the 24 hours to get the actual Hour objects for each day const dayHours = await Promise.all(uniqueHours.map(async function (map: { date: string, time: number }, i) { const dayId = uniqueDayIds.find((dayIds: { id: string, date: string }) => map.date == dayIds.date)!.id; - - return hourJoinsQuery(ctx, map.time, dayId); + const datetime = spacetime(map.date, "Etc/UTC").hour(map.time).toNativeDate(); + return hourJoinsQuery(ctx, datetime, dayId); })); return dayHours; } - -function listOfDates(dateRange: [Date, Date]) { - const [start, end] = dateRange.map((date) => dateFromInput({ - dateQuery: spacetime(date, "UTC").goto("UTC").format("iso-short"), - timezone: "Etc/UTC" - })); - const dates = []; - let currentDate = parseISO(start); - while (currentDate <= parseISO(end)) { - dates.push(format(currentDate, "yyyy-MM-dd")); - currentDate = addDays(currentDate, 1); - } - return dates.length === 0 ? [format(parseISO(start), "yyyy-MM-dd")] : dates; -} - - export const hoursAppRouter = router({ get: authedProcedure .input(z.object({ dateQuery: z.string(), - time: z.number() })) .output(zHourSchema) .query(async ({ input, ctx }) => { @@ -165,8 +144,7 @@ export const hoursAppRouter = router({ .leftJoin(days, eq(days.id, hours.dayId)) .where( and( - eq(hours.time, input.time), - eq(days.date, input.dateQuery), + eq(hours.datetime, spacetime(input.dateQuery, "Etc/UTC").toNativeDate()), eq(hours.userId, ctx.user!.id) ) ); @@ -255,10 +233,20 @@ export const hoursAppRouter = router({ } ))) .query(async ({ input, ctx }) => { + + // console.log(input.dateRange, input.timezone); const hoursList = await getHours(ctx, { dateQuery: input.dateRange, timezone: input.timezone }); + // console.log(hoursList.map(h => { + // return { + // datetime: spacetime(h.datetime).goto("America/Los_Angeles").format("{iso-short} {hour-24}:{minute}"), + // id: h.id, + // date: h.date, + // }; + // })); + // Count total hours in the filtered range const totalHours = hoursList.length; diff --git a/packages/trpc/routers/measurements.ts b/packages/trpc/routers/measurements.ts index fd2f531..42a025e 100644 --- a/packages/trpc/routers/measurements.ts +++ b/packages/trpc/routers/measurements.ts @@ -1,14 +1,17 @@ import { TRPCError } from "@trpc/server"; -import { and, desc, eq, inArray, notExists } from "drizzle-orm"; +import { and, desc, eq, inArray, notExists, sql } from "drizzle-orm"; import { z, ZodNull } from "zod"; -import { SqliteError } from "@lifetracker/db"; -import { colors, metrics, measurements, hours } from "@lifetracker/db/schema"; +import { DatabaseError } from "@lifetracker/db"; +import { colors, metrics, measurements, hours, days } from "@lifetracker/db/schema"; import { zMetricSchema, zMeasurementSchema } from "@lifetracker/shared/types/metrics"; import type { Context } from "../index"; import { authedProcedure, router } from "../index"; import { zColorSchema } from "@lifetracker/shared/types/colors"; import { titleCase } from "title-case"; +import { listOfDates, listOfDayIds } from "./days"; +import { getHours } from "./hours"; +import { datetime } from "drizzle-orm/mysql-core"; const getMetricFromInput = async (ctx: Context, input: { metricId?: string | null | undefined; metricName?: string | null | undefined; }) => { @@ -181,4 +184,44 @@ export const measurementsAppRouter = router({ return 0; } }), + getTimeseries: authedProcedure + .input(z.object({ + dateRange: z.tuple([z.date(), z.date()]), + timezone: z.string(), + metricName: z.string() + })) + .output(z.array(z.object({ + id: z.string(), + value: z.string(), + unit: z.string(), + datetime: z.date(), + }) + )) + .query(async ({ input, ctx }) => { + const hoursList = await getHours(ctx, { + dateQuery: input.dateRange, + timezone: input.timezone, + }); + const hourIds = hoursList.map((hour) => hour.id); + const metric = await ctx.db.select().from(metrics).where(eq(metrics.name, titleCase(input.metricName))); + if (!metric[0]) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Metric not found", + }); + } + const measurementsList = await ctx.db.select({ + id: measurements.id, + value: measurements.value, + unit: metrics.unit, + datetime: hours.datetime, + }).from(measurements) + .leftJoin(metrics, eq(measurements.metricId, metrics.id)) + .leftJoin(hours, eq(measurements.hourId, hours.id)) + .where(and( + eq(measurements.metricId, metric[0].id), + inArray(measurements.hourId, hourIds), + )); + return measurementsList; + }), }); \ No newline at end of file diff --git a/packages/trpc/routers/metrics.ts b/packages/trpc/routers/metrics.ts index 7fa7894..0e9162d 100644 --- a/packages/trpc/routers/metrics.ts +++ b/packages/trpc/routers/metrics.ts @@ -2,7 +2,7 @@ import { TRPCError } from "@trpc/server"; import { and, desc, eq, inArray, notExists } from "drizzle-orm"; import { z } from "zod"; -import { SqliteError } from "@lifetracker/db"; +import { DatabaseError, ErrorCodes } from "@lifetracker/db"; import { colors, metrics } from "@lifetracker/db/schema"; import { zMetricSchema, zMeasurementSchema } from "@lifetracker/shared/types/metrics"; import type { Context } from "../index"; @@ -40,8 +40,8 @@ export const metricsAppRouter = router({ .returning(); return result[0]; } catch (e) { - if (e instanceof SqliteError) { - if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { + if (e instanceof DatabaseError) { + if (e.code == ErrorCodes.UNIQUE_VIOLATION) { throw new TRPCError({ code: "BAD_REQUEST", message: "This metric already exists", diff --git a/packages/trpc/routers/users.ts b/packages/trpc/routers/users.ts index 1a963cd..27222d9 100644 --- a/packages/trpc/routers/users.ts +++ b/packages/trpc/routers/users.ts @@ -3,7 +3,7 @@ import { and, count, eq } from "drizzle-orm"; import invariant from "tiny-invariant"; import { z } from "zod"; -import { SqliteError } from "@lifetracker/db"; +import { DatabaseError, ErrorCodes } from "@lifetracker/db"; import { users } from "@lifetracker/db/schema"; import serverConfig from "@lifetracker/shared/config"; import { zSignUpSchema } from "@lifetracker/shared/types/users"; @@ -49,8 +49,8 @@ export async function createUser( }); return result[0]; } catch (e) { - if (e instanceof SqliteError) { - if (e.code == "SQLITE_CONSTRAINT_UNIQUE") { + if (e instanceof DatabaseError) { + if (e.code == ErrorCodes.UNIQUE_VIOLATION) { throw new TRPCError({ code: "BAD_REQUEST", message: "Email is already taken", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7601b9..26ae817 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: prettier: specifier: ^3.3.3 version: 3.3.3 + tsx: + specifier: ^4.19.2 + version: 4.19.2 turbo: specifier: ^2.2.3 version: 2.2.3 @@ -318,7 +321,7 @@ importers: version: 1.11.13 drizzle-orm: specifier: ^0.33.0 - version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7) + version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/pg@8.11.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(pg@8.13.1)(react@18.3.1)(sqlite3@5.1.7) fastest-levenshtein: specifier: ^1.0.16 version: 1.0.16 @@ -327,19 +330,22 @@ importers: version: 3.5.2 lucide-react: specifier: latest - version: 0.473.0(react@18.3.1) + version: 0.474.0(react@18.3.1) next: specifier: latest - version: 15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: ^4.24.5 - version: 4.24.10(next@15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 4.24.10(next@15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-pwa: specifier: ^5.6.0 - version: 5.6.0(@babel/core@7.26.0)(@types/babel__core@7.20.5)(next@15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.95.0) + version: 5.6.0(@babel/core@7.26.0)(@types/babel__core@7.20.5)(next@15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.95.0) next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + pg-dump-restore: + specifier: ^1.0.12 + version: 1.0.12 prettier: specifier: ^3.2.5 version: 3.3.3 @@ -467,18 +473,15 @@ importers: '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 - better-sqlite3: - specifier: ^11.3.0 - version: 11.5.0 dotenv: specifier: ^16.4.1 version: 16.4.5 drizzle-orm: specifier: ^0.33.0 - version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7) - expo-sqlite: - specifier: ^14.0.6 - version: 14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)) + version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/pg@8.11.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(pg@8.13.1)(react@18.3.1)(sqlite3@5.1.7) + pg: + specifier: ^8.11.3 + version: 8.13.1 tsx: specifier: ^4.7.1 version: 4.19.1 @@ -492,12 +495,18 @@ importers: '@tsconfig/node21': specifier: ^21.0.1 version: 21.0.3 - '@types/better-sqlite3': - specifier: ^7.6.9 - version: 7.6.11 + '@types/pg': + specifier: ^8.11.0 + version: 8.11.11 + better-sqlite3: + specifier: ^11.3.0 + version: 11.5.0 drizzle-kit: specifier: ^0.24.2 version: 0.24.2 + pg-dump-restore: + specifier: ^1.0.12 + version: 1.0.12 sqlite3: specifier: ^5.1.7 version: 5.1.7 @@ -675,7 +684,7 @@ importers: version: 4.1.0 drizzle-orm: specifier: ^0.33.0 - version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7) + version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/pg@8.11.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(pg@8.13.1)(react@18.3.1)(sqlite3@5.1.7) spacetime: specifier: ^7.6.2 version: 7.6.2 @@ -3195,56 +3204,56 @@ packages: '@microsoft/tsdoc@0.14.2': resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} - '@next/env@15.1.5': - resolution: {integrity: sha512-jg8ygVq99W3/XXb9Y6UQsritwhjc+qeiO7QrGZRYOfviyr/HcdnhdBQu4gbp2rBIh2ZyBYTBMWbPw3JSCb0GHw==} + '@next/env@15.1.6': + resolution: {integrity: sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==} '@next/eslint-plugin-next@14.2.6': resolution: {integrity: sha512-d3+p4AjIYmhqzYHhhmkRYYN6ZU35TwZAKX08xKRfnHkz72KhWL2kxMFsDptpZs5e8bBGdepn7vn1+9DaF8iX+A==} - '@next/swc-darwin-arm64@15.1.5': - resolution: {integrity: sha512-5ttHGE75Nw9/l5S8zR2xEwR8OHEqcpPym3idIMAZ2yo+Edk0W/Vf46jGqPOZDk+m/SJ+vYZDSuztzhVha8rcdA==} + '@next/swc-darwin-arm64@15.1.6': + resolution: {integrity: sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.1.5': - resolution: {integrity: sha512-8YnZn7vDURUUTInfOcU5l0UWplZGBqUlzvqKKUFceM11SzfNEz7E28E1Arn4/FsOf90b1Nopboy7i7ufc4jXag==} + '@next/swc-darwin-x64@15.1.6': + resolution: {integrity: sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.1.5': - resolution: {integrity: sha512-rDJC4ctlYbK27tCyFUhgIv8o7miHNlpCjb2XXfTLQszwAUOSbcMN9q2y3urSrrRCyGVOd9ZR9a4S45dRh6JF3A==} + '@next/swc-linux-arm64-gnu@15.1.6': + resolution: {integrity: sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.1.5': - resolution: {integrity: sha512-FG5RApf4Gu+J+pHUQxXPM81oORZrKBYKUaBTylEIQ6Lz17hKVDsLbSXInfXM0giclvXbyiLXjTv42sQMATmZ0A==} + '@next/swc-linux-arm64-musl@15.1.6': + resolution: {integrity: sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.1.5': - resolution: {integrity: sha512-NX2Ar3BCquAOYpnoYNcKz14eH03XuF7SmSlPzTSSU4PJe7+gelAjxo3Y7F2m8+hLT8ZkkqElawBp7SWBdzwqQw==} + '@next/swc-linux-x64-gnu@15.1.6': + resolution: {integrity: sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.1.5': - resolution: {integrity: sha512-EQgqMiNu3mrV5eQHOIgeuh6GB5UU57tu17iFnLfBEhYfiOfyK+vleYKh2dkRVkV6ayx3eSqbIYgE7J7na4hhcA==} + '@next/swc-linux-x64-musl@15.1.6': + resolution: {integrity: sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.1.5': - resolution: {integrity: sha512-HPULzqR/VqryQZbZME8HJE3jNFmTGcp+uRMHabFbQl63TtDPm+oCXAz3q8XyGv2AoihwNApVlur9Up7rXWRcjg==} + '@next/swc-win32-arm64-msvc@15.1.6': + resolution: {integrity: sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.1.5': - resolution: {integrity: sha512-n74fUb/Ka1dZSVYfjwQ+nSJ+ifUff7jGurFcTuJNKZmI62FFOxQXUYit/uZXPTj2cirm1rvGWHG2GhbSol5Ikw==} + '@next/swc-win32-x64-msvc@15.1.6': + resolution: {integrity: sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -4401,6 +4410,9 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/pg@8.11.11': + resolution: {integrity: sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==} + '@types/prismjs@1.26.4': resolution: {integrity: sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==} @@ -7324,9 +7336,6 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} @@ -8570,6 +8579,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} @@ -8654,8 +8664,8 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lucide-react@0.473.0: - resolution: {integrity: sha512-KW6u5AKeIjkvrxXZ6WuCu9zHE/gEYSXCay+Gre2ZoInD0Je/e3RBtP4OHpJVJ40nDklSvjVKjgH7VU8/e2dzRw==} + lucide-react@0.474.0: + resolution: {integrity: sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -9207,8 +9217,8 @@ packages: react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - next@15.1.5: - resolution: {integrity: sha512-Cf/TEegnt01hn3Hoywh6N8fvkhbOuChO4wFje24+a86wKOubgVaWkDqxGVgoWlz2Hp9luMJ9zw3epftujdnUOg==} + next@15.1.6: + resolution: {integrity: sha512-Hch4wzbaX0vKQtalpXvUiw5sYivBy4cm5rzUKrBnUB/y436LGrvOUqYvlSeNVCWFO/770gDlltR9gqZH62ct4Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -9680,6 +9690,51 @@ packages: periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + + pg-dump-restore@1.0.12: + resolution: {integrity: sha512-4ubF4amu0B/LjdVvq7M32PFb8labXZ61PnG1PMZaZuwGXGHl1CRoVWSNIjpA1UF2FwBovUJvJElwMIV9bxgk3Q==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + + pg@8.13.1: + resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -10021,6 +10076,41 @@ packages: resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + pouchdb-collections@1.0.1: resolution: {integrity: sha512-31db6JRg4+4D5Yzc2nqsRqsA2oOkZS8DpFav3jf/qVNBxusKa2ClkEIZ2bJNpaDbMfWtnuSq59p6Bn+CipPMdg==} @@ -11189,6 +11279,10 @@ packages: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} engines: {node: '>=6.0.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} @@ -11707,6 +11801,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -12754,6 +12853,7 @@ snapshots: '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 + optional: true '@babel/code-frame@7.22.13': dependencies: @@ -12827,6 +12927,7 @@ snapshots: lodash: 4.17.21 source-map: 0.5.7 trim-right: 1.0.1 + optional: true '@babel/generator@7.23.3': dependencies: @@ -12969,6 +13070,7 @@ snapshots: '@babel/helper-environment-visitor@7.24.7': dependencies: '@babel/types': 7.26.0 + optional: true '@babel/helper-function-name@7.23.0': dependencies: @@ -13210,6 +13312,7 @@ snapshots: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.1.1 + optional: true '@babel/parser@7.23.3': dependencies: @@ -13298,6 +13401,7 @@ snapshots: '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) transitivePeerDependencies: - supports-color + optional: true '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': dependencies: @@ -13315,6 +13419,7 @@ snapshots: '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) transitivePeerDependencies: - supports-color + optional: true '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': dependencies: @@ -13326,6 +13431,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + optional: true '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': dependencies: @@ -13338,6 +13444,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + optional: true '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.26.0)': dependencies: @@ -13347,12 +13454,14 @@ snapshots: '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + optional: true '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + optional: true '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.26.0)': dependencies: @@ -13410,6 +13519,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.3)': dependencies: @@ -13861,6 +13971,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': dependencies: @@ -15633,7 +15744,7 @@ snapshots: '@esbuild-kit/esm-loader@2.6.5': dependencies: '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.7.2 + get-tsconfig: 4.8.1 '@esbuild/aix-ppc64@0.19.12': optional: true @@ -15937,6 +16048,7 @@ snapshots: '@expo/bunyan@4.0.1': dependencies: uuid: 8.3.2 + optional: true '@expo/cli@0.18.30(encoding@0.1.13)(expo-modules-autolinking@1.11.3)': dependencies: @@ -16023,11 +16135,13 @@ snapshots: - expo-modules-autolinking - supports-color - utf-8-validate + optional: true '@expo/code-signing-certificates@0.0.5': dependencies: node-forge: 1.3.1 nullthrows: 1.1.1 + optional: true '@expo/config-plugins@8.0.10': dependencies: @@ -16048,8 +16162,10 @@ snapshots: xml2js: 0.6.0 transitivePeerDependencies: - supports-color + optional: true - '@expo/config-types@51.0.3': {} + '@expo/config-types@51.0.3': + optional: true '@expo/config@9.0.4': dependencies: @@ -16066,6 +16182,7 @@ snapshots: sucrase: 3.34.0 transitivePeerDependencies: - supports-color + optional: true '@expo/devcert@1.1.4': dependencies: @@ -16083,6 +16200,7 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@expo/env@0.3.0': dependencies: @@ -16093,6 +16211,7 @@ snapshots: getenv: 1.0.0 transitivePeerDependencies: - supports-color + optional: true '@expo/image-utils@0.5.1(encoding@0.1.13)': dependencies: @@ -16108,12 +16227,14 @@ snapshots: tempy: 0.3.0 transitivePeerDependencies: - encoding + optional: true '@expo/json-file@8.3.3': dependencies: '@babel/code-frame': 7.10.4 json5: 2.2.3 write-file-atomic: 2.4.3 + optional: true '@expo/metro-config@0.18.11': dependencies: @@ -16137,11 +16258,13 @@ snapshots: resolve-from: 5.0.0 transitivePeerDependencies: - supports-color + optional: true '@expo/osascript@2.1.3': dependencies: '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 + optional: true '@expo/package-manager@1.5.2': dependencies: @@ -16157,12 +16280,14 @@ snapshots: ora: 3.4.0 split: 1.0.1 sudo-prompt: 9.1.1 + optional: true '@expo/plist@0.1.3': dependencies: '@xmldom/xmldom': 0.7.13 base64-js: 1.5.1 xmlbuilder: 14.0.0 + optional: true '@expo/prebuild-config@7.0.9(encoding@0.1.13)(expo-modules-autolinking@1.11.3)': dependencies: @@ -16181,6 +16306,7 @@ snapshots: transitivePeerDependencies: - encoding - supports-color + optional: true '@expo/rudder-sdk-node@1.1.1(encoding@0.1.13)': dependencies: @@ -16193,16 +16319,20 @@ snapshots: uuid: 8.3.2 transitivePeerDependencies: - encoding + optional: true - '@expo/sdk-runtime-versions@1.0.0': {} + '@expo/sdk-runtime-versions@1.0.0': + optional: true '@expo/spawn-async@1.7.2': dependencies: cross-spawn: 7.0.5 + optional: true '@expo/vector-icons@14.0.4': dependencies: prop-types: 15.8.1 + optional: true '@expo/websql@1.0.1': dependencies: @@ -16211,6 +16341,7 @@ snapshots: noop-fn: 1.0.0 pouchdb-collections: 1.0.1 tiny-queue: 0.2.1 + optional: true '@expo/xcpretty@4.3.1': dependencies: @@ -16218,6 +16349,7 @@ snapshots: chalk: 4.1.2 find-up: 5.0.0 js-yaml: 4.1.0 + optional: true '@floating-ui/core@1.6.8': dependencies: @@ -16250,6 +16382,7 @@ snapshots: '@graphql-typed-document-node/core@3.2.0(graphql@15.8.0)': dependencies: graphql: 15.8.0 + optional: true '@hapi/hoek@9.3.0': {} @@ -16429,6 +16562,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 1.1.2 '@types/yargs': 13.0.12 + optional: true '@jest/types@29.6.3': dependencies: @@ -16555,34 +16689,34 @@ snapshots: '@microsoft/tsdoc@0.14.2': {} - '@next/env@15.1.5': {} + '@next/env@15.1.6': {} '@next/eslint-plugin-next@14.2.6': dependencies: glob: 10.3.10 - '@next/swc-darwin-arm64@15.1.5': + '@next/swc-darwin-arm64@15.1.6': optional: true - '@next/swc-darwin-x64@15.1.5': + '@next/swc-darwin-x64@15.1.6': optional: true - '@next/swc-linux-arm64-gnu@15.1.5': + '@next/swc-linux-arm64-gnu@15.1.6': optional: true - '@next/swc-linux-arm64-musl@15.1.5': + '@next/swc-linux-arm64-musl@15.1.6': optional: true - '@next/swc-linux-x64-gnu@15.1.5': + '@next/swc-linux-x64-gnu@15.1.6': optional: true - '@next/swc-linux-x64-musl@15.1.5': + '@next/swc-linux-x64-musl@15.1.6': optional: true - '@next/swc-win32-arm64-msvc@15.1.5': + '@next/swc-win32-arm64-msvc@15.1.6': optional: true - '@next/swc-win32-x64-msvc@15.1.5': + '@next/swc-win32-x64-msvc@15.1.6': optional: true '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': @@ -16612,6 +16746,7 @@ snapshots: '@npmcli/fs@3.1.1': dependencies: semver: 7.6.3 + optional: true '@npmcli/move-file@1.1.2': dependencies: @@ -16630,7 +16765,7 @@ snapshots: '@pkgr/utils@2.4.2': dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 fast-glob: 3.3.2 is-glob: 4.0.3 open: 9.1.0 @@ -17116,6 +17251,7 @@ snapshots: transitivePeerDependencies: - '@babel/preset-env' - supports-color + optional: true '@react-native/babel-plugin-codegen@0.76.2(@babel/preset-env@7.25.7(@babel/core@7.26.0))': dependencies: @@ -17172,6 +17308,7 @@ snapshots: transitivePeerDependencies: - '@babel/preset-env' - supports-color + optional: true '@react-native/babel-preset@0.76.2(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))': dependencies: @@ -17236,6 +17373,7 @@ snapshots: nullthrows: 1.1.1 transitivePeerDependencies: - supports-color + optional: true '@react-native/codegen@0.76.2(@babel/preset-env@7.25.7(@babel/core@7.26.0))': dependencies: @@ -17272,7 +17410,8 @@ snapshots: - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.74.85': {} + '@react-native/debugger-frontend@0.74.85': + optional: true '@react-native/debugger-frontend@0.76.2': {} @@ -17296,6 +17435,7 @@ snapshots: - encoding - supports-color - utf-8-validate + optional: true '@react-native/dev-middleware@0.76.2': dependencies: @@ -17384,6 +17524,7 @@ snapshots: rimraf: 3.0.2 transitivePeerDependencies: - supports-color + optional: true '@rollup/plugin-babel@5.3.1(@babel/core@7.26.0)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: @@ -17488,6 +17629,7 @@ snapshots: dependencies: component-type: 1.2.2 join-component: 1.1.0 + optional: true '@sideway/address@4.1.5': dependencies: @@ -17790,6 +17932,7 @@ snapshots: '@types/better-sqlite3@7.6.11': dependencies: '@types/node': 20.11.24 + optional: true '@types/body-parser@1.19.5': dependencies: @@ -17941,6 +18084,7 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-lib-report': 3.0.3 + optional: true '@types/istanbul-reports@3.0.4': dependencies: @@ -17973,6 +18117,7 @@ snapshots: '@types/node@18.19.64': dependencies: undici-types: 5.26.5 + optional: true '@types/node@20.11.24': dependencies: @@ -17982,6 +18127,12 @@ snapshots: '@types/parse-json@4.0.2': {} + '@types/pg@8.11.11': + dependencies: + '@types/node': 20.11.24 + pg-protocol: 1.7.0 + pg-types: 4.0.2 + '@types/prismjs@1.26.4': {} '@types/prop-types@15.7.5': {} @@ -18091,6 +18242,7 @@ snapshots: '@types/yargs@13.0.12': dependencies: '@types/yargs-parser': 21.0.3 + optional: true '@types/yargs@17.0.33': dependencies: @@ -18316,12 +18468,14 @@ snapshots: '@graphql-typed-document-node/core': 3.2.0(graphql@15.8.0) graphql: 15.8.0 wonka: 4.0.15 + optional: true '@urql/exchange-retry@0.3.0(graphql@15.8.0)': dependencies: '@urql/core': 2.3.6(graphql@15.8.0) graphql: 15.8.0 wonka: 4.0.15 + optional: true '@vercel/style-guide@5.2.0(@next/eslint-plugin-next@14.2.6)(eslint@8.57.0)(prettier@3.3.3)(typescript@5.3.3)': dependencies: @@ -18641,9 +18795,11 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@xmldom/xmldom@0.7.13': {} + '@xmldom/xmldom@0.7.13': + optional: true - '@xmldom/xmldom@0.8.10': {} + '@xmldom/xmldom@0.8.10': + optional: true '@xtuc/ieee754@1.2.0': {} @@ -18686,6 +18842,7 @@ snapshots: debug: 4.3.7 transitivePeerDependencies: - supports-color + optional: true agent-base@7.1.0: dependencies: @@ -18765,7 +18922,8 @@ snapshots: ansi-html-community@0.0.8: {} - ansi-regex@4.1.1: {} + ansi-regex@4.1.1: + optional: true ansi-regex@5.0.1: {} @@ -18790,7 +18948,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - application-config-path@0.1.1: {} + application-config-path@0.1.1: + optional: true aproba@2.0.0: optional: true @@ -18811,7 +18970,8 @@ snapshots: argparse@2.0.1: {} - argsarray@0.0.1: {} + argsarray@0.0.1: + optional: true aria-hidden@1.2.4: dependencies: @@ -18830,6 +18990,7 @@ snapshots: dependencies: call-bind: 1.0.7 is-array-buffer: 3.0.4 + optional: true array-flatten@1.1.1: {} @@ -18901,6 +19062,7 @@ snapshots: get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 + optional: true asap@2.0.6: {} @@ -18930,7 +19092,8 @@ snapshots: dependencies: has-symbols: 1.0.3 - asynckit@0.4.0: {} + asynckit@0.4.0: + optional: true at-least-node@1.0.0: {} @@ -18961,6 +19124,7 @@ snapshots: available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 + optional: true axe-core@4.7.0: {} @@ -19085,8 +19249,10 @@ snapshots: pretty-format: 24.9.0 zod: 3.23.8 zod-validation-error: 2.1.0(zod@3.23.8) + optional: true - babel-plugin-react-native-web@0.19.13: {} + babel-plugin-react-native-web@0.19.13: + optional: true babel-plugin-syntax-hermes-parser@0.23.1: dependencies: @@ -19137,6 +19303,7 @@ snapshots: - '@babel/core' - '@babel/preset-env' - supports-color + optional: true babel-preset-jest@29.6.3(@babel/core@7.26.0): dependencies: @@ -19161,6 +19328,7 @@ snapshots: better-opn@3.0.2: dependencies: open: 8.4.2 + optional: true better-sqlite3@11.5.0: dependencies: @@ -19169,7 +19337,8 @@ snapshots: big-integer@1.6.51: {} - big-integer@1.6.52: {} + big-integer@1.6.52: + optional: true big.js@5.2.2: {} @@ -19234,10 +19403,12 @@ snapshots: bplist-creator@0.0.7: dependencies: stream-buffers: 2.2.0 + optional: true bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 + optional: true bplist-parser@0.2.0: dependencies: @@ -19246,10 +19417,12 @@ snapshots: bplist-parser@0.3.1: dependencies: big-integer: 1.6.52 + optional: true bplist-parser@0.3.2: dependencies: big-integer: 1.6.52 + optional: true brace-expansion@1.1.11: dependencies: @@ -19293,14 +19466,17 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-alloc-unsafe@1.1.0: {} + buffer-alloc-unsafe@1.1.0: + optional: true buffer-alloc@1.2.0: dependencies: buffer-alloc-unsafe: 1.1.0 buffer-fill: 1.0.0 + optional: true - buffer-fill@1.0.0: {} + buffer-fill@1.0.0: + optional: true buffer-from@1.1.2: {} @@ -19311,7 +19487,8 @@ snapshots: builtin-modules@3.3.0: {} - builtins@1.0.3: {} + builtins@1.0.3: + optional: true builtins@5.0.1: dependencies: @@ -19369,6 +19546,7 @@ snapshots: ssri: 10.0.6 tar: 6.2.1 unique-filename: 3.0.0 + optional: true cacheable-lookup@7.0.0: {} @@ -19516,7 +19694,8 @@ snapshots: chardet@0.7.0: {} - charenc@0.0.2: {} + charenc@0.0.2: + optional: true check-error@1.0.3: dependencies: @@ -19625,6 +19804,7 @@ snapshots: cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 + optional: true cli-cursor@3.1.0: dependencies: @@ -19632,7 +19812,8 @@ snapshots: cli-spinners@2.9.0: {} - cli-spinners@2.9.2: {} + cli-spinners@2.9.2: + optional: true cli-table3@0.6.5: dependencies: @@ -19658,7 +19839,8 @@ snapshots: clone@1.0.4: {} - clone@2.1.2: {} + clone@2.1.2: + optional: true clsx@1.2.1: {} @@ -19714,12 +19896,14 @@ snapshots: combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 + optional: true comma-separated-tokens@1.0.8: {} comma-separated-tokens@2.0.3: {} - command-exists@1.2.9: {} + command-exists@1.2.9: + optional: true commander@10.0.1: {} @@ -19749,7 +19933,8 @@ snapshots: commondir@1.0.1: {} - component-type@1.2.2: {} + component-type@1.2.2: + optional: true compressible@2.0.18: dependencies: @@ -19907,6 +20092,7 @@ snapshots: semver: 5.7.2 shebang-command: 1.2.0 which: 1.3.1 + optional: true cross-spawn@7.0.3: dependencies: @@ -19920,9 +20106,11 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypt@0.0.2: {} + crypt@0.0.2: + optional: true - crypto-random-string@1.0.0: {} + crypto-random-string@1.0.0: + optional: true crypto-random-string@2.0.0: {} @@ -20148,7 +20336,8 @@ snapshots: dependencies: d3-array: 3.2.1 - dag-map@1.0.2: {} + dag-map@1.0.2: + optional: true damerau-levenshtein@1.0.8: {} @@ -20159,18 +20348,21 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + optional: true data-view-byte-length@1.0.1: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + optional: true data-view-byte-offset@1.0.0: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + optional: true date-fns@2.30.0: dependencies: @@ -20234,6 +20426,7 @@ snapshots: dependencies: execa: 1.0.0 ip-regex: 2.1.0 + optional: true default-gateway@6.0.3: dependencies: @@ -20309,7 +20502,8 @@ snapshots: dependencies: robust-predicates: 3.0.2 - delayed-stream@1.0.0: {} + delayed-stream@1.0.0: + optional: true delegates@1.0.0: optional: true @@ -20446,6 +20640,7 @@ snapshots: dotenv-expand@11.0.6: dependencies: dotenv: 16.4.5 + optional: true dotenv@16.0.3: {} @@ -20460,12 +20655,14 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7): + drizzle-orm@0.33.0(@types/better-sqlite3@7.6.11)(@types/pg@8.11.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(pg@8.13.1)(react@18.3.1)(sqlite3@5.1.7): optionalDependencies: '@types/better-sqlite3': 7.6.11 + '@types/pg': 8.11.11 '@types/react': 18.2.61 better-sqlite3: 11.5.0 expo-sqlite: 14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)) + pg: 8.13.1 react: 18.3.1 sqlite3: 5.1.7 @@ -20531,12 +20728,14 @@ snapshots: entities@4.5.0: {} - env-editor@0.4.2: {} + env-editor@0.4.2: + optional: true env-paths@2.2.1: optional: true - eol@0.9.1: {} + eol@0.9.1: + optional: true err-code@2.0.3: optional: true @@ -20639,6 +20838,7 @@ snapshots: typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 + optional: true es-define-property@1.0.0: dependencies: @@ -20668,6 +20868,7 @@ snapshots: es-object-atoms@1.0.0: dependencies: es-errors: 1.3.0 + optional: true es-set-tostringtag@2.0.2: dependencies: @@ -20680,6 +20881,7 @@ snapshots: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 + optional: true es-shim-unscopables@1.0.2: dependencies: @@ -20834,7 +21036,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.33.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) @@ -20873,7 +21075,7 @@ snapshots: eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.0)(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0) fast-glob: 3.3.1 - get-tsconfig: 4.7.2 + get-tsconfig: 4.8.1 is-core-module: 2.13.1 is-glob: 4.0.3 transitivePeerDependencies: @@ -20888,9 +21090,9 @@ snapshots: enhanced-resolve: 5.15.0 eslint: 8.57.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) fast-glob: 3.3.1 - get-tsconfig: 4.7.2 + get-tsconfig: 4.8.1 is-core-module: 2.13.1 is-glob: 4.0.3 transitivePeerDependencies: @@ -20927,7 +21129,7 @@ snapshots: eslint: 8.57.0 ignore: 5.3.1 - eslint-plugin-import@2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + eslint-plugin-import@2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 @@ -21208,7 +21410,8 @@ snapshots: events@3.3.0: {} - exec-async@2.2.0: {} + exec-async@2.2.0: + optional: true execa@1.0.0: dependencies: @@ -21219,10 +21422,11 @@ snapshots: p-finally: 1.0.0 signal-exit: 3.0.7 strip-eof: 1.0.0 + optional: true execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -21268,6 +21472,7 @@ snapshots: md5-file: 3.2.3 transitivePeerDependencies: - supports-color + optional: true expo-constants@16.0.2(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)): dependencies: @@ -21276,19 +21481,23 @@ snapshots: expo: 51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13) transitivePeerDependencies: - supports-color + optional: true expo-file-system@17.0.1(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)): dependencies: expo: 51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13) + optional: true expo-font@12.0.10(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)): dependencies: expo: 51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13) fontfaceobserver: 2.3.0 + optional: true expo-keep-awake@13.0.2(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)): dependencies: expo: 51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13) + optional: true expo-modules-autolinking@1.11.3: dependencies: @@ -21299,15 +21508,18 @@ snapshots: fs-extra: 9.1.0 require-from-string: 2.0.2 resolve-from: 5.0.0 + optional: true expo-modules-core@1.12.25: dependencies: invariant: 2.2.4 + optional: true expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)): dependencies: '@expo/websql': 1.0.1 expo: 51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13) + optional: true expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13): dependencies: @@ -21333,6 +21545,7 @@ snapshots: - encoding - supports-color - utf-8-validate + optional: true exponential-backoff@3.1.1: {} @@ -21441,6 +21654,7 @@ snapshots: fbjs: 3.0.5(encoding@0.1.13) transitivePeerDependencies: - encoding + optional: true fbjs-css-vars@1.0.2: {} @@ -21462,7 +21676,8 @@ snapshots: dependencies: xml-js: 1.6.11 - fetch-retry@4.1.1: {} + fetch-retry@4.1.1: + optional: true figures@3.2.0: dependencies: @@ -21563,6 +21778,7 @@ snapshots: find-yarn-workspace-root@2.0.0: dependencies: micromatch: 4.0.8 + optional: true flat-cache@3.0.4: dependencies: @@ -21581,7 +21797,8 @@ snapshots: follow-redirects@1.15.9: {} - fontfaceobserver@2.3.0: {} + fontfaceobserver@2.3.0: + optional: true for-each@0.3.3: dependencies: @@ -21589,7 +21806,7 @@ snapshots: foreground-child@3.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 signal-exit: 4.1.0 foreground-child@3.3.0: @@ -21624,6 +21841,7 @@ snapshots: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 + optional: true format@0.2.2: {} @@ -21637,7 +21855,8 @@ snapshots: fraction.js@4.3.7: {} - freeport-async@2.0.0: {} + freeport-async@2.0.0: + optional: true fresh@0.5.2: {} @@ -21667,6 +21886,7 @@ snapshots: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 1.0.0 + optional: true fs-extra@9.1.0: dependencies: @@ -21682,6 +21902,7 @@ snapshots: fs-minipass@3.0.3: dependencies: minipass: 7.1.2 + optional: true fs-monkey@1.0.6: {} @@ -21740,13 +21961,15 @@ snapshots: get-package-type@0.1.0: {} - get-port@3.2.0: {} + get-port@3.2.0: + optional: true get-stdin@9.0.0: {} get-stream@4.1.0: dependencies: pump: 3.0.2 + optional: true get-stream@6.0.1: {} @@ -21762,10 +21985,7 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - - get-tsconfig@4.7.2: - dependencies: - resolve-pkg-maps: 1.0.0 + optional: true get-tsconfig@4.8.1: dependencies: @@ -21784,7 +22004,8 @@ snapshots: dependencies: isobject: 3.0.1 - getenv@1.0.0: {} + getenv@1.0.0: + optional: true git-hooks-list@3.1.0: {} @@ -21827,6 +22048,7 @@ snapshots: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 + optional: true glob@7.2.3: dependencies: @@ -21865,6 +22087,7 @@ snapshots: dependencies: define-properties: 1.2.1 gopd: 1.0.1 + optional: true globby@10.0.2: dependencies: @@ -21937,8 +22160,10 @@ snapshots: dependencies: graphql: 15.8.0 tslib: 2.8.1 + optional: true - graphql@15.8.0: {} + graphql@15.8.0: + optional: true gray-matter@4.0.3: dependencies: @@ -21980,7 +22205,8 @@ snapshots: has-proto@1.0.1: {} - has-proto@1.0.3: {} + has-proto@1.0.3: + optional: true has-symbols@1.0.3: {} @@ -21991,6 +22217,7 @@ snapshots: has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 + optional: true has-unicode@2.0.1: optional: true @@ -22004,6 +22231,7 @@ snapshots: hasown@2.0.2: dependencies: function-bind: 1.1.2 + optional: true hast-util-from-parse5@8.0.1: dependencies: @@ -22116,7 +22344,8 @@ snapshots: no-case: 2.3.2 upper-case: 1.1.3 - hermes-estree@0.19.1: {} + hermes-estree@0.19.1: + optional: true hermes-estree@0.23.1: {} @@ -22127,6 +22356,7 @@ snapshots: hermes-parser@0.19.1: dependencies: hermes-estree: 0.19.1 + optional: true hermes-parser@0.23.1: dependencies: @@ -22164,6 +22394,7 @@ snapshots: hosted-git-info@3.0.8: dependencies: lru-cache: 6.0.0 + optional: true hpack.js@2.1.6: dependencies: @@ -22301,6 +22532,7 @@ snapshots: debug: 4.3.7 transitivePeerDependencies: - supports-color + optional: true https-proxy-agent@7.0.1: dependencies: @@ -22344,7 +22576,8 @@ snapshots: dependencies: queue: 6.0.2 - immediate@3.3.0: {} + immediate@3.3.0: + optional: true immer@9.0.21: {} @@ -22429,6 +22662,7 @@ snapshots: dependencies: default-gateway: 4.2.0 ipaddr.js: 1.9.1 + optional: true internal-slot@1.0.6: dependencies: @@ -22441,6 +22675,7 @@ snapshots: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 + optional: true internmap@2.0.3: {} @@ -22450,7 +22685,8 @@ snapshots: dependencies: loose-envify: 1.4.0 - ip-regex@2.1.0: {} + ip-regex@2.1.0: + optional: true ip@1.1.8: {} @@ -22484,6 +22720,7 @@ snapshots: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 + optional: true is-arrayish@0.2.1: {} @@ -22506,7 +22743,8 @@ snapshots: call-bind: 1.0.5 has-tostringtag: 1.0.0 - is-buffer@1.1.6: {} + is-buffer@1.1.6: + optional: true is-builtin-module@3.2.1: dependencies: @@ -22525,6 +22763,7 @@ snapshots: is-data-view@1.0.1: dependencies: is-typed-array: 1.1.13 + optional: true is-date-object@1.0.5: dependencies: @@ -22542,7 +22781,8 @@ snapshots: is-extendable@0.1.1: {} - is-extglob@1.0.0: {} + is-extglob@1.0.0: + optional: true is-extglob@2.1.1: {} @@ -22559,6 +22799,7 @@ snapshots: is-glob@2.0.1: dependencies: is-extglob: 1.0.0 + optional: true is-glob@4.0.3: dependencies: @@ -22582,6 +22823,7 @@ snapshots: is-invalid-path@0.1.0: dependencies: is-glob: 2.0.1 + optional: true is-lambda@1.0.1: optional: true @@ -22596,7 +22838,8 @@ snapshots: is-negative-zero@2.0.2: {} - is-negative-zero@2.0.3: {} + is-negative-zero@2.0.3: + optional: true is-npm@6.0.0: {} @@ -22654,8 +22897,10 @@ snapshots: is-shared-array-buffer@1.0.3: dependencies: call-bind: 1.0.7 + optional: true - is-stream@1.1.0: {} + is-stream@1.1.0: + optional: true is-stream@2.0.1: {} @@ -22676,6 +22921,7 @@ snapshots: is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 + optional: true is-typedarray@1.0.0: {} @@ -22688,6 +22934,7 @@ snapshots: is-valid-path@0.1.1: dependencies: is-invalid-path: 0.1.0 + optional: true is-weakmap@2.0.1: {} @@ -22843,7 +23090,8 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jimp-compact@0.16.1: {} + jimp-compact@0.16.1: + optional: true jiti@1.21.6: {} @@ -22857,7 +23105,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - join-component@1.1.0: {} + join-component@1.1.0: + optional: true jose@4.15.9: {} @@ -22927,6 +23176,7 @@ snapshots: memory-cache: 0.2.0 traverse: 0.6.10 valid-url: 1.0.9 + optional: true json-schema-traverse@0.4.1: {} @@ -23066,6 +23316,7 @@ snapshots: lightningcss-linux-x64-gnu: 1.19.0 lightningcss-linux-x64-musl: 1.19.0 lightningcss-win32-x64-msvc: 1.19.0 + optional: true lightningcss@1.28.1: dependencies: @@ -23145,6 +23396,7 @@ snapshots: log-symbols@2.2.0: dependencies: chalk: 2.4.2 + optional: true log-symbols@3.0.0: dependencies: @@ -23205,7 +23457,7 @@ snapshots: lru-cache@7.18.3: {} - lucide-react@0.473.0(react@18.3.1): + lucide-react@0.474.0(react@18.3.1): dependencies: react: 18.3.1 @@ -23266,20 +23518,24 @@ snapshots: md5-file@3.2.3: dependencies: buffer-alloc: 1.2.0 + optional: true md5@2.2.1: dependencies: charenc: 0.0.2 crypt: 0.0.2 is-buffer: 1.1.6 + optional: true md5@2.3.0: dependencies: charenc: 0.0.2 crypt: 0.0.2 is-buffer: 1.1.6 + optional: true - md5hex@1.0.0: {} + md5hex@1.0.0: + optional: true mdast-util-directive@3.0.0: dependencies: @@ -23486,7 +23742,8 @@ snapshots: memoize-one@6.0.0: {} - memory-cache@0.2.0: {} + memory-cache@0.2.0: + optional: true merge-descriptors@1.0.3: {} @@ -23998,7 +24255,8 @@ snapshots: mime@1.6.0: {} - mimic-fn@1.2.0: {} + mimic-fn@1.2.0: + optional: true mimic-fn@2.1.0: {} @@ -24044,6 +24302,7 @@ snapshots: minipass-collect@2.0.1: dependencies: minipass: 7.1.2 + optional: true minipass-fetch@1.4.1: dependencies: @@ -24057,10 +24316,12 @@ snapshots: minipass-flush@1.0.5: dependencies: minipass: 3.3.6 + optional: true minipass-pipeline@1.2.4: dependencies: minipass: 3.3.6 + optional: true minipass-sized@1.0.3: dependencies: @@ -24142,17 +24403,18 @@ snapshots: neo-async@2.6.2: {} - nested-error-stacks@2.0.1: {} + nested-error-stacks@2.0.1: + optional: true netmask@2.0.2: {} - next-auth@4.24.10(next@15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-auth@4.24.10(next@15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.26.0 '@panva/hkdf': 1.2.1 cookie: 0.7.2 jose: 4.15.9 - next: 15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) oauth: 0.9.15 openid-client: 5.7.0 preact: 10.24.3 @@ -24161,12 +24423,12 @@ snapshots: react-dom: 18.3.1(react@18.3.1) uuid: 8.3.2 - next-pwa@5.6.0(@babel/core@7.26.0)(@types/babel__core@7.20.5)(next@15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.95.0): + next-pwa@5.6.0(@babel/core@7.26.0)(@types/babel__core@7.20.5)(next@15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.95.0): dependencies: babel-loader: 8.4.1(@babel/core@7.26.0)(webpack@5.95.0) clean-webpack-plugin: 4.0.0(webpack@5.95.0) globby: 11.1.0 - next: 15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) terser-webpack-plugin: 5.3.10(webpack@5.95.0) workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.95.0) workbox-window: 6.6.0 @@ -24184,9 +24446,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@15.1.5(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@15.1.6(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 15.1.5 + '@next/env': 15.1.6 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 @@ -24196,20 +24458,21 @@ snapshots: react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.1.5 - '@next/swc-darwin-x64': 15.1.5 - '@next/swc-linux-arm64-gnu': 15.1.5 - '@next/swc-linux-arm64-musl': 15.1.5 - '@next/swc-linux-x64-gnu': 15.1.5 - '@next/swc-linux-x64-musl': 15.1.5 - '@next/swc-win32-arm64-msvc': 15.1.5 - '@next/swc-win32-x64-msvc': 15.1.5 + '@next/swc-darwin-arm64': 15.1.6 + '@next/swc-darwin-x64': 15.1.6 + '@next/swc-linux-arm64-gnu': 15.1.6 + '@next/swc-linux-arm64-musl': 15.1.6 + '@next/swc-linux-x64-gnu': 15.1.6 + '@next/swc-linux-x64-musl': 15.1.6 + '@next/swc-win32-arm64-msvc': 15.1.6 + '@next/swc-win32-x64-msvc': 15.1.6 sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - nice-try@1.0.5: {} + nice-try@1.0.5: + optional: true no-case@2.3.2: dependencies: @@ -24284,7 +24547,8 @@ snapshots: node-releases@2.0.18: {} - noop-fn@1.0.0: {} + noop-fn@1.0.0: + optional: true nopt@5.0.0: dependencies: @@ -24310,10 +24574,12 @@ snapshots: osenv: 0.1.5 semver: 5.7.2 validate-npm-package-name: 3.0.0 + optional: true npm-run-path@2.0.2: dependencies: path-key: 2.0.1 + optional: true npm-run-path@4.0.1: dependencies: @@ -24355,7 +24621,8 @@ snapshots: object-inspect@1.13.1: {} - object-inspect@1.13.2: {} + object-inspect@1.13.2: + optional: true object-keys@1.1.1: {} @@ -24372,6 +24639,7 @@ snapshots: define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 + optional: true object.entries@1.1.7: dependencies: @@ -24428,6 +24696,7 @@ snapshots: onetime@2.0.1: dependencies: mimic-fn: 1.2.0 + optional: true onetime@5.1.2: dependencies: @@ -24481,6 +24750,7 @@ snapshots: log-symbols: 2.2.0 strip-ansi: 5.2.0 wcwidth: 1.0.1 + optional: true ora@4.1.1: dependencies: @@ -24505,7 +24775,8 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - os-homedir@1.0.2: {} + os-homedir@1.0.2: + optional: true os-tmpdir@1.0.2: {} @@ -24513,10 +24784,12 @@ snapshots: dependencies: os-homedir: 1.0.2 os-tmpdir: 1.0.2 + optional: true p-cancelable@3.0.0: {} - p-finally@1.0.0: {} + p-finally@1.0.0: + optional: true p-limit@2.3.0: dependencies: @@ -24645,6 +24918,7 @@ snapshots: parse-png@2.1.0: dependencies: pngjs: 3.4.0 + optional: true parse5-htmlparser2-tree-adapter@7.0.0: dependencies: @@ -24675,6 +24949,7 @@ snapshots: dependencies: ansi-escapes: 4.3.2 cross-spawn: 7.0.5 + optional: true path-case@2.1.1: dependencies: @@ -24690,7 +24965,8 @@ snapshots: path-is-inside@1.0.2: {} - path-key@2.0.1: {} + path-key@2.0.1: + optional: true path-key@3.1.1: {} @@ -24730,13 +25006,65 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.2 + pg-cloudflare@1.1.1: + optional: true + + pg-connection-string@2.7.0: {} + + pg-dump-restore@1.0.12: + dependencies: + execa: 5.1.1 + + pg-int8@1.0.1: {} + + pg-numeric@1.0.2: {} + + pg-pool@3.7.0(pg@8.13.1): + dependencies: + pg: 8.13.1 + + pg-protocol@1.7.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg-types@4.0.2: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + pg@8.13.1: + dependencies: + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.1) + pg-protocol: 1.7.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.0.0: {} picocolors@1.1.1: {} picomatch@2.3.1: {} - picomatch@3.0.1: {} + picomatch@3.0.1: + optional: true pify@2.3.0: {} @@ -24777,12 +25105,15 @@ snapshots: '@xmldom/xmldom': 0.8.10 base64-js: 1.5.1 xmlbuilder: 15.1.1 + optional: true pluralize@8.0.0: {} - pngjs@3.4.0: {} + pngjs@3.4.0: + optional: true - possible-typed-array-names@1.0.0: {} + possible-typed-array-names@1.0.0: + optional: true postcss-calc@9.0.1(postcss@8.4.31): dependencies: @@ -25183,7 +25514,30 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - pouchdb-collections@1.0.1: {} + postgres-array@2.0.0: {} + + postgres-array@3.0.2: {} + + postgres-bytea@1.0.0: {} + + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + + postgres-date@1.0.7: {} + + postgres-date@2.1.0: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + + pouchdb-collections@1.0.1: + optional: true preact-render-to-string@5.2.6(preact@10.24.3): dependencies: @@ -25241,6 +25595,7 @@ snapshots: ansi-regex: 4.1.1 ansi-styles: 3.2.1 react-is: 16.13.1 + optional: true pretty-format@29.7.0: dependencies: @@ -25264,7 +25619,8 @@ snapshots: process-nextick-args@2.0.1: {} - progress@2.0.3: {} + progress@2.0.3: + optional: true promise-inflight@1.0.1: optional: true @@ -25337,7 +25693,8 @@ snapshots: dependencies: escape-goat: 4.0.0 - qrcode-terminal@0.11.0: {} + qrcode-terminal@0.11.0: + optional: true qs@6.13.0: dependencies: @@ -25890,6 +26247,7 @@ snapshots: define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 + optional: true regexpu-core@6.1.1: dependencies: @@ -26008,7 +26366,8 @@ snapshots: mdast-util-to-markdown: 2.1.0 unified: 11.0.5 - remove-trailing-slash@0.1.1: {} + remove-trailing-slash@0.1.1: + optional: true renderkid@3.0.0: dependencies: @@ -26033,6 +26392,7 @@ snapshots: nested-error-stacks: 2.0.1 rc: 1.2.8 resolve: 1.7.1 + optional: true requires-port@1.0.0: {} @@ -26048,7 +26408,8 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve.exports@2.0.2: {} + resolve.exports@2.0.2: + optional: true resolve@1.19.0: dependencies: @@ -26064,6 +26425,7 @@ snapshots: resolve@1.7.1: dependencies: path-parse: 1.0.7 + optional: true resolve@2.0.0-next.5: dependencies: @@ -26079,6 +26441,7 @@ snapshots: dependencies: onetime: 2.0.1 signal-exit: 3.0.7 + optional: true restore-cursor@3.1.0: dependencies: @@ -26211,6 +26574,7 @@ snapshots: get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 + optional: true safe-buffer@5.1.2: {} @@ -26227,6 +26591,7 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 + optional: true safe-stable-stringify@2.5.0: {} @@ -26311,6 +26676,7 @@ snapshots: statuses: 2.0.1 transitivePeerDependencies: - supports-color + optional: true send@0.19.0: dependencies: @@ -26408,6 +26774,7 @@ snapshots: es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + optional: true set-value@4.1.0: dependencies: @@ -26455,12 +26822,14 @@ snapshots: shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 + optional: true shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - shebang-regex@1.0.0: {} + shebang-regex@1.0.0: + optional: true shebang-regex@3.0.0: {} @@ -26504,6 +26873,7 @@ snapshots: bplist-creator: 0.1.0 bplist-parser: 0.3.1 plist: 3.1.0 + optional: true simple-swizzle@0.2.2: dependencies: @@ -26538,7 +26908,8 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - slugify@1.6.6: {} + slugify@1.6.6: + optional: true smart-buffer@4.2.0: {} @@ -26655,9 +27026,12 @@ snapshots: transitivePeerDependencies: - supports-color + split2@4.2.0: {} + split@1.0.1: dependencies: through: 2.3.8 + optional: true sprintf-js@1.0.3: {} @@ -26678,6 +27052,7 @@ snapshots: ssri@10.0.6: dependencies: minipass: 7.1.2 + optional: true ssri@8.0.1: dependencies: @@ -26704,7 +27079,8 @@ snapshots: std-env@3.7.0: {} - stream-buffers@2.2.0: {} + stream-buffers@2.2.0: + optional: true streamsearch@1.1.0: {} @@ -26744,6 +27120,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 + optional: true string.prototype.trimend@1.0.7: dependencies: @@ -26756,6 +27133,7 @@ snapshots: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + optional: true string.prototype.trimstart@1.0.7: dependencies: @@ -26768,6 +27146,7 @@ snapshots: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + optional: true string_decoder@1.1.1: dependencies: @@ -26791,6 +27170,7 @@ snapshots: strip-ansi@5.2.0: dependencies: ansi-regex: 4.1.1 + optional: true strip-ansi@6.0.1: dependencies: @@ -26806,7 +27186,8 @@ snapshots: strip-comments@2.0.1: {} - strip-eof@1.0.0: {} + strip-eof@1.0.0: + optional: true strip-final-newline@2.0.0: {} @@ -26824,7 +27205,8 @@ snapshots: dependencies: js-tokens: 9.0.0 - structured-headers@0.4.1: {} + structured-headers@0.4.1: + optional: true style-to-object@0.4.4: dependencies: @@ -26866,6 +27248,7 @@ snapshots: mz: 2.7.0 pirates: 4.0.6 ts-interface-checker: 0.1.13 + optional: true sucrase@3.35.0: dependencies: @@ -26877,9 +27260,11 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - sudo-prompt@8.2.5: {} + sudo-prompt@8.2.5: + optional: true - sudo-prompt@9.1.1: {} + sudo-prompt@9.1.1: + optional: true superjson@2.2.1: dependencies: @@ -26901,6 +27286,7 @@ snapshots: dependencies: has-flag: 4.0.0 supports-color: 7.2.0 + optional: true supports-preserve-symlinks-flag@1.0.0: {} @@ -26997,7 +27383,8 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - temp-dir@1.0.0: {} + temp-dir@1.0.0: + optional: true temp-dir@2.0.0: {} @@ -27010,6 +27397,7 @@ snapshots: temp-dir: 1.0.0 type-fest: 0.3.1 unique-string: 1.0.0 + optional: true tempy@0.6.0: dependencies: @@ -27025,11 +27413,13 @@ snapshots: temp-dir: 2.0.0 type-fest: 0.16.0 unique-string: 2.0.0 + optional: true terminal-link@2.1.1: dependencies: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 + optional: true terser-webpack-plugin@5.3.10(webpack@5.95.0): dependencies: @@ -27080,7 +27470,8 @@ snapshots: tiny-invariant@1.3.3: {} - tiny-queue@0.2.1: {} + tiny-queue@0.2.1: + optional: true tiny-warning@1.0.3: {} @@ -27141,10 +27532,12 @@ snapshots: gopd: 1.0.1 typedarray.prototype.slice: 1.0.3 which-typed-array: 1.1.15 + optional: true trim-lines@3.0.1: {} - trim-right@1.0.1: {} + trim-right@1.0.1: + optional: true triple-beam@1.4.1: {} @@ -27222,6 +27615,13 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -27267,7 +27667,8 @@ snapshots: type-fest@0.21.3: {} - type-fest@0.3.1: {} + type-fest@0.3.1: + optional: true type-fest@0.6.0: {} @@ -27297,6 +27698,7 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 is-typed-array: 1.1.13 + optional: true typed-array-byte-length@1.0.0: dependencies: @@ -27312,6 +27714,7 @@ snapshots: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 + optional: true typed-array-byte-offset@1.0.0: dependencies: @@ -27329,6 +27732,7 @@ snapshots: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 + optional: true typed-array-length@1.0.4: dependencies: @@ -27344,6 +27748,7 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + optional: true typedarray-to-buffer@3.1.5: dependencies: @@ -27357,6 +27762,7 @@ snapshots: es-errors: 1.3.0 typed-array-buffer: 1.0.2 typed-array-byte-offset: 1.0.2 + optional: true typescript@5.3.3: {} @@ -27411,6 +27817,7 @@ snapshots: unique-filename@3.0.0: dependencies: unique-slug: 4.0.0 + optional: true unique-slug@2.0.2: dependencies: @@ -27420,10 +27827,12 @@ snapshots: unique-slug@4.0.0: dependencies: imurmurhash: 0.1.4 + optional: true unique-string@1.0.0: dependencies: crypto-random-string: 1.0.0 + optional: true unique-string@2.0.0: dependencies: @@ -27462,7 +27871,8 @@ snapshots: universalify@0.1.2: {} - universalify@1.0.0: {} + universalify@1.0.0: + optional: true universalify@2.0.0: {} @@ -27522,7 +27932,8 @@ snapshots: dependencies: punycode: 2.3.0 - url-join@4.0.0: {} + url-join@4.0.0: + optional: true url-loader@4.1.1(file-loader@6.2.0(webpack@5.95.0))(webpack@5.95.0): dependencies: @@ -27586,13 +27997,15 @@ snapshots: utils-merge@1.0.1: {} - uuid@7.0.3: {} + uuid@7.0.3: + optional: true uuid@8.3.2: {} v8-compile-cache-lib@3.0.1: {} - valid-url@1.0.9: {} + valid-url@1.0.9: + optional: true validate-npm-package-license@3.0.4: dependencies: @@ -27602,6 +28015,7 @@ snapshots: validate-npm-package-name@3.0.0: dependencies: builtins: 1.0.3 + optional: true validate-npm-package-name@5.0.0: dependencies: @@ -27788,7 +28202,8 @@ snapshots: webidl-conversions@4.0.2: {} - webidl-conversions@5.0.0: {} + webidl-conversions@5.0.0: + optional: true webpack-bundle-analyzer@4.10.2: dependencies: @@ -27929,6 +28344,7 @@ snapshots: buffer: 5.7.1 punycode: 2.3.1 webidl-conversions: 5.0.0 + optional: true whatwg-url@5.0.0: dependencies: @@ -27986,6 +28402,7 @@ snapshots: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 + optional: true which@1.3.1: dependencies: @@ -28031,7 +28448,8 @@ snapshots: triple-beam: 1.4.1 winston-transport: 4.9.0 - wonka@4.0.15: {} + wonka@4.0.15: + optional: true wordwrap@1.0.0: {} @@ -28210,6 +28628,7 @@ snapshots: dependencies: simple-plist: 1.3.1 uuid: 7.0.3 + optional: true xdg-basedir@5.1.0: {} @@ -28221,12 +28640,16 @@ snapshots: dependencies: sax: 1.4.1 xmlbuilder: 11.0.1 + optional: true - xmlbuilder@11.0.1: {} + xmlbuilder@11.0.1: + optional: true - xmlbuilder@14.0.0: {} + xmlbuilder@14.0.0: + optional: true - xmlbuilder@15.1.1: {} + xmlbuilder@15.1.1: + optional: true xtend@4.0.2: {} @@ -28261,6 +28684,7 @@ snapshots: zod-validation-error@2.1.0(zod@3.23.8): dependencies: zod: 3.23.8 + optional: true zod@3.23.8: {}