From f4d3fade9b6cd4e37c6d37cd27be0148c1dbc623 Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Tue, 10 Mar 2026 17:13:23 +0100 Subject: [PATCH] setup local dev env --- .env.example | 22 +- .gitignore | 2 +- .woodpecker.yml | 29 + Cargo.lock | 2794 ++++++++++++++++ Cargo.toml | 3 - README.md | 139 +- backend/Cargo.lock | 2842 +++++++++++++++++ backend/Cargo.toml | 23 +- backend/campaign-service/Cargo.toml | 18 + backend/campaign-service/Dockerfile | 14 + .../migrations/campaign/0001_init.sql | 15 + .../migrations/users/0001_init.sql | 15 + backend/campaign-service/src/main.rs | 118 + backend/common/Cargo.toml | 12 + backend/common/src/error.rs | 40 + backend/common/src/jwt.rs | 49 + backend/common/src/lib.rs | 5 + backend/content-service/Cargo.toml | 16 + backend/content-service/Dockerfile | 14 + .../migrations/content/0001_init.sql | 7 + backend/content-service/src/main.rs | 124 + backend/src/lib.rs | 1 - backend/src/main.rs | 43 - docker-compose.yml | 74 +- package.json | 8 +- pnpm-lock.yaml | 160 +- scripts/ci-local.sh | 15 + symbiote/src/lib/api.ts | 44 +- web/Dockerfile | 22 + web/build/404.html | 38 - web/build/_app/env.js | 1 - web/build/_app/immutable/chunks/Bzak7iHL.js | 1 - web/build/_app/immutable/chunks/C5YqYP7P.js | 1 - web/build/_app/immutable/chunks/CAYgxOZ1.js | 1 - web/build/_app/immutable/chunks/CGowzvwH.js | 1 - web/build/_app/immutable/chunks/CUCwB180.js | 1 - web/build/_app/immutable/chunks/DNqN6DmX.js | 1 - web/build/_app/immutable/chunks/Db9w--lA.js | 2 - web/build/_app/immutable/chunks/YzYuob9f.js | 1 - web/build/_app/immutable/chunks/eiK12uJk.js | 1 - web/build/_app/immutable/chunks/pTMRHjpX.js | 1 - .../_app/immutable/entry/app.H3SWXino.js | 2 - .../_app/immutable/entry/start.Pj34kLt-.js | 1 - web/build/_app/immutable/nodes/0.D7-FTC_1.js | 1 - web/build/_app/immutable/nodes/1.BZR9od8C.js | 1 - web/build/_app/immutable/nodes/2.Zg4cVoEY.js | 1 - web/build/_app/immutable/nodes/3.BjNotmmr.js | 1 - web/build/_app/immutable/nodes/4.D0WiVz9B.js | 1 - web/build/_app/immutable/nodes/5.B-zruxZU.js | 1 - web/build/_app/immutable/nodes/6.Cniq5yLG.js | 1 - web/build/_app/immutable/nodes/7.BjdHyPf8.js | 1 - web/build/_app/immutable/nodes/8.Chqc1uyl.js | 1 - web/build/_app/version.json | 1 - web/package.json | 5 +- web/src/lib/api.ts | 51 +- web/src/lib/server/proxy.ts | 79 + web/src/routes/+layout.svelte | 4 +- web/src/routes/api/auth/[...path]/+server.ts | 19 + .../routes/api/campaign/[...path]/+server.ts | 15 + .../routes/api/content/[...path]/+server.ts | 15 + web/svelte.config.js | 4 +- 61 files changed, 6695 insertions(+), 228 deletions(-) create mode 100644 .woodpecker.yml create mode 100644 Cargo.lock delete mode 100644 Cargo.toml create mode 100644 backend/Cargo.lock create mode 100644 backend/campaign-service/Cargo.toml create mode 100644 backend/campaign-service/Dockerfile create mode 100644 backend/campaign-service/migrations/campaign/0001_init.sql create mode 100644 backend/campaign-service/migrations/users/0001_init.sql create mode 100644 backend/campaign-service/src/main.rs create mode 100644 backend/common/Cargo.toml create mode 100644 backend/common/src/error.rs create mode 100644 backend/common/src/jwt.rs create mode 100644 backend/common/src/lib.rs create mode 100644 backend/content-service/Cargo.toml create mode 100644 backend/content-service/Dockerfile create mode 100644 backend/content-service/migrations/content/0001_init.sql create mode 100644 backend/content-service/src/main.rs delete mode 100644 backend/src/lib.rs delete mode 100644 backend/src/main.rs create mode 100755 scripts/ci-local.sh create mode 100644 web/Dockerfile delete mode 100644 web/build/404.html delete mode 100644 web/build/_app/env.js delete mode 100644 web/build/_app/immutable/chunks/Bzak7iHL.js delete mode 100644 web/build/_app/immutable/chunks/C5YqYP7P.js delete mode 100644 web/build/_app/immutable/chunks/CAYgxOZ1.js delete mode 100644 web/build/_app/immutable/chunks/CGowzvwH.js delete mode 100644 web/build/_app/immutable/chunks/CUCwB180.js delete mode 100644 web/build/_app/immutable/chunks/DNqN6DmX.js delete mode 100644 web/build/_app/immutable/chunks/Db9w--lA.js delete mode 100644 web/build/_app/immutable/chunks/YzYuob9f.js delete mode 100644 web/build/_app/immutable/chunks/eiK12uJk.js delete mode 100644 web/build/_app/immutable/chunks/pTMRHjpX.js delete mode 100644 web/build/_app/immutable/entry/app.H3SWXino.js delete mode 100644 web/build/_app/immutable/entry/start.Pj34kLt-.js delete mode 100644 web/build/_app/immutable/nodes/0.D7-FTC_1.js delete mode 100644 web/build/_app/immutable/nodes/1.BZR9od8C.js delete mode 100644 web/build/_app/immutable/nodes/2.Zg4cVoEY.js delete mode 100644 web/build/_app/immutable/nodes/3.BjNotmmr.js delete mode 100644 web/build/_app/immutable/nodes/4.D0WiVz9B.js delete mode 100644 web/build/_app/immutable/nodes/5.B-zruxZU.js delete mode 100644 web/build/_app/immutable/nodes/6.Cniq5yLG.js delete mode 100644 web/build/_app/immutable/nodes/7.BjdHyPf8.js delete mode 100644 web/build/_app/immutable/nodes/8.Chqc1uyl.js delete mode 100644 web/build/_app/version.json create mode 100644 web/src/lib/server/proxy.ts create mode 100644 web/src/routes/api/auth/[...path]/+server.ts create mode 100644 web/src/routes/api/campaign/[...path]/+server.ts create mode 100644 web/src/routes/api/content/[...path]/+server.ts diff --git a/.env.example b/.env.example index 57ed54c..9ab0048 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,23 @@ -# Backend -DATABASE_URL=postgres://campaign_manager:devpassword@localhost:5432/campaign_manager +# Campaign service +USERS_DATABASE_URL=postgres://cm_campaign_app:devpassword@localhost:5432/cm_users +CAMPAIGN_DATABASE_URL=postgres://cm_campaign_app:devpassword@localhost:5432/cm_campaign +CAMPAIGN_PORT=3000 + +# Content service +CONTENT_DATABASE_URL=postgres://cm_content_app:devpassword@localhost:5432/cm_content +CONTENT_PORT=3001 + +# Shared auth JWT_SECRET=change-me-to-a-long-random-secret -PORT=3000 + +# Web BFF upstreams (server-side only) +CAMPAIGN_API_BASE=http://localhost:3000/v1 +CONTENT_API_BASE=http://localhost:3001/v1 +WEB_PORT=5173 + +# Symbiote direct upstreams (build-time) +VITE_CAMPAIGN_API_BASE=http://localhost:3000/v1 +VITE_CONTENT_API_BASE=http://localhost:3001/v1 # Object storage (Cloudflare R2 or any S3-compatible) S3_ENDPOINT=https://.r2.cloudflarestorage.com diff --git a/.gitignore b/.gitignore index 1c963ab..465cbb5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ dist/ .svelte-kit/ +web/build/ .env .env.* !.env.example @@ -12,7 +13,6 @@ pnpm-debug.log* # Rust target/ -Cargo.lock # OS .DS_Store diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..6153b9f --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,29 @@ +steps: + js-build: + image: node:current-alpine + commands: + - corepack enable + - pnpm install --frozen-lockfile + - pnpm build:web + - pnpm build:symbiote + + rust-check: + image: rust:alpine + commands: + - apk add --no-cache build-base pkgconfig openssl-dev + - rustup component add rustfmt + - cargo fmt --manifest-path backend/Cargo.toml --all -- --check + - cargo check --manifest-path backend/Cargo.toml --workspace + + compose-validate: + image: docker:cli + commands: + - apk add --no-cache docker-cli-compose + - docker compose version + - docker compose config + +when: + event: + - push + - pull_request + - manual diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c0f5e87 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2794 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "axum-macros", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "campaign-manager-backend" +version = "0.1.0" +dependencies = [ + "argon2", + "axum", + "dotenvy", + "jsonwebtoken", + "serde", + "serde_json", + "sqlx", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index d1e49e3..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[workspace] -members = ["backend"] -resolver = "2" diff --git a/README.md b/README.md index 7cf9e55..3570a84 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,97 @@ - Root - - .gitignore, pnpm-workspace.yaml, package.json (workspace scripts), Cargo.toml (workspace), .npmrc - - rulesets/ — @campaign-manager/rulesets workspace package - - types.ts — Ruleset, SheetData, ValidationResult, DiceAction, StatBlock, VNode interfaces - - dsa5e/index.ts — DSA5e stub (typed default sheet with attributes, talents, combat, spells) - - generic/index.ts — Generic stub (name, HP, notes) - - index.ts — re-exports everything + RULESETS registry map +# Campaign Manager - symbiote/ — Plain Svelte + Vite (target es2022 for top-level await support) - - vite.config.ts, tsconfig.json, index.html - - public/manifest.json — valid TaleSpire manifest with colorStyles, fonts, diceFinder, icons extras - - src/lib/ts-api.d.ts — ambient TS global (storage, dice, players, sync) - - src/lib/store.ts — accessToken, refreshToken, currentUser, currentGroup, isBoardTransition stores + - loadTokens/saveTokens/clearTokens via TS.storage - - src/lib/api.ts — auto-refresh on 401, suppresses calls during board transition - - src/App.svelte — currentView store drives view switching - - src/main.ts — board transition listeners, awaits TS.hasInitialized, mounts App - - src/views/ — Login, GroupList, GroupDetail, CharacterSheet, RollHistory stubs +Campaign Manager is split into two Rust backend services, a SvelteKit web app, and a TaleSpire Symbiote frontend. - web/ — SvelteKit + adapter-static - - svelte.config.js, vite.config.ts, tsconfig.json, src/app.html - - src/lib/api.ts — access token in memory, refresh via HttpOnly cookie - - src/routes/+layout.svelte — silent token refresh on mount, redirects to /login if unauthenticated - - All routes stubbed: /, /login, /groups, /groups/[id], /groups/[id]/settings, /characters, /characters/[id] +## Architecture - backend/ — Rust + Axum - - Cargo.toml with all specified dependencies - - src/main.rs — reads DATABASE_URL/JWT_SECRET, builds Axum router, CORS, tracing, binds :3000 - - src/lib.rs — module entrypoint +- `backend/common`: shared Rust crate for JWT and API error primitives. +- `backend/campaign-service`: auth + campaign domain service. +- `backend/content-service`: ruleset/content domain service. +- `web`: SvelteKit Node server that uses server-side BFF proxy routes (`/api/*`). +- `symbiote`: static Svelte app for TaleSpire. - Verification results: ✅ symbiote build → dist/ with index.html + manifest.json ✅ web build → SvelteKit static output - ✅ cargo check → no errors +## Data layout +All databases run on one Postgres instance with separate logical databases: - Local dev workflow is now: - - # Start Postgres - docker compose up -d - - # Copy and fill in secrets - cp .env.example .env +- `cm_users`: users/auth/session data. +- `cm_campaign`: campaign and character data. +- `cm_content`: rulesets/content data. - # Run backend - cd backend && cargo run +## Environment - # Symbiote (build-watch mode — see below) - pnpm dev:symbiote +Copy `.env.example` to `.env` and set values. - # Web app - pnpm dev:web Local dev workflow is now: - - # Start Postgres - docker compose up -d - - # Copy and fill in secrets - cp .env.example .env +Important variables: - # Run backend - cd backend && cargo run +- `USERS_DATABASE_URL` +- `CAMPAIGN_DATABASE_URL` +- `CONTENT_DATABASE_URL` +- `JWT_SECRET` +- `CAMPAIGN_API_BASE` / `CONTENT_API_BASE` (web BFF upstreams) +- `VITE_CAMPAIGN_API_BASE` / `VITE_CONTENT_API_BASE` (symbiote build-time) - # Symbiote (build-watch mode — see below) - pnpm dev:symbiote +## Local development - # Web app - pnpm dev:web +```bash +# Install JS dependencies +pnpm install + +# Run campaign service +pnpm dev:campaign + +# Run content service +pnpm dev:content + +# Run web app (SvelteKit dev server) +pnpm dev:web + +# Run symbiote app +pnpm dev:symbiote +``` + +Build commands: + +```bash +pnpm build:campaign +pnpm build:content +pnpm build:backend +pnpm build:web +pnpm build:symbiote +``` + +Run the same checks as CI locally: + +```bash +pnpm ci:local +``` + +## Web BFF routes + +The web app proxies backend calls via SvelteKit server routes: + +- `/api/auth/*` -> campaign service (`CAMPAIGN_API_BASE`) +- `/api/campaign/*` -> campaign service (`CAMPAIGN_API_BASE`) +- `/api/content/*` -> content service (`CONTENT_API_BASE`) + +The web app is intended to run as a server process (Node adapter) in production. + +## Docker compose + +`docker-compose.yml` runs both backend services plus the web server and expects an external `dev-infra` network for Postgres connectivity. + +## Woodpecker without Public Ingress + +If your Gitea is remote and your Woodpecker server runs locally, push/PR webhooks cannot reach your machine without a public endpoint. + +Recommended workflow until ingress/tunnel exists: + +- Run `pnpm ci:local` before push. +- Use local Woodpecker only for manual runs. + +Local stack files are in `../../infra/woodpecker` from this directory: + +```bash +cp ../../infra/woodpecker/.env.example ../../infra/woodpecker/.env +docker compose -f ../../infra/woodpecker/docker-compose.yml up -d +``` diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 0000000..cdfb655 --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,2842 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "axum-macros", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "campaign-service" +version = "0.1.0" +dependencies = [ + "argon2", + "axum", + "common", + "dotenvy", + "serde", + "serde_json", + "sqlx", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "jsonwebtoken", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "content-service" +version = "0.1.0" +dependencies = [ + "axum", + "common", + "dotenvy", + "serde", + "serde_json", + "sqlx", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.18", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 678a4d8..cf447f9 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,18 +1,19 @@ -[package] -name = "campaign-manager-backend" -version = "0.1.0" -edition = "2021" +[workspace] +members = ["common", "campaign-service", "content-service"] +resolver = "2" -[dependencies] +[workspace.dependencies] axum = { version = "0.7", features = ["macros"] } -tokio = { version = "1", features = ["full"] } -sqlx = { version = "0.8", features = ["postgres", "uuid", "runtime-tokio-native-tls", "chrono"] } +chrono = { version = "0.4", features = ["serde", "clock"] } +dotenvy = "0.15" +jsonwebtoken = "9" serde = { version = "1", features = ["derive"] } serde_json = "1" -jsonwebtoken = "9" -argon2 = "0.5" -uuid = { version = "1", features = ["v4", "serde"] } +sqlx = { version = "0.8", features = ["postgres", "uuid", "runtime-tokio-native-tls", "chrono"] } +thiserror = "1" +tokio = { version = "1", features = ["full"] } tower-http = { version = "0.5", features = ["cors", "trace"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -dotenvy = "0.15" +uuid = { version = "1", features = ["v4", "serde"] } +argon2 = "0.5" diff --git a/backend/campaign-service/Cargo.toml b/backend/campaign-service/Cargo.toml new file mode 100644 index 0000000..4377de4 --- /dev/null +++ b/backend/campaign-service/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "campaign-service" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { workspace = true } +argon2 = { workspace = true } +common = { path = "../common" } +dotenvy = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sqlx = { workspace = true } +tokio = { workspace = true } +tower-http = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +uuid = { workspace = true } diff --git a/backend/campaign-service/Dockerfile b/backend/campaign-service/Dockerfile new file mode 100644 index 0000000..acc5c0d --- /dev/null +++ b/backend/campaign-service/Dockerfile @@ -0,0 +1,14 @@ +FROM rust:alpine AS builder +WORKDIR /app + +RUN apk add --no-cache build-base pkgconfig openssl-dev + +COPY backend ./backend +RUN cargo build --release --manifest-path backend/Cargo.toml -p campaign-service + +FROM alpine:3.23 +RUN apk add --no-cache ca-certificates openssl libgcc libstdc++ + +COPY --from=builder /app/backend/target/release/campaign-service /usr/local/bin/campaign-service +EXPOSE 3000 +CMD ["campaign-service"] diff --git a/backend/campaign-service/migrations/campaign/0001_init.sql b/backend/campaign-service/migrations/campaign/0001_init.sql new file mode 100644 index 0000000..c0ca5d6 --- /dev/null +++ b/backend/campaign-service/migrations/campaign/0001_init.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS groups ( + id UUID PRIMARY KEY, + name TEXT NOT NULL, + dm_user_id UUID NOT NULL, + ruleset_id TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS group_members ( + group_id UUID NOT NULL REFERENCES groups(id), + user_id UUID NOT NULL, + role TEXT NOT NULL, + joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (group_id, user_id) +); diff --git a/backend/campaign-service/migrations/users/0001_init.sql b/backend/campaign-service/migrations/users/0001_init.sql new file mode 100644 index 0000000..9ac5d96 --- /dev/null +++ b/backend/campaign-service/migrations/users/0001_init.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY, + email TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + email_verified BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS refresh_sessions ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL REFERENCES users(id), + token_hash TEXT NOT NULL, + expires_at TIMESTAMPTZ NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); diff --git a/backend/campaign-service/src/main.rs b/backend/campaign-service/src/main.rs new file mode 100644 index 0000000..83e53d8 --- /dev/null +++ b/backend/campaign-service/src/main.rs @@ -0,0 +1,118 @@ +use axum::{ + extract::State, + http::StatusCode, + response::IntoResponse, + routing::{any, get, post}, + Json, Router, +}; +use common::{issue_access_token, AppResult}; +use serde::Serialize; +use sqlx::{postgres::PgPoolOptions, PgPool}; +use tower_http::cors::CorsLayer; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[derive(Clone)] +struct AppState { + users_pool: PgPool, + campaign_pool: PgPool, + jwt_secret: String, +} + +#[derive(Serialize)] +struct HealthResponse { + service: &'static str, + status: &'static str, +} + +#[derive(Serialize)] +struct RefreshResponse { + #[serde(rename = "accessToken")] + access_token: String, + #[serde(rename = "refreshToken")] + refresh_token: String, +} + +#[tokio::main] +async fn main() { + let _ = dotenvy::dotenv(); + + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "campaign_service=debug,tower_http=debug".into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + let users_database_url = + std::env::var("USERS_DATABASE_URL").expect("USERS_DATABASE_URL must be set"); + let campaign_database_url = + std::env::var("CAMPAIGN_DATABASE_URL").expect("CAMPAIGN_DATABASE_URL must be set"); + let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); + let port: u16 = std::env::var("CAMPAIGN_PORT") + .or_else(|_| std::env::var("PORT")) + .unwrap_or_else(|_| "3000".to_string()) + .parse() + .expect("PORT must be a valid u16"); + + let users_pool = PgPoolOptions::new() + .max_connections(10) + .connect_lazy(&users_database_url) + .expect("invalid USERS_DATABASE_URL"); + + let campaign_pool = PgPoolOptions::new() + .max_connections(10) + .connect_lazy(&campaign_database_url) + .expect("invalid CAMPAIGN_DATABASE_URL"); + + let state = AppState { + users_pool, + campaign_pool, + jwt_secret, + }; + + let app = Router::new() + .route("/health", get(health)) + .route("/v1/auth/refresh", post(refresh_token)) + .route("/v1/auth/login", post(not_implemented)) + .route("/v1/auth/register", post(not_implemented)) + .route("/v1/auth/logout", post(not_implemented)) + .route("/v1/*path", any(not_implemented)) + .with_state(state) + .layer(CorsLayer::permissive()); + + let listener = tokio::net::TcpListener::bind(("0.0.0.0", port)) + .await + .expect("failed to bind"); + + tracing::info!( + "campaign-service listening on {}", + listener.local_addr().unwrap() + ); + axum::serve(listener, app).await.expect("server error"); +} + +async fn health(State(state): State) -> impl IntoResponse { + let _ = &state.users_pool; + let _ = &state.campaign_pool; + + Json(HealthResponse { + service: "campaign-service", + status: "ok", + }) +} + +async fn refresh_token(State(state): State) -> AppResult> { + // Stub response until real refresh-token/session persistence is implemented. + let access_token = issue_access_token(&state.jwt_secret, "dev-user", vec!["user".to_string()])?; + let refresh_token = uuid::Uuid::new_v4().to_string(); + + Ok(Json(RefreshResponse { + access_token, + refresh_token, + })) +} + +async fn not_implemented() -> impl IntoResponse { + (StatusCode::NOT_IMPLEMENTED, "not implemented") +} diff --git a/backend/common/Cargo.toml b/backend/common/Cargo.toml new file mode 100644 index 0000000..4c2ab18 --- /dev/null +++ b/backend/common/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { workspace = true } +chrono = { workspace = true } +jsonwebtoken = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } diff --git a/backend/common/src/error.rs b/backend/common/src/error.rs new file mode 100644 index 0000000..8beee42 --- /dev/null +++ b/backend/common/src/error.rs @@ -0,0 +1,40 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use serde::Serialize; +use thiserror::Error; + +#[derive(Debug, Serialize)] +pub struct ApiErrorBody { + pub error: String, +} + +#[derive(Debug, Error)] +pub enum AppError { + #[error("unauthorized: {0}")] + Unauthorized(String), + #[error("bad request: {0}")] + BadRequest(String), + #[error("internal error: {0}")] + Internal(String), +} + +pub type AppResult = Result; + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + let status = match self { + AppError::Unauthorized(_) => StatusCode::UNAUTHORIZED, + AppError::BadRequest(_) => StatusCode::BAD_REQUEST, + AppError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + }; + + let body = ApiErrorBody { + error: self.to_string(), + }; + + (status, Json(body)).into_response() + } +} diff --git a/backend/common/src/jwt.rs b/backend/common/src/jwt.rs new file mode 100644 index 0000000..ff1481d --- /dev/null +++ b/backend/common/src/jwt.rs @@ -0,0 +1,49 @@ +use chrono::{Duration, Utc}; +use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; +use serde::{Deserialize, Serialize}; + +use crate::{AppError, AppResult}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Claims { + pub sub: String, + pub iat: usize, + pub exp: usize, + pub global_roles: Vec, +} + +pub fn issue_access_token( + secret: &str, + user_id: &str, + global_roles: Vec, +) -> AppResult { + let now = Utc::now(); + let exp = now + Duration::minutes(15); + + let claims = Claims { + sub: user_id.to_owned(), + iat: now.timestamp() as usize, + exp: exp.timestamp() as usize, + global_roles, + }; + + encode( + &Header::new(Algorithm::HS256), + &claims, + &EncodingKey::from_secret(secret.as_bytes()), + ) + .map_err(|err| AppError::Internal(format!("failed to encode JWT: {err}"))) +} + +pub fn decode_jwt(secret: &str, token: &str) -> AppResult { + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = true; + + decode::( + token, + &DecodingKey::from_secret(secret.as_bytes()), + &validation, + ) + .map(|data| data.claims) + .map_err(|err| AppError::Unauthorized(format!("invalid token: {err}"))) +} diff --git a/backend/common/src/lib.rs b/backend/common/src/lib.rs new file mode 100644 index 0000000..999a490 --- /dev/null +++ b/backend/common/src/lib.rs @@ -0,0 +1,5 @@ +pub mod error; +pub mod jwt; + +pub use error::{ApiErrorBody, AppError, AppResult}; +pub use jwt::{decode_jwt, issue_access_token, Claims}; diff --git a/backend/content-service/Cargo.toml b/backend/content-service/Cargo.toml new file mode 100644 index 0000000..2da3dc8 --- /dev/null +++ b/backend/content-service/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "content-service" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { workspace = true } +common = { path = "../common" } +dotenvy = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sqlx = { workspace = true } +tokio = { workspace = true } +tower-http = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } diff --git a/backend/content-service/Dockerfile b/backend/content-service/Dockerfile new file mode 100644 index 0000000..bf94e67 --- /dev/null +++ b/backend/content-service/Dockerfile @@ -0,0 +1,14 @@ +FROM rust:alpine AS builder +WORKDIR /app + +RUN apk add --no-cache build-base pkgconfig openssl-dev + +COPY backend ./backend +RUN cargo build --release --manifest-path backend/Cargo.toml -p content-service + +FROM alpine:3.23 +RUN apk add --no-cache ca-certificates openssl libgcc libstdc++ + +COPY --from=builder /app/backend/target/release/content-service /usr/local/bin/content-service +EXPOSE 3001 +CMD ["content-service"] diff --git a/backend/content-service/migrations/content/0001_init.sql b/backend/content-service/migrations/content/0001_init.sql new file mode 100644 index 0000000..fd94a38 --- /dev/null +++ b/backend/content-service/migrations/content/0001_init.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS rulesets ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + version TEXT NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); diff --git a/backend/content-service/src/main.rs b/backend/content-service/src/main.rs new file mode 100644 index 0000000..c11ac68 --- /dev/null +++ b/backend/content-service/src/main.rs @@ -0,0 +1,124 @@ +use axum::{ + extract::State, + http::{header::AUTHORIZATION, HeaderMap, StatusCode}, + response::IntoResponse, + routing::{any, get}, + Json, Router, +}; +use common::{decode_jwt, AppError, AppResult}; +use serde::Serialize; +use sqlx::{postgres::PgPoolOptions, PgPool}; +use tower_http::cors::CorsLayer; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[derive(Clone)] +struct AppState { + content_pool: PgPool, + jwt_secret: String, +} + +#[derive(Serialize)] +struct HealthResponse { + service: &'static str, + status: &'static str, +} + +#[derive(Serialize)] +struct RulesetSummary { + id: &'static str, + name: &'static str, +} + +#[tokio::main] +async fn main() { + let _ = dotenvy::dotenv(); + + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "content_service=debug,tower_http=debug".into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + let content_database_url = + std::env::var("CONTENT_DATABASE_URL").expect("CONTENT_DATABASE_URL must be set"); + let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); + let port: u16 = std::env::var("CONTENT_PORT") + .or_else(|_| std::env::var("PORT")) + .unwrap_or_else(|_| "3001".to_string()) + .parse() + .expect("PORT must be a valid u16"); + + let content_pool = PgPoolOptions::new() + .max_connections(10) + .connect_lazy(&content_database_url) + .expect("invalid CONTENT_DATABASE_URL"); + + let state = AppState { + content_pool, + jwt_secret, + }; + + let app = Router::new() + .route("/health", get(health)) + .route("/v1/rulesets", get(list_rulesets)) + .route("/v1/*path", any(not_implemented)) + .with_state(state) + .layer(CorsLayer::permissive()); + + let listener = tokio::net::TcpListener::bind(("0.0.0.0", port)) + .await + .expect("failed to bind"); + + tracing::info!( + "content-service listening on {}", + listener.local_addr().unwrap() + ); + axum::serve(listener, app).await.expect("server error"); +} + +async fn health(State(state): State) -> impl IntoResponse { + let _ = &state.content_pool; + + Json(HealthResponse { + service: "content-service", + status: "ok", + }) +} + +async fn list_rulesets( + State(state): State, + headers: HeaderMap, +) -> AppResult>> { + require_bearer(&state.jwt_secret, &headers)?; + + Ok(Json(vec![ + RulesetSummary { + id: "generic", + name: "Generic", + }, + RulesetSummary { + id: "dsa5e", + name: "DSA5e", + }, + ])) +} + +fn require_bearer(jwt_secret: &str, headers: &HeaderMap) -> AppResult<()> { + let header = headers + .get(AUTHORIZATION) + .and_then(|value| value.to_str().ok()) + .ok_or_else(|| AppError::Unauthorized("missing Authorization header".to_string()))?; + + let token = header + .strip_prefix("Bearer ") + .ok_or_else(|| AppError::Unauthorized("expected Bearer token".to_string()))?; + + let _claims = decode_jwt(jwt_secret, token)?; + Ok(()) +} + +async fn not_implemented() -> impl IntoResponse { + (StatusCode::NOT_IMPLEMENTED, "not implemented") +} diff --git a/backend/src/lib.rs b/backend/src/lib.rs deleted file mode 100644 index 049ecd2..0000000 --- a/backend/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -// Module entrypoint — reserved for integration tests and shared types. diff --git a/backend/src/main.rs b/backend/src/main.rs deleted file mode 100644 index 9a472de..0000000 --- a/backend/src/main.rs +++ /dev/null @@ -1,43 +0,0 @@ -use axum::{ - http::StatusCode, - response::IntoResponse, - routing::any, - Router, -}; -use tower_http::cors::CorsLayer; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - -#[tokio::main] -async fn main() { - // Load .env if present (dev convenience) - let _ = dotenvy::dotenv(); - - tracing_subscriber::registry() - .with(tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| "campaign_manager_backend=debug,tower_http=debug".into())) - .with(tracing_subscriber::fmt::layer()) - .init(); - - let _database_url = std::env::var("DATABASE_URL") - .expect("DATABASE_URL must be set"); - let _jwt_secret = std::env::var("JWT_SECRET") - .expect("JWT_SECRET must be set"); - - // TODO: initialize sqlx connection pool - // let pool = sqlx::PgPool::connect(&database_url).await.expect("failed to connect to DB"); - - let app = Router::new() - .route("/v1/*path", any(not_implemented)) - .layer(CorsLayer::permissive()); - - let listener = tokio::net::TcpListener::bind("0.0.0.0:3000") - .await - .expect("failed to bind"); - - tracing::info!("listening on {}", listener.local_addr().unwrap()); - axum::serve(listener, app).await.expect("server error"); -} - -async fn not_implemented() -> impl IntoResponse { - (StatusCode::NOT_IMPLEMENTED, "not implemented") -} diff --git a/docker-compose.yml b/docker-compose.yml index 9dae8c2..34c95f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,64 @@ services: - postgres: - image: postgres:18 + campaign-service: + build: + context: . + dockerfile: backend/campaign-service/Dockerfile restart: unless-stopped + env_file: + - path: .env + required: false environment: - POSTGRES_DB: campaign_manager - POSTGRES_USER: campaign_manager - POSTGRES_PASSWORD: devpassword + USERS_DATABASE_URL: ${USERS_DATABASE_URL:-postgres://cm_campaign_app:devpassword@postgres:5432/cm_users} + CAMPAIGN_DATABASE_URL: ${CAMPAIGN_DATABASE_URL:-postgres://cm_campaign_app:devpassword@postgres:5432/cm_campaign} + JWT_SECRET: ${JWT_SECRET:-change-me-to-a-long-random-secret} + PORT: ${CAMPAIGN_PORT:-3000} ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U campaign_manager"] - interval: 5s - timeout: 5s - retries: 5 + - "3000:3000" + networks: + - dev-infra + - internal -volumes: - postgres_data: + content-service: + build: + context: . + dockerfile: backend/content-service/Dockerfile + restart: unless-stopped + env_file: + - path: .env + required: false + environment: + CONTENT_DATABASE_URL: ${CONTENT_DATABASE_URL:-postgres://cm_content_app:devpassword@postgres:5432/cm_content} + JWT_SECRET: ${JWT_SECRET:-change-me-to-a-long-random-secret} + PORT: ${CONTENT_PORT:-3001} + ports: + - "3001:3001" + networks: + - dev-infra + - internal + + web: + build: + context: . + dockerfile: web/Dockerfile + restart: unless-stopped + env_file: + - path: .env + required: false + environment: + CAMPAIGN_API_BASE: ${CAMPAIGN_API_BASE:-http://campaign-service:3000/v1} + CONTENT_API_BASE: ${CONTENT_API_BASE:-http://content-service:3001/v1} + PORT: ${WEB_PORT:-5173} + HOST: 0.0.0.0 + ports: + - "${WEB_PORT:-5173}:${WEB_PORT:-5173}" + depends_on: + - campaign-service + - content-service + networks: + - internal + +networks: + dev-infra: + external: true + internal: + driver: bridge diff --git a/package.json b/package.json index 3410bff..da4385c 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,16 @@ "onlyBuiltDependencies": ["esbuild"] }, "scripts": { + "ci:local": "./scripts/ci-local.sh", + "dev:campaign": "cargo run --manifest-path backend/Cargo.toml -p campaign-service", + "dev:content": "cargo run --manifest-path backend/Cargo.toml -p content-service", "dev:symbiote": "pnpm --filter symbiote dev", "dev:web": "pnpm --filter web dev", + "start:web": "pnpm --filter web start", + "build:campaign": "cargo build --release --manifest-path backend/Cargo.toml -p campaign-service", + "build:content": "cargo build --release --manifest-path backend/Cargo.toml -p content-service", "build:symbiote": "pnpm --filter symbiote build", "build:web": "pnpm --filter web build", - "build:backend": "cargo build --release" + "build:backend": "cargo build --release --manifest-path backend/Cargo.toml --workspace" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c66835d..9efc265 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,9 +41,9 @@ importers: specifier: ^5.0.0 version: 5.53.8 devDependencies: - '@sveltejs/adapter-static': - specifier: ^3.0.0 - version: 3.0.10(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1)) + '@sveltejs/adapter-node': + specifier: ^5.5.4 + version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1)) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.0 version: 5.1.1(svelte@5.53.8)(vite@6.4.1) @@ -231,6 +231,42 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@rollup/plugin-commonjs@29.0.2': + resolution: {integrity: sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.59.0': resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] @@ -377,10 +413,10 @@ packages: peerDependencies: acorn: ^8.9.0 - '@sveltejs/adapter-static@3.0.10': - resolution: {integrity: sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==} + '@sveltejs/adapter-node@5.5.4': + resolution: {integrity: sha512-45X92CXW+2J8ZUzPv3eLlKWEzINKiiGeFWTjyER4ZN4sGgNoaoeSkCY/QYNxHpPXy71QPsctwccBo9jJs0ySPQ==} peerDependencies: - '@sveltejs/kit': ^2.0.0 + '@sveltejs/kit': ^2.4.0 '@sveltejs/kit@2.53.4': resolution: {integrity: sha512-iAIPEahFgDJJyvz8g0jP08KvqnM6JvdW8YfsygZ+pMeMvyM2zssWMltcsotETvjSZ82G3VlitgDtBIvpQSZrTA==} @@ -419,6 +455,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -439,6 +478,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -470,6 +512,9 @@ packages: esrap@2.2.3: resolution: {integrity: sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -484,6 +529,23 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -509,6 +571,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -520,6 +585,11 @@ packages: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -536,6 +606,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + svelte@5.53.8: resolution: {integrity: sha512-UD++BnEc3PUFgjin381LiMHzDjT187Fy+KsPZxvaKrYPZqR0GQ/Ha8h7GDoegIF8tFl1uogoNUejKgcRk77T2Q==} engines: {node: '>=18'} @@ -705,6 +779,42 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@rollup/plugin-commonjs@29.0.2(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.3) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-node-resolve@16.0.3(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.0 + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -786,9 +896,13 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1))': + '@sveltejs/adapter-node@5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1))': dependencies: + '@rollup/plugin-commonjs': 29.0.2(rollup@4.59.0) + '@rollup/plugin-json': 6.1.0(rollup@4.59.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.59.0) '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1) + rollup: 4.59.0 '@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.8)(vite@6.4.1))(svelte@5.53.8)(typescript@5.9.3)(vite@6.4.1)': dependencies: @@ -836,6 +950,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/resolve@1.20.2': {} + '@types/trusted-types@2.0.7': {} acorn@8.16.0: {} @@ -846,6 +962,8 @@ snapshots: clsx@2.1.1: {} + commondir@1.0.1: {} + cookie@0.6.0: {} debug@4.4.3: @@ -891,6 +1009,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + estree-walker@2.0.2: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -898,6 +1018,22 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-module@1.0.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.8 + is-reference@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -916,6 +1052,8 @@ snapshots: nanoid@3.3.11: {} + path-parse@1.0.7: {} + picocolors@1.1.1: {} picomatch@4.0.3: {} @@ -926,6 +1064,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 @@ -967,6 +1111,8 @@ snapshots: source-map-js@1.2.1: {} + supports-preserve-symlinks-flag@1.0.0: {} + svelte@5.53.8: dependencies: '@jridgewell/remapping': 2.3.5 diff --git a/scripts/ci-local.sh b/scripts/ci-local.sh new file mode 100755 index 0000000..dcb9611 --- /dev/null +++ b/scripts/ci-local.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh +set -eu + +corepack enable +pnpm install --frozen-lockfile + +pnpm build:web +pnpm build:symbiote + +cargo fmt --manifest-path backend/Cargo.toml --all -- --check +cargo check --manifest-path backend/Cargo.toml --workspace + +docker compose config >/dev/null + +echo "Local CI checks passed." diff --git a/symbiote/src/lib/api.ts b/symbiote/src/lib/api.ts index 5ca8a43..2805265 100644 --- a/symbiote/src/lib/api.ts +++ b/symbiote/src/lib/api.ts @@ -1,17 +1,23 @@ import { get } from 'svelte/store'; import { accessToken, refreshToken, saveTokens, clearTokens, isBoardTransition } from './store'; -export const BASE_URL = 'https://api.campaign-manager.example.com/v1'; +const CAMPAIGN_BASE_URL = import.meta.env.VITE_CAMPAIGN_API_BASE || 'http://localhost:3000/v1'; +const CONTENT_BASE_URL = import.meta.env.VITE_CONTENT_API_BASE || 'http://localhost:3001/v1'; interface RequestOptions extends RequestInit { skipAuth?: boolean; } +function joinUrl(base: string, path: string): string { + if (!path) return base; + return `${base}${path.startsWith('/') ? path : `/${path}`}`; +} + async function silentRefresh(): Promise { const rt = get(refreshToken); if (!rt) return false; - const res = await fetch(`${BASE_URL}/auth/refresh`, { + const res = await fetch(joinUrl(CAMPAIGN_BASE_URL, '/auth/refresh'), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken: rt }), @@ -27,7 +33,7 @@ async function silentRefresh(): Promise { return true; } -async function apiFetch(path: string, options: RequestOptions = {}): Promise { +async function apiFetch(baseUrl: string, path: string, options: RequestOptions = {}): Promise { if (get(isBoardTransition)) { throw new Error('API call suppressed during board transition'); } @@ -44,14 +50,15 @@ async function apiFetch(path: string, options: RequestOptions = {}): Promise - apiFetch(path, { ...options, method: 'GET' }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'GET' }), post: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), put: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), patch: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), delete: (path: string, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'DELETE' }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'DELETE' }), +}; + +export const contentApi = { + get: (path: string, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'GET' }), + + post: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), + + put: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), + + patch: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), + + delete: (path: string, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'DELETE' }), }; diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..cc087c6 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,22 @@ +FROM node:current-alpine + +WORKDIR /app + +RUN corepack enable + +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ +COPY web ./web +COPY rulesets ./rulesets + +RUN pnpm install --frozen-lockfile +RUN pnpm --filter @campaign-manager/web build + +WORKDIR /app/web + +ENV NODE_ENV=production +ENV HOST=0.0.0.0 +ENV PORT=5173 + +EXPOSE 5173 + +CMD ["node", "build"] diff --git a/web/build/404.html b/web/build/404.html deleted file mode 100644 index a822853..0000000 --- a/web/build/404.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - -
- -
- - diff --git a/web/build/_app/env.js b/web/build/_app/env.js deleted file mode 100644 index f5427da..0000000 --- a/web/build/_app/env.js +++ /dev/null @@ -1 +0,0 @@ -export const env={} \ No newline at end of file diff --git a/web/build/_app/immutable/chunks/Bzak7iHL.js b/web/build/_app/immutable/chunks/Bzak7iHL.js deleted file mode 100644 index e8f20e7..0000000 --- a/web/build/_app/immutable/chunks/Bzak7iHL.js +++ /dev/null @@ -1 +0,0 @@ -var e;typeof window<"u"&&((e=window.__svelte??(window.__svelte={})).v??(e.v=new Set)).add("5"); diff --git a/web/build/_app/immutable/chunks/C5YqYP7P.js b/web/build/_app/immutable/chunks/C5YqYP7P.js deleted file mode 100644 index d516516..0000000 --- a/web/build/_app/immutable/chunks/C5YqYP7P.js +++ /dev/null @@ -1 +0,0 @@ -import{s as c,g as l}from"./DNqN6DmX.js";import{b as o,d as b,n as a,m as d,g as p,e as g}from"./CUCwB180.js";let s=!1,i=Symbol();function m(e,u,r){const n=r[u]??(r[u]={store:null,source:d(void 0),unsubscribe:a});if(n.store!==e&&!(i in r))if(n.unsubscribe(),n.store=e??null,e==null)n.source.v=void 0,n.unsubscribe=a;else{var t=!0;n.unsubscribe=c(e,f=>{t?n.source.v=f:g(n.source,f)}),t=!1}return e&&i in r?l(e):p(n.source)}function y(){const e={};function u(){o(()=>{for(var r in e)e[r].unsubscribe();b(e,i,{enumerable:!1,value:!0})})}return[e,u]}function N(e){var u=s;try{return s=!1,[e(),s]}finally{s=u}}export{m as a,N as c,y as s}; diff --git a/web/build/_app/immutable/chunks/CAYgxOZ1.js b/web/build/_app/immutable/chunks/CAYgxOZ1.js deleted file mode 100644 index dc17f74..0000000 --- a/web/build/_app/immutable/chunks/CAYgxOZ1.js +++ /dev/null @@ -1 +0,0 @@ -import{w as a}from"./CUCwB180.js";a(); diff --git a/web/build/_app/immutable/chunks/CGowzvwH.js b/web/build/_app/immutable/chunks/CGowzvwH.js deleted file mode 100644 index b32e6e4..0000000 --- a/web/build/_app/immutable/chunks/CGowzvwH.js +++ /dev/null @@ -1 +0,0 @@ -import{s as e}from"./YzYuob9f.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p}; diff --git a/web/build/_app/immutable/chunks/CUCwB180.js b/web/build/_app/immutable/chunks/CUCwB180.js deleted file mode 100644 index c62ebd2..0000000 --- a/web/build/_app/immutable/chunks/CUCwB180.js +++ /dev/null @@ -1 +0,0 @@ -var ot=Object.defineProperty;var mn=e=>{throw TypeError(e)};var ct=(e,n,t)=>n in e?ot(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t;var ne=(e,n,t)=>ct(e,typeof n!="symbol"?n+"":n,t),Ze=(e,n,t)=>n.has(e)||mn("Cannot "+t);var d=(e,n,t)=>(Ze(e,n,"read from private field"),t?t.call(e):n.get(e)),D=(e,n,t)=>n.has(e)?mn("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(e):n.set(e,t),z=(e,n,t,r)=>(Ze(e,n,"write to private field"),r?r.call(e,t):n.set(e,t),t),L=(e,n,t)=>(Ze(e,n,"access private method"),t);var _t=Array.isArray,vt=Array.prototype.indexOf,me=Array.prototype.includes,fr=Array.from,lr=Object.defineProperty,Oe=Object.getOwnPropertyDescriptor,dt=Object.getOwnPropertyDescriptors,ht=Object.prototype,pt=Array.prototype,Nn=Object.getPrototypeOf,En=Object.isExtensible;const wt=()=>{};function ir(e){return e()}function yt(e){for(var n=0;n{e=r,n=s});return{promise:t,resolve:e,reject:n}}const T=2,Ee=4,Fe=8,Dn=1<<24,Q=16,H=32,le=64,gt=128,I=512,E=1024,x=2048,B=4096,q=8192,U=16384,_e=32768,Ue=65536,Tn=1<<17,mt=1<<18,Me=1<<19,Pn=1<<20,ie=65536,Xe=1<<21,un=1<<22,J=1<<23,De=Symbol("$state"),ar=Symbol("legacy props"),G=new class extends Error{constructor(){super(...arguments);ne(this,"name","StaleReactionError");ne(this,"message","The reaction that called `getAbortSignal()` was re-run or destroyed")}},Ke=3,In=8;function Et(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function Tt(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function bt(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function At(e){throw new Error("https://svelte.dev/e/effect_orphan")}function Rt(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function or(){throw new Error("https://svelte.dev/e/hydration_failed")}function cr(e){throw new Error("https://svelte.dev/e/props_invalid_value")}function St(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function xt(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function kt(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function _r(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const vr=1,dr=2,hr=4,pr=8,wr=16,yr=1,gr=2,Nt="[",Ot="[!",mr="[?",Dt="]",on={},b=Symbol(),Pt="http://www.w3.org/1999/xhtml";function cn(e){console.warn("https://svelte.dev/e/hydration_mismatch")}function Er(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}let ae=!1;function Tr(e){ae=e}let m;function Te(e){if(e===null)throw cn(),on;return m=e}function br(){return Te(ee(m))}function Ar(e){if(ae){if(ee(m)!==null)throw cn(),on;m=e}}function Rr(e=1){if(ae){for(var n=e,t=m;n--;)t=ee(t);m=t}}function Sr(e=!0){for(var n=0,t=m;;){if(t.nodeType===In){var r=t.data;if(r===Dt){if(n===0)return t;n-=1}else(r===Nt||r===Ot||r[0]==="["&&!isNaN(Number(r.slice(1))))&&(n+=1)}var s=ee(t);e&&t.remove(),t=s}}function xr(e){if(!e||e.nodeType!==In)throw cn(),on;return e.data}function Cn(e){return e===this.v}function It(e,n){return e!=e?n==n:e!==n||e!==null&&typeof e=="object"||typeof e=="function"}function Fn(e){return!It(e,this.v)}let $e=!1;function kr(){$e=!0}let S=null;function He(e){S=e}function Nr(e,n=!1,t){S={p:S,i:!1,c:null,e:null,s:e,x:null,l:$e&&!n?{s:null,u:null,$:[]}:null}}function Or(e){var n=S,t=n.e;if(t!==null){n.e=null;for(var r of t)Xn(r)}return n.i=!0,S=n.p,{}}function je(){return!$e||S!==null&&S.l===null}let re=[];function Mn(){var e=re;re=[],yt(e)}function bn(e){if(re.length===0&&!Pe){var n=re;queueMicrotask(()=>{n===re&&Mn()})}re.push(e)}function Ct(){for(;re.length>0;)Mn()}function Ft(e){var n=w;if(n===null)return v.f|=J,e;if((n.f&_e)===0&&(n.f&Ee)===0)throw e;Be(e,n)}function Be(e,n){for(;n!==null;){if((n.f>)!==0){if((n.f&_e)===0)throw e;try{n.b.error(e);return}catch(t){e=t}}n=n.parent}throw e}const Mt=-7169;function y(e,n){e.f=e.f&Mt|n}function _n(e){(e.f&I)!==0||e.deps===null?y(e,E):y(e,B)}function jn(e){if(e!==null)for(const n of e)(n.f&T)===0||(n.f&ie)===0||(n.f^=ie,jn(n.deps))}function jt(e,n,t){(e.f&x)!==0?n.add(e):(e.f&B)!==0&&t.add(e),jn(e.deps),y(e,E)}const xe=new Set;let h=null,A=null,Qe=null,Pe=!1,Je=!1,ve=null,Ye=null;var An=0;let Lt=1;var de,he,pe,we,Ce,$,ye,Z,Y,ge,R,en,nn,tn,rn,Ln;const Ge=class Ge{constructor(){D(this,R);ne(this,"id",Lt++);ne(this,"current",new Map);ne(this,"previous",new Map);D(this,de,new Set);D(this,he,new Set);D(this,pe,0);D(this,we,0);D(this,Ce,null);D(this,$,[]);D(this,ye,new Set);D(this,Z,new Set);D(this,Y,new Map);ne(this,"is_fork",!1);D(this,ge,!1)}skip_effect(n){d(this,Y).has(n)||d(this,Y).set(n,{d:[],m:[]})}unskip_effect(n){var t=d(this,Y).get(n);if(t){d(this,Y).delete(n);for(var r of t.d)y(r,x),this.schedule(r);for(r of t.m)y(r,B),this.schedule(r)}}capture(n,t){t!==b&&!this.previous.has(n)&&this.previous.set(n,t),(n.f&J)===0&&(this.current.set(n,n.v),A==null||A.set(n,n.v))}activate(){h=this}deactivate(){h=null,A=null}flush(){try{if(Je=!0,h=this,!L(this,R,en).call(this)){for(const n of d(this,ye))d(this,Z).delete(n),y(n,x),this.schedule(n);for(const n of d(this,Z))y(n,B),this.schedule(n)}L(this,R,nn).call(this)}finally{An=0,Qe=null,ve=null,Ye=null,Je=!1,h=null,A=null,W.clear()}}discard(){for(const n of d(this,he))n(this);d(this,he).clear()}increment(n){z(this,pe,d(this,pe)+1),n&&z(this,we,d(this,we)+1)}decrement(n,t){z(this,pe,d(this,pe)-1),n&&z(this,we,d(this,we)-1),!(d(this,ge)||t)&&(z(this,ge,!0),bn(()=>{z(this,ge,!1),this.flush()}))}oncommit(n){d(this,de).add(n)}ondiscard(n){d(this,he).add(n)}settled(){return(d(this,Ce)??z(this,Ce,On())).promise}static ensure(){if(h===null){const n=h=new Ge;Je||(xe.add(h),Pe||bn(()=>{h===n&&n.flush()}))}return h}apply(){}schedule(n){var s;if(Qe=n,(s=n.b)!=null&&s.is_pending&&(n.f&(Ee|Fe|Dn))!==0&&(n.f&_e)===0){n.b.defer_effect(n);return}for(var t=n;t.parent!==null;){t=t.parent;var r=t.f;if(ve!==null&&t===w&&(v===null||(v.f&T)===0))return;if((r&(le|H))!==0){if((r&E)===0)return;t.f^=E}}d(this,$).push(t)}};de=new WeakMap,he=new WeakMap,pe=new WeakMap,we=new WeakMap,Ce=new WeakMap,$=new WeakMap,ye=new WeakMap,Z=new WeakMap,Y=new WeakMap,ge=new WeakMap,R=new WeakSet,en=function(){return this.is_fork||d(this,we)>0},nn=function(){var a,l;An++>1e3&&qt();const n=d(this,$);z(this,$,[]),this.apply();var t=ve=[],r=[],s=Ye=[];for(const i of n)L(this,R,tn).call(this,i,t,r);if(h=null,s.length>0){var f=Ge.ensure();for(const i of s)f.schedule(i)}if(ve=null,Ye=null,L(this,R,en).call(this)){L(this,R,rn).call(this,r),L(this,R,rn).call(this,t);for(const[i,o]of d(this,Y))Un(i,o)}else{d(this,ye).clear(),d(this,Z).clear();for(const i of d(this,de))i(this);d(this,de).clear(),Rn(r),Rn(t),d(this,pe)===0&&L(this,R,Ln).call(this),(a=d(this,Ce))==null||a.resolve()}var u=h;u!==null&&(xe.add(u),L(l=u,R,nn).call(l))},tn=function(n,t,r){n.f^=E;for(var s=n.first;s!==null;){var f=s.f,u=(f&(H|le))!==0,a=u&&(f&E)!==0,l=a||(f&q)!==0||d(this,Y).has(s);if(!l&&s.fn!==null){u?s.f^=E:(f&Ee)!==0?t.push(s):Le(s)&&((f&Q)!==0&&d(this,Z).add(s),Ae(s));var i=s.first;if(i!==null){s=i;continue}}for(;s!==null;){var o=s.next;if(o!==null){s=o;break}s=s.parent}}},rn=function(n){for(var t=0;t1){this.previous.clear();var n=h,t=A,r=!0;for(const f of xe){if(f===this){r=!1;continue}const u=[];for(const[l,i]of this.current){if(f.current.has(l))if(r&&i!==f.current.get(l))f.current.set(l,i);else continue;u.push(l)}if(u.length===0)continue;const a=[...f.current.keys()].filter(l=>!this.current.has(l));if(a.length>0){f.activate();const l=new Set,i=new Map;for(const o of u)Yn(o,a,l,i);if(d(f,$).length>0){f.apply();for(const o of d(f,$))L(s=f,R,tn).call(s,o,[],[])}f.deactivate()}}h=n,A=t}d(this,Y).clear(),xe.delete(this)};let ue=Ge;function Yt(e){var n=Pe;Pe=!0;try{for(var t;;){if(Ct(),h===null)return t;h.flush()}}finally{Pe=n}}function qt(){try{Rt()}catch(e){Be(e,Qe)}}let M=null;function Rn(e){var n=e.length;if(n!==0){for(var t=0;t0)){W.clear();for(const s of M){if((s.f&(U|q))!==0)continue;const f=[s];let u=s.parent;for(;u!==null;)M.has(u)&&(M.delete(u),f.push(u)),u=u.parent;for(let a=f.length-1;a>=0;a--){const l=f[a];(l.f&(U|q))===0&&Ae(l)}}M.clear()}}M=null}}function Yn(e,n,t,r){if(!t.has(e)&&(t.add(e),e.reactions!==null))for(const s of e.reactions){const f=s.f;(f&T)!==0?Yn(s,n,t,r):(f&(un|Q))!==0&&(f&x)===0&&qn(s,n,r)&&(y(s,x),vn(s))}}function qn(e,n,t){const r=t.get(e);if(r!==void 0)return r;if(e.deps!==null)for(const s of e.deps){if(me.call(n,s))return!0;if((s.f&T)!==0&&qn(s,n,t))return t.set(s,!0),!0}return t.set(e,!1),!1}function vn(e){h.schedule(e)}function Un(e,n){if(!((e.f&H)!==0&&(e.f&E)!==0)){(e.f&x)!==0?n.d.push(e):(e.f&B)!==0&&n.m.push(e),y(e,E);for(var t=e.first;t!==null;)Un(t,n),t=t.next}}function Ut(e,n,t,r){const s=je()?dn:Vt;var f=e.filter(c=>!c.settled);if(t.length===0&&f.length===0){r(n.map(s));return}var u=w,a=Ht(),l=f.length===1?f[0].promise:f.length>1?Promise.all(f.map(c=>c.promise)):null;function i(c){a();try{r(c)}catch(g){(u.f&U)===0&&Be(g,u)}Ve()}if(t.length===0){l.then(()=>i(n.map(s)));return}var o=Hn();function _(){Promise.all(t.map(c=>Bt(c))).then(c=>i([...n.map(s),...c])).catch(c=>Be(c,u)).finally(()=>o())}l?l.then(()=>{a(),_(),Ve()}):_()}function Ht(){var e=w,n=v,t=S,r=h;return function(f=!0){be(e),X(n),He(t),f&&(e.f&U)===0&&(r==null||r.activate(),r==null||r.apply())}}function Ve(e=!0){be(null),X(null),He(null),e&&(h==null||h.deactivate())}function Hn(){var e=w.b,n=h,t=e.is_rendered();return e.update_pending_count(1,n),n.increment(t),(r=!1)=>{e.update_pending_count(-1,n),n.decrement(t,r)}}function dn(e){var n=T|x,t=v!==null&&(v.f&T)!==0?v:null;return w!==null&&(w.f|=Me),{ctx:S,deps:null,effects:null,equals:Cn,f:n,fn:e,reactions:null,rv:0,v:b,wv:0,parent:t??w,ac:null}}function Bt(e,n,t){let r=w;r===null&&Et();var s=void 0,f=pn(b),u=!v,a=new Map;return Xt(()=>{var g;var l=w,i=On();s=i.promise;try{Promise.resolve(e()).then(i.resolve,i.reject).finally(Ve)}catch(p){i.reject(p),Ve()}var o=h;if(u){if((l.f&_e)!==0)var _=Hn();if(r.b.is_rendered())(g=a.get(o))==null||g.reject(G),a.delete(o);else{for(const p of a.values())p.reject(G);a.clear()}a.set(o,i)}const c=(p,F=void 0)=>{if(_){var k=F===G;_(k)}if(!(F===G||(l.f&U)!==0)){if(o.activate(),F)f.f|=J,fn(f,F);else{(f.f&J)!==0&&(f.f^=J),fn(f,p);for(const[Re,Se]of a){if(a.delete(Re),Re===o)break;Se.reject(G)}}o.deactivate()}};i.promise.then(c,p=>c(null,p||"unknown"))}),Wt(()=>{for(const l of a.values())l.reject(G)}),new Promise(l=>{function i(o){function _(){o===s?l(f):i(s)}o.then(_,_)}i(s)})}function Dr(e){const n=dn(e);return rt(n),n}function Vt(e){const n=dn(e);return n.equals=Fn,n}function zt(e){var n=e.effects;if(n!==null){e.effects=null;for(var t=0;t0&&!zn&&$t()}return n}function $t(){zn=!1;for(const e of sn)(e.f&E)!==0&&y(e,B),Le(e)&&Ae(e);sn.clear()}function We(e){te(e,e.v+1)}function Gn(e,n,t){var r=e.reactions;if(r!==null)for(var s=je(),f=r.length,u=0;u{if(fe===f)return a();var l=v,i=fe;X(null),kn(f);var o=a();return X(l),kn(i),o};return r&&t.set("length",K(e.length)),new Proxy(e,{defineProperty(a,l,i){(!("value"in i)||i.configurable===!1||i.enumerable===!1||i.writable===!1)&&St();var o=t.get(l);return o===void 0?u(()=>{var _=K(i.value);return t.set(l,_),_}):te(o,i.value,!0),!0},deleteProperty(a,l){var i=t.get(l);if(i===void 0){if(l in a){const o=u(()=>K(b));t.set(l,o),We(s)}}else te(i,b),We(s);return!0},get(a,l,i){var g;if(l===De)return e;var o=t.get(l),_=l in a;if(o===void 0&&(!_||(g=Oe(a,l))!=null&&g.writable)&&(o=u(()=>{var p=ke(_?a[l]:b),F=K(p);return F}),t.set(l,o)),o!==void 0){var c=Ne(o);return c===b?void 0:c}return Reflect.get(a,l,i)},getOwnPropertyDescriptor(a,l){var i=Reflect.getOwnPropertyDescriptor(a,l);if(i&&"value"in i){var o=t.get(l);o&&(i.value=Ne(o))}else if(i===void 0){var _=t.get(l),c=_==null?void 0:_.v;if(_!==void 0&&c!==b)return{enumerable:!0,configurable:!0,value:c,writable:!0}}return i},has(a,l){var c;if(l===De)return!0;var i=t.get(l),o=i!==void 0&&i.v!==b||Reflect.has(a,l);if(i!==void 0||w!==null&&(!o||(c=Oe(a,l))!=null&&c.writable)){i===void 0&&(i=u(()=>{var g=o?ke(a[l]):b,p=K(g);return p}),t.set(l,i));var _=Ne(i);if(_===b)return!1}return o},set(a,l,i,o){var gn;var _=t.get(l),c=l in a;if(r&&l==="length")for(var g=i;g<_.v;g+=1){var p=t.get(g+"");p!==void 0?te(p,b):g in a&&(p=u(()=>K(b)),t.set(g+"",p))}if(_===void 0)(!c||(gn=Oe(a,l))!=null&&gn.writable)&&(_=u(()=>K(void 0)),te(_,ke(i)),t.set(l,_));else{c=_.v!==b;var F=u(()=>ke(i));te(_,F)}var k=Reflect.getOwnPropertyDescriptor(a,l);if(k!=null&&k.set&&k.set.call(o,i),!c){if(r&&typeof l=="string"){var Re=t.get("length"),Se=Number(l);Number.isInteger(Se)&&Se>=Re.v&&te(Re,Se+1)}We(s)}return!0},ownKeys(a){Ne(s);var l=Reflect.ownKeys(a).filter(_=>{var c=t.get(_);return c===void 0||c.v!==b});for(var[i,o]of t)o.v!==b&&!(i in a)&&l.push(i);return l},setPrototypeOf(){xt()}})}var Sn,Zt,Kn,$n;function Ir(){if(Sn===void 0){Sn=window,Zt=/Firefox/.test(navigator.userAgent);var e=Element.prototype,n=Node.prototype,t=Text.prototype;Kn=Oe(n,"firstChild").get,$n=Oe(n,"nextSibling").get,En(e)&&(e.__click=void 0,e.__className=void 0,e.__attributes=null,e.__style=void 0,e.__e=void 0),En(t)&&(t.__t=void 0)}}function ze(e=""){return document.createTextNode(e)}function ln(e){return Kn.call(e)}function ee(e){return $n.call(e)}function Cr(e,n){if(!ae)return ln(e);var t=ln(m);if(t===null)t=m.appendChild(ze());else if(n&&t.nodeType!==Ke){var r=ze();return t==null||t.before(r),Te(r),r}return n&&wn(t),Te(t),t}function Fr(e,n=!1){if(!ae){var t=ln(e);return t instanceof Comment&&t.data===""?ee(t):t}if(n){if((m==null?void 0:m.nodeType)!==Ke){var r=ze();return m==null||m.before(r),Te(r),r}wn(m)}return m}function Mr(e,n=1,t=!1){let r=ae?m:e;for(var s;n--;)s=r,r=ee(r);if(!ae)return r;if(t){if((r==null?void 0:r.nodeType)!==Ke){var f=ze();return r===null?s==null||s.after(f):r.before(f),Te(f),f}wn(r)}return Te(r),r}function jr(e){e.textContent=""}function Lr(){return!1}function Yr(e,n,t){return document.createElementNS(Pt,e,void 0)}function wn(e){if(e.nodeValue.length<65536)return;let n=e.nextSibling;for(;n!==null&&n.nodeType===Ke;)n.remove(),e.nodeValue+=n.nodeValue,n=e.nextSibling}function Zn(e){var n=v,t=w;X(null),be(null);try{return e()}finally{X(n),be(t)}}function Jn(e){w===null&&(v===null&&At(),bt()),ce&&Tt()}function Jt(e,n){var t=n.last;t===null?n.last=n.first=e:(t.next=e,e.prev=t,n.last=e)}function V(e,n){var t=w;t!==null&&(t.f&q)!==0&&(e|=q);var r={ctx:S,deps:null,nodes:null,f:e|x|I,first:null,fn:n,last:null,next:null,parent:t,b:t&&t.b,prev:null,teardown:null,wv:0,ac:null},s=r;if((e&Ee)!==0)ve!==null?ve.push(r):ue.ensure().schedule(r);else if(n!==null){try{Ae(r)}catch(u){throw oe(r),u}s.deps===null&&s.teardown===null&&s.nodes===null&&s.first===s.last&&(s.f&Me)===0&&(s=s.first,(e&Q)!==0&&(e&Ue)!==0&&s!==null&&(s.f|=Ue))}if(s!==null&&(s.parent=t,t!==null&&Jt(s,t),v!==null&&(v.f&T)!==0&&(e&le)===0)){var f=v;(f.effects??(f.effects=[])).push(s)}return r}function Wn(){return v!==null&&!j}function Wt(e){const n=V(Fe,null);return y(n,E),n.teardown=e,n}function qr(e){Jn();var n=w.f,t=!v&&(n&H)!==0&&(n&_e)===0;if(t){var r=S;(r.e??(r.e=[])).push(e)}else return Xn(e)}function Xn(e){return V(Ee|Pn,e)}function Ur(e){return Jn(),V(Fe|Pn,e)}function Hr(e){ue.ensure();const n=V(le|Me,e);return(t={})=>new Promise(r=>{t.outro?nr(n,()=>{oe(n),r(void 0)}):(oe(n),r(void 0))})}function Br(e){return V(Ee,e)}function Xt(e){return V(un|Me,e)}function Vr(e,n=0){return V(Fe|n,e)}function zr(e,n=[],t=[],r=[]){Ut(r,n,t,s=>{V(Fe,()=>e(...s.map(Ne)))})}function Gr(e,n=0){var t=V(Q|n,e);return t}function Kr(e){return V(H|Me,e)}function Qn(e){var n=e.teardown;if(n!==null){const t=ce,r=v;xn(!0),X(null);try{n.call(null)}finally{xn(t),X(r)}}}function yn(e,n=!1){var t=e.first;for(e.first=e.last=null;t!==null;){const s=t.ac;s!==null&&Zn(()=>{s.abort(G)});var r=t.next;(t.f&le)!==0?t.parent=null:oe(t,n),t=r}}function Qt(e){for(var n=e.first;n!==null;){var t=n.next;(n.f&H)===0&&oe(n),n=t}}function oe(e,n=!0){var t=!1;(n||(e.f&mt)!==0)&&e.nodes!==null&&e.nodes.end!==null&&(er(e.nodes.start,e.nodes.end),t=!0),yn(e,n&&!t),Ie(e,0),y(e,U);var r=e.nodes&&e.nodes.t;if(r!==null)for(const f of r)f.stop();Qn(e);var s=e.parent;s!==null&&s.first!==null&&et(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=null}function er(e,n){for(;e!==null;){var t=e===n?null:ee(e);e.remove(),e=t}}function et(e){var n=e.parent,t=e.prev,r=e.next;t!==null&&(t.next=r),r!==null&&(r.prev=t),n!==null&&(n.first===e&&(n.first=r),n.last===e&&(n.last=t))}function nr(e,n,t=!0){var r=[];nt(e,r,!0);var s=()=>{t&&oe(e),n&&n()},f=r.length;if(f>0){var u=()=>--f||s();for(var a of r)a.out(u)}else s()}function nt(e,n,t){if((e.f&q)===0){e.f^=q;var r=e.nodes&&e.nodes.t;if(r!==null)for(const a of r)(a.is_global||t)&&n.push(a);for(var s=e.first;s!==null;){var f=s.next,u=(s.f&Ue)!==0||(s.f&H)!==0&&(e.f&Q)!==0;nt(s,n,u?t:!1),s=f}}}function $r(e){tt(e,!0)}function tt(e,n){if((e.f&q)!==0){e.f^=q,(e.f&E)===0&&(y(e,x),ue.ensure().schedule(e));for(var t=e.first;t!==null;){var r=t.next,s=(t.f&Ue)!==0||(t.f&H)!==0;tt(t,s?n:!1),t=r}var f=e.nodes&&e.nodes.t;if(f!==null)for(const u of f)(u.is_global||n)&&u.in()}}function Zr(e,n){if(e.nodes)for(var t=e.nodes.start,r=e.nodes.end;t!==null;){var s=t===r?null:ee(t);n.append(t),t=s}}let qe=!1,ce=!1;function xn(e){ce=e}let v=null,j=!1;function X(e){v=e}let w=null;function be(e){w=e}let C=null;function rt(e){v!==null&&(C===null?C=[e]:C.push(e))}let N=null,O=0,P=null;function tr(e){P=e}let st=1,se=0,fe=se;function kn(e){fe=e}function ft(){return++st}function Le(e){var n=e.f;if((n&x)!==0)return!0;if(n&T&&(e.f&=~ie),(n&B)!==0){for(var t=e.deps,r=t.length,s=0;se.wv)return!0}(n&I)!==0&&A===null&&y(e,E)}return!1}function lt(e,n,t=!0){var r=e.reactions;if(r!==null&&!(C!==null&&me.call(C,e)))for(var s=0;s{e.ac.abort(G)}),e.ac=null);try{e.f|=Xe;var o=e.fn,_=o();e.f|=_e;var c=e.deps,g=h==null?void 0:h.is_fork;if(N!==null){var p;if(g||Ie(e,O),c!==null&&O>0)for(c.length=O+N.length,p=0;pe.subscribe(n,s));return u.unsubscribe?()=>u.unsubscribe():u}const i=[];function q(e,n=c){let s=null;const u=new Set;function r(o){if(p(e,o)&&(e=o,s)){const f=!i.length;for(const t of u)t[1](),i.push(t,e);if(f){for(let t=0;t{u.delete(t),u.size===0&&s&&(s(),s=null)}}return{set:r,update:b,subscribe:_}}function k(e){let n;return g(e,s=>n=s)(),n}function x(e){l===null&&h(),m&&l.l!==null?w(l).m.push(e):d(()=>{const n=a(e);if(typeof n=="function")return n})}function w(e){var n=e.l;return n.u??(n.u={a:[],b:[],m:[]})}export{k as g,x as o,g as s,q as w}; diff --git a/web/build/_app/immutable/chunks/Db9w--lA.js b/web/build/_app/immutable/chunks/Db9w--lA.js deleted file mode 100644 index 7e6c183..0000000 --- a/web/build/_app/immutable/chunks/Db9w--lA.js +++ /dev/null @@ -1,2 +0,0 @@ -var Fe=Object.defineProperty;var le=r=>{throw TypeError(r)};var ke=(r,e,t)=>e in r?Fe(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var q=(r,e,t)=>ke(r,typeof e!="symbol"?e+"":e,t),re=(r,e,t)=>e.has(r)||le("Cannot "+t);var s=(r,e,t)=>(re(r,e,"read from private field"),t?t.call(r):e.get(r)),d=(r,e,t)=>e.has(r)?le("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(r):e.set(r,t),n=(r,e,t,i)=>(re(r,e,"write to private field"),i?i.call(r,t):e.set(r,t),t),p=(r,e,t)=>(re(r,e,"access private method"),t);import{L as Ye,g as be,M as Ie,N as Ee,j as Me,O as de,P as J,E as Y,D as I,z as P,Q as ce,S as Ce,U as k,y as Te,V as se,W as _e,X as He,Y as ue,Z as Pe,_ as Ve,$ as Be,a0 as Z,a1 as G,a2 as pe,a3 as Le,a4 as $e,a5 as we,h as Se,a6 as je,a7 as ie,H as K,v as qe,a8 as xe,a9 as x,aa as We,F as ze,ab as Ue,ac as ge,ad as Je,ae as Qe,af as Xe,d as Ze,ag as ae,A as Ge,ah as Re,ai as Ke,aj as et,ak as ne,al as W,am as tt,an as rt,ao as st,ap as it,p as at,aq as nt,ar as ht,a as ft}from"./CUCwB180.js";import{b as ot}from"./pTMRHjpX.js";function lt(r){let e=0,t=Ee(0),i;return()=>{Ye()&&(be(t),Ie(()=>(e===0&&(i=Me(()=>r(()=>de(t)))),e+=1,()=>{J(()=>{e-=1,e===0&&(i==null||i(),i=void 0,de(t))})})))}}var dt=Qe|Xe;function ct(r,e,t,i){new _t(r,e,t,i)}var b,j,w,M,g,S,E,T,R,C,A,V,B,L,D,ee,f,De,Ne,Ae,he,Q,X,fe;class _t{constructor(e,t,i,o){d(this,f);q(this,"parent");q(this,"is_pending",!1);q(this,"transform_error");d(this,b);d(this,j,I?Y:null);d(this,w);d(this,M);d(this,g);d(this,S,null);d(this,E,null);d(this,T,null);d(this,R,null);d(this,C,0);d(this,A,0);d(this,V,!1);d(this,B,new Set);d(this,L,new Set);d(this,D,null);d(this,ee,lt(()=>(n(this,D,Ee(s(this,C))),()=>{n(this,D,null)})));var a;n(this,b,e),n(this,w,t),n(this,M,h=>{var _=P;_.b=this,_.f|=ce,i(h)}),this.parent=P.b,this.transform_error=o??((a=this.parent)==null?void 0:a.transform_error)??(h=>h),n(this,g,Ce(()=>{if(I){const h=s(this,j);ze();const _=h.data===Ue;if(h.data.startsWith(ge)){const c=JSON.parse(h.data.slice(ge.length));p(this,f,Ne).call(this,c)}else _?p(this,f,Ae).call(this):p(this,f,De).call(this)}else p(this,f,he).call(this)},dt)),I&&n(this,b,Y)}defer_effect(e){Be(e,s(this,B),s(this,L))}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!s(this,w).pending}update_pending_count(e,t){p(this,f,fe).call(this,e,t),n(this,C,s(this,C)+e),!(!s(this,D)||s(this,V))&&(n(this,V,!0),J(()=>{n(this,V,!1),s(this,D)&&je(s(this,D),s(this,C))}))}get_effect_pending(){return s(this,ee).call(this),be(s(this,D))}error(e){var t=s(this,w).onerror;let i=s(this,w).failed;if(!t&&!i)throw e;s(this,S)&&(ie(s(this,S)),n(this,S,null)),s(this,E)&&(ie(s(this,E)),n(this,E,null)),s(this,T)&&(ie(s(this,T)),n(this,T,null)),I&&(K(s(this,j)),qe(),K(xe()));var o=!1,a=!1;const h=()=>{if(o){Je();return}o=!0,a&&We(),s(this,T)!==null&&se(s(this,T),()=>{n(this,T,null)}),p(this,f,X).call(this,()=>{p(this,f,he).call(this)})},_=l=>{try{a=!0,t==null||t(l,h),a=!1}catch(c){x(c,s(this,g)&&s(this,g).parent)}i&&n(this,T,p(this,f,X).call(this,()=>{try{return k(()=>{var c=P;c.b=this,c.f|=ce,i(s(this,b),()=>l,()=>h)})}catch(c){return x(c,s(this,g).parent),null}}))};J(()=>{var l;try{l=this.transform_error(e)}catch(c){x(c,s(this,g)&&s(this,g).parent);return}l!==null&&typeof l=="object"&&typeof l.then=="function"?l.then(_,c=>x(c,s(this,g)&&s(this,g).parent)):_(l)})}}b=new WeakMap,j=new WeakMap,w=new WeakMap,M=new WeakMap,g=new WeakMap,S=new WeakMap,E=new WeakMap,T=new WeakMap,R=new WeakMap,C=new WeakMap,A=new WeakMap,V=new WeakMap,B=new WeakMap,L=new WeakMap,D=new WeakMap,ee=new WeakMap,f=new WeakSet,De=function(){try{n(this,S,k(()=>s(this,M).call(this,s(this,b))))}catch(e){this.error(e)}},Ne=function(e){const t=s(this,w).failed;t&&n(this,T,k(()=>{t(s(this,b),()=>e,()=>()=>{})}))},Ae=function(){const e=s(this,w).pending;if(e){this.is_pending=!0,n(this,E,k(()=>e(s(this,b))));var t=_e;J(()=>{var i=n(this,R,document.createDocumentFragment()),o=Te();i.append(o),n(this,S,p(this,f,X).call(this,()=>k(()=>s(this,M).call(this,o)))),s(this,A)===0&&(s(this,b).before(i),n(this,R,null),se(s(this,E),()=>{n(this,E,null)}),p(this,f,Q).call(this,t))})}},he=function(){var e=_e;try{if(this.is_pending=this.has_pending_snippet(),n(this,A,0),n(this,C,0),n(this,S,k(()=>{s(this,M).call(this,s(this,b))})),s(this,A)>0){var t=n(this,R,document.createDocumentFragment());He(s(this,S),t);const i=s(this,w).pending;n(this,E,k(()=>i(s(this,b))))}else p(this,f,Q).call(this,e)}catch(i){this.error(i)}},Q=function(e){this.is_pending=!1;for(const t of s(this,B))ue(t,Pe),e.schedule(t);for(const t of s(this,L))ue(t,Ve),e.schedule(t);s(this,B).clear(),s(this,L).clear()},X=function(e){var t=P,i=we,o=Se;Z(s(this,g)),G(s(this,g)),pe(s(this,g).ctx);try{return Le.ensure(),e()}catch(a){return $e(a),null}finally{Z(t),G(i),pe(o)}},fe=function(e,t){var i;if(!this.has_pending_snippet()){this.parent&&p(i=this.parent,f,fe).call(i,e,t);return}n(this,A,s(this,A)+e),s(this,A)===0&&(p(this,f,Q).call(this,t),s(this,E)&&se(s(this,E),()=>{n(this,E,null)}),s(this,R)&&(s(this,b).before(s(this,R)),n(this,R,null)))};const ut=["touchstart","touchmove"];function pt(r){return ut.includes(r)}const z=Symbol("events"),gt=new Set,ve=new Set;let ye=null;function me(r){var O,m;var e=this,t=e.ownerDocument,i=r.type,o=((O=r.composedPath)==null?void 0:O.call(r))||[],a=o[0]||r.target;ye=r;var h=0,_=ye===r&&r[z];if(_){var l=o.indexOf(_);if(l!==-1&&(e===document||e===window)){r[z]=e;return}var c=o.indexOf(e);if(c===-1)return;l<=c&&(h=l)}if(a=o[h]||r.target,a!==e){Ze(r,"currentTarget",{configurable:!0,get(){return a||t}});var H=we,$=P;G(null),Z(null);try{for(var N,v=[];a!==null;){var u=a.assignedSlot||a.parentNode||a.host||null;try{var y=(m=a[z])==null?void 0:m[i];y!=null&&(!a.disabled||r.target===a)&&y.call(a,r)}catch(F){N?v.push(F):N=F}if(r.cancelBubble||u===e||u===null)break;a=u}if(N){for(let F of v)queueMicrotask(()=>{throw F});throw N}}finally{r[z]=e,delete r.currentTarget,G(H),Z($)}}}function Et(r,e){var t=e==null?"":typeof e=="object"?`${e}`:e;t!==(r.__t??(r.__t=r.nodeValue))&&(r.__t=t,r.nodeValue=`${t}`)}function vt(r,e){return Oe(r,e)}function Tt(r,e){ae(),e.intro=e.intro??!1;const t=e.target,i=I,o=Y;try{for(var a=Ge(t);a&&(a.nodeType!==Re||a.data!==Ke);)a=et(a);if(!a)throw ne;W(!0),K(a);const h=Oe(r,{...e,anchor:a});return W(!1),h}catch(h){if(h instanceof Error&&h.message.split(` -`).some(_=>_.startsWith("https://svelte.dev/e/")))throw h;return h!==ne&&console.warn("Failed to hydrate: ",h),e.recover===!1&&tt(),ae(),rt(t),W(!1),vt(r,e)}finally{W(i),K(o)}}const U=new Map;function Oe(r,{target:e,anchor:t,props:i={},events:o,context:a,intro:h=!0,transformError:_}){ae();var l=void 0,c=st(()=>{var H=t??e.appendChild(Te());ct(H,{pending:()=>{}},v=>{at({});var u=Se;if(a&&(u.c=a),o&&(i.$$events=o),I&&ot(v,null),l=r(v,i)||{},I&&(P.nodes.end=Y,Y===null||Y.nodeType!==Re||Y.data!==nt))throw ht(),ne;ft()},_);var $=new Set,N=v=>{for(var u=0;u{var O;for(var v of $)for(const m of[e,document]){var u=U.get(m),y=u.get(v);--y==0?(m.removeEventListener(v,me),u.delete(v),u.size===0&&U.delete(m)):u.set(v,y)}ve.delete(N),H!==t&&((O=H.parentNode)==null||O.removeChild(H))}});return oe.set(l,c),l}let oe=new WeakMap;function wt(r,e){const t=oe.get(r);return t?(oe.delete(r),t(e)):Promise.resolve()}export{Tt as h,vt as m,Et as s,wt as u}; diff --git a/web/build/_app/immutable/chunks/YzYuob9f.js b/web/build/_app/immutable/chunks/YzYuob9f.js deleted file mode 100644 index 4817e37..0000000 --- a/web/build/_app/immutable/chunks/YzYuob9f.js +++ /dev/null @@ -1 +0,0 @@ -var Xt=t=>{throw TypeError(t)};var Pe=(t,e,n)=>e.has(t)||Xt("Cannot "+n);var w=(t,e,n)=>(Pe(t,e,"read from private field"),n?n.call(t):e.get(t)),A=(t,e,n)=>e.has(t)?Xt("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{aL as T,g as I,e as P,aK as pt,aN as Oe}from"./CUCwB180.js";import{w as jt,o as Qt}from"./DNqN6DmX.js";class Nt{constructor(e,n){this.status=e,typeof n=="string"?this.body={message:n}:n?this.body=n:this.body={message:`Error: ${e}`}}toString(){return JSON.stringify(this.body)}}class Dt{constructor(e,n){this.status=e,this.location=n}}class Vt extends Error{constructor(e,n,r){super(r),this.status=e,this.text=n}}new URL("sveltekit-internal://");function $e(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function Ce(t){return t.split("%25").map(decodeURI).join("%25")}function je(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function Lt({href:t}){return t.split("#")[0]}function Ne(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let a=r.length;for(;a;)e=e*33^r[--a]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function De(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&Y.delete(qt(t)),Ve(t,e));const Y=new Map;function qe(t,e){const n=qt(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:a,...s}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&Y.set(n,{body:a,init:s,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(a=De(a)),Promise.resolve(new Response(a,s))}return window.fetch(t,e)}function Ke(t,e,n){if(Y.size>0){const r=qt(t,n),a=Y.get(r);if(a){if(performance.now(){const a=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(a)return e.push({name:a[1],matcher:a[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const s=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(s)return e.push({name:s[1],matcher:s[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const o=r.split(/\[(.+?)\](?!\])/);return"/"+o.map((l,c)=>{if(c%2){if(l.startsWith("x+"))return Ut(String.fromCharCode(parseInt(l.slice(2),16)));if(l.startsWith("u+"))return Ut(String.fromCharCode(...l.slice(2).split("-").map(_=>parseInt(_,16))));const d=Be.exec(l),[,u,v,f,h]=d;return e.push({name:f,matcher:h,optional:!!u,rest:!!v,chained:v?c===1&&o[0]==="":!1}),v?"([^]*?)":u?"([^/]*)?":"([^/]+?)"}return Ut(l)}).join("")}).join("")}/?$`),params:e}}function Fe(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function Ge(t){return t.slice(1).split("/").filter(Fe)}function We(t,e,n){const r={},a=t.slice(1),s=a.filter(i=>i!==void 0);let o=0;for(let i=0;id).join("/"),o=0),c===void 0)if(l.rest)c="";else continue;if(!l.matcher||n[l.matcher](c)){r[l.name]=c;const d=e[i+1],u=a[i+1];d&&!d.rest&&d.optional&&u&&l.chained&&(o=0),!d&&!u&&Object.keys(r).length===s.length&&(o=0);continue}if(l.optional&&l.chained){o++;continue}return}if(!o)return r}function Ut(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function Ye({nodes:t,server_loads:e,dictionary:n,matchers:r}){const a=new Set(e);return Object.entries(n).map(([i,[l,c,d]])=>{const{pattern:u,params:v}=Me(i),f={id:i,exec:h=>{const _=u.exec(h);if(_)return We(_,v,r)},errors:[1,...d||[]].map(h=>t[h]),layouts:[0,...c||[]].map(o),leaf:s(l)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function s(i){const l=i<0;return l&&(i=~i),[l,t[i]]}function o(i){return i===void 0?i:[a.has(i),t[i]]}}function ue(t,e=JSON.parse){try{return e(sessionStorage[t])}catch{}}function Zt(t,e,n=JSON.stringify){const r=n(e);try{sessionStorage[t]=r}catch{}}var se;const U=((se=globalThis.__sveltekit_1smak34)==null?void 0:se.base)??"";var ie;const ze=((ie=globalThis.__sveltekit_1smak34)==null?void 0:ie.assets)??U??"",He="1773071061170",de="sveltekit:snapshot",he="sveltekit:scroll",pe="sveltekit:states",Je="sveltekit:pageurl",F="sveltekit:history",H="sveltekit:navigation",D={tap:1,hover:2,viewport:3,eager:4,off:-1,false:-1},Et=location.origin;function Kt(t){if(t instanceof URL)return t;let e=document.baseURI;if(!e){const n=document.getElementsByTagName("base");e=n.length?n[0].href:document.URL}return new URL(t,e)}function q(){return{x:pageXOffset,y:pageYOffset}}function M(t,e){return t.getAttribute(`data-sveltekit-${e}`)}const te={...D,"":D.hover};function ge(t){let e=t.assignedSlot??t.parentNode;return(e==null?void 0:e.nodeType)===11&&(e=e.host),e}function me(t,e){for(;t&&t!==e;){if(t.nodeName.toUpperCase()==="A"&&t.hasAttribute("href"))return t;t=ge(t)}}function It(t,e,n){let r;try{if(r=new URL(t instanceof SVGAElement?t.href.baseVal:t.href,document.baseURI),n&&r.hash.match(/^#[^/]/)){const i=location.hash.split("#")[1]||"/";r.hash=`#${i}${r.hash}`}}catch{}const a=t instanceof SVGAElement?t.target.baseVal:t.target,s=!r||!!a||St(r,e,n)||(t.getAttribute("rel")||"").split(/\s+/).includes("external"),o=(r==null?void 0:r.origin)===Et&&t.hasAttribute("download");return{url:r,external:s,target:a,download:o}}function gt(t){let e=null,n=null,r=null,a=null,s=null,o=null,i=t;for(;i&&i!==document.documentElement;)r===null&&(r=M(i,"preload-code")),a===null&&(a=M(i,"preload-data")),e===null&&(e=M(i,"keepfocus")),n===null&&(n=M(i,"noscroll")),s===null&&(s=M(i,"reload")),o===null&&(o=M(i,"replacestate")),i=ge(i);function l(c){switch(c){case"":case"true":return!0;case"off":case"false":return!1;default:return}}return{preload_code:te[r??"off"],preload_data:te[a??"off"],keepfocus:l(e),noscroll:l(n),reload:l(s),replace_state:l(o)}}function ee(t){const e=jt(t);let n=!0;function r(){n=!0,e.update(o=>o)}function a(o){n=!1,e.set(o)}function s(o){let i;return e.subscribe(l=>{(i===void 0||n&&l!==i)&&o(i=l)})}return{notify:r,set:a,subscribe:s}}const _e={v:()=>{}};function Xe(){const{set:t,subscribe:e}=jt(!1);let n;async function r(){clearTimeout(n);try{const a=await fetch(`${ze}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!a.ok)return!1;const o=(await a.json()).version!==He;return o&&(t(!0),_e.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function St(t,e,n){return t.origin!==Et||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function xn(t){}const we=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...we];const Qe=new Set([...we]);[...Qe];function Ze(t){return t.filter(e=>e!=null)}function Bt(t){return t instanceof Nt||t instanceof Vt?t.status:500}function tn(t){return t instanceof Vt?t.text:"Internal Error"}let R,J,At;const en=Qt.toString().includes("$$")||/function \w+\(\) \{\}/.test(Qt.toString());var et,nt,at,rt,ot,st,it,lt,le,ct,ce,ft,fe;en?(R={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},J={current:null},At={current:!1}):(R=new(le=class{constructor(){A(this,et,T({}));A(this,nt,T(null));A(this,at,T(null));A(this,rt,T({}));A(this,ot,T({id:null}));A(this,st,T({}));A(this,it,T(-1));A(this,lt,T(new URL("https://example.com")))}get data(){return I(w(this,et))}set data(e){P(w(this,et),e)}get form(){return I(w(this,nt))}set form(e){P(w(this,nt),e)}get error(){return I(w(this,at))}set error(e){P(w(this,at),e)}get params(){return I(w(this,rt))}set params(e){P(w(this,rt),e)}get route(){return I(w(this,ot))}set route(e){P(w(this,ot),e)}get state(){return I(w(this,st))}set state(e){P(w(this,st),e)}get status(){return I(w(this,it))}set status(e){P(w(this,it),e)}get url(){return I(w(this,lt))}set url(e){P(w(this,lt),e)}},et=new WeakMap,nt=new WeakMap,at=new WeakMap,rt=new WeakMap,ot=new WeakMap,st=new WeakMap,it=new WeakMap,lt=new WeakMap,le),J=new(ce=class{constructor(){A(this,ct,T(null))}get current(){return I(w(this,ct))}set current(e){P(w(this,ct),e)}},ct=new WeakMap,ce),At=new(fe=class{constructor(){A(this,ft,T(!1))}get current(){return I(w(this,ft))}set current(e){P(w(this,ft),e)}},ft=new WeakMap,fe),_e.v=()=>At.current=!0);function nn(t){Object.assign(R,t)}const an=new Set(["icon","shortcut icon","apple-touch-icon"]),j=ue(he)??{},X=ue(de)??{},C={url:ee({}),page:ee({}),navigating:jt(null),updated:Xe()};function Mt(t){j[t]=q()}function rn(t,e){let n=t+1;for(;j[n];)delete j[n],n+=1;for(n=e+1;X[n];)delete X[n],n+=1}function Q(t,e=!1){return e?location.replace(t.href):location.href=t.href,new Promise(()=>{})}async function ve(){if("serviceWorker"in navigator){const t=await navigator.serviceWorker.getRegistration(U||"/");t&&await t.update()}}function ne(){}let Ft,Pt,mt,O,Ot,E;const _t=[],wt=[];let y=null;function $t(){var t;(t=y==null?void 0:y.fork)==null||t.then(e=>e==null?void 0:e.discard()),y=null}const ht=new Map,ye=new Set,on=new Set,z=new Set;let m={branch:[],error:null,url:null},be=!1,vt=!1,ae=!0,Z=!1,W=!1,ke=!1,Gt=!1,Ee,k,L,V;const yt=new Set,re=new Map;async function Tn(t,e,n){var s,o,i,l,c;(s=globalThis.__sveltekit_1smak34)!=null&&s.data&&globalThis.__sveltekit_1smak34.data,document.URL!==location.href&&(location.href=location.href),E=t,await((i=(o=t.hooks).init)==null?void 0:i.call(o)),Ft=Ye(t),O=document.documentElement,Ot=e,Pt=t.nodes[0],mt=t.nodes[1],Pt(),mt(),k=(l=history.state)==null?void 0:l[F],L=(c=history.state)==null?void 0:c[H],k||(k=L=Date.now(),history.replaceState({...history.state,[F]:k,[H]:L},""));const r=j[k];function a(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}n?(a(),await vn(Ot,n)):(await G({type:"enter",url:Kt(E.hash?kn(new URL(location.href)):location.href),replace_state:!0}),a()),wn()}function sn(){_t.length=0,Gt=!1}function Se(t){wt.some(e=>e==null?void 0:e.snapshot)&&(X[t]=wt.map(e=>{var n;return(n=e==null?void 0:e.snapshot)==null?void 0:n.capture()}))}function Re(t){var e;(e=X[t])==null||e.forEach((n,r)=>{var a,s;(s=(a=wt[r])==null?void 0:a.snapshot)==null||s.restore(n)})}function oe(){Mt(k),Zt(he,j),Se(L),Zt(de,X)}async function xe(t,e,n,r){let a;e.invalidateAll&&$t(),await G({type:"goto",url:Kt(t),keepfocus:e.keepFocus,noscroll:e.noScroll,replace_state:e.replaceState,state:e.state,redirect_count:n,nav_token:r,accept:()=>{e.invalidateAll&&(Gt=!0,a=[...re.keys()]),e.invalidate&&e.invalidate.forEach(_n)}}),e.invalidateAll&&pt().then(pt).then(()=>{re.forEach(({resource:s},o)=>{var i;a!=null&&a.includes(o)&&((i=s.refresh)==null||i.call(s))})})}async function ln(t){if(t.id!==(y==null?void 0:y.id)){$t();const e={};yt.add(e),y={id:t.id,token:e,promise:Ue({...t,preload:e}).then(n=>(yt.delete(e),n.type==="loaded"&&n.state.error&&$t(),n)),fork:null}}return y.promise}async function Tt(t){var n;const e=(n=await Rt(t,!1))==null?void 0:n.route;e&&await Promise.all([...e.layouts,e.leaf].filter(Boolean).map(r=>r[1]()))}async function Le(t,e,n){var a;m=t.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(R,t.props.page),Ee=new E.root({target:e,props:{...t.props,stores:C,components:wt},hydrate:n,sync:!1}),await Promise.resolve(),Re(L),n){const s={from:null,to:{params:m.params,route:{id:((a=m.route)==null?void 0:a.id)??null},url:new URL(location.href),scroll:j[k]??q()},willUnload:!1,type:"enter",complete:Promise.resolve()};z.forEach(o=>o(s))}vt=!0}function bt({url:t,params:e,branch:n,status:r,error:a,route:s,form:o}){let i="never";if(U&&(t.pathname===U||t.pathname===U+"/"))i="always";else for(const f of n)(f==null?void 0:f.slash)!==void 0&&(i=f.slash);t.pathname=$e(t.pathname,i),t.search=t.search;const l={type:"loaded",state:{url:t,params:e,branch:n,error:a,route:s},props:{constructors:Ze(n).map(f=>f.node.component),page:Jt(R)}};o!==void 0&&(l.props.form=o);let c={},d=!R,u=0;for(let f=0;fi(new URL(o))))return!0;return!1}function Yt(t,e){return(t==null?void 0:t.type)==="data"?t:(t==null?void 0:t.type)==="skip"?e??null:null}function un(t,e){if(!t)return new Set(e.searchParams.keys());const n=new Set([...t.searchParams.keys(),...e.searchParams.keys()]);for(const r of n){const a=t.searchParams.getAll(r),s=e.searchParams.getAll(r);a.every(o=>s.includes(o))&&s.every(o=>a.includes(o))&&n.delete(r)}return n}function dn({error:t,url:e,route:n,params:r}){return{type:"loaded",state:{error:t,url:e,route:n,params:r,branch:[]},props:{page:Jt(R),constructors:[]}}}async function Ue({id:t,invalidating:e,url:n,params:r,route:a,preload:s}){if((y==null?void 0:y.id)===t)return yt.delete(y.token),y.promise;const{errors:o,layouts:i,leaf:l}=a,c=[...i,l];o.forEach(g=>g==null?void 0:g().catch(()=>{})),c.forEach(g=>g==null?void 0:g[1]().catch(()=>{}));const d=m.url?t!==kt(m.url):!1,u=m.route?a.id!==m.route.id:!1,v=un(m.url,n);let f=!1;const h=c.map(async(g,p)=>{var $;if(!g)return;const b=m.branch[p];return g[1]===(b==null?void 0:b.loader)&&!fn(f,u,d,v,($=b.universal)==null?void 0:$.uses,r)?b:(f=!0,Wt({loader:g[1],url:n,params:r,route:a,parent:async()=>{var ut;const N={};for(let K=0;K{});const _=[];for(let g=0;gPromise.resolve({}),server_data_node:Yt(s)}),i={node:await mt(),loader:mt,universal:null,server:null,data:null};return bt({url:n,params:a,branch:[o,i],status:t,error:e,route:null})}catch(o){if(o instanceof Dt)return xe(new URL(o.location,location.href),{},0);throw o}}async function pn(t){const e=t.href;if(ht.has(e))return ht.get(e);let n;try{const r=(async()=>{let a=await E.hooks.reroute({url:new URL(t),fetch:async(s,o)=>cn(s,o,t).promise})??t;if(typeof a=="string"){const s=new URL(t);E.hash?s.hash=a:s.pathname=a,a=s}return a})();ht.set(e,r),n=await r}catch{ht.delete(e);return}return n}async function Rt(t,e){if(t&&!St(t,U,E.hash)){const n=await pn(t);if(!n)return;const r=gn(n);for(const a of Ft){const s=a.exec(r);if(s)return{id:kt(t),invalidating:e,route:a,params:je(s),url:t}}}}function gn(t){return Ce(E.hash?t.hash.replace(/^#/,"").replace(/[?#].+/,""):t.pathname.slice(U.length))||"/"}function kt(t){return(E.hash?t.hash.replace(/^#/,""):t.pathname)+t.search}function Ae({url:t,type:e,intent:n,delta:r,event:a,scroll:s}){let o=!1;const i=Ht(m,n,t,e,s??null);r!==void 0&&(i.navigation.delta=r),a!==void 0&&(i.navigation.event=a);const l={...i.navigation,cancel:()=>{o=!0,i.reject(new Error("navigation cancelled"))}};return Z||ye.forEach(c=>c(l)),o?null:i}async function G({type:t,url:e,popped:n,keepfocus:r,noscroll:a,replace_state:s,state:o={},redirect_count:i=0,nav_token:l={},accept:c=ne,block:d=ne,event:u}){var K;const v=V;V=l;const f=await Rt(e,!1),h=t==="enter"?Ht(m,f,e,t):Ae({url:e,type:t,delta:n==null?void 0:n.delta,intent:f,scroll:n==null?void 0:n.scroll,event:u});if(!h){d(),V===l&&(V=v);return}const _=k,g=L;c(),Z=!0,vt&&h.navigation.type!=="enter"&&C.navigating.set(J.current=h.navigation);let p=f&&await Ue(f);if(!p){if(St(e,U,E.hash))return await Q(e,s);p=await Te(e,{id:null},await tt(new Vt(404,"Not Found",`Not found: ${e.pathname}`),{url:e,params:{},route:{id:null}}),404,s)}if(e=(f==null?void 0:f.url)||e,V!==l)return h.reject(new Error("navigation aborted")),!1;if(p.type==="redirect"){if(i<20){await G({type:t,url:new URL(p.location,e),popped:n,keepfocus:r,noscroll:a,replace_state:s,state:o,redirect_count:i+1,nav_token:l}),h.fulfil(void 0);return}p=await zt({status:500,error:await tt(new Error("Redirect loop"),{url:e,params:{},route:{id:null}}),url:e,route:{id:null}})}else p.props.page.status>=400&&await C.updated.check()&&(await ve(),await Q(e,s));if(sn(),Mt(_),Se(g),p.props.page.url.pathname!==e.pathname&&(e.pathname=p.props.page.url.pathname),o=n?n.state:o,!n){const S=s?0:1,dt={[F]:k+=S,[H]:L+=S,[pe]:o};(s?history.replaceState:history.pushState).call(history,dt,"",e),s||rn(k,L)}const b=f&&(y==null?void 0:y.id)===f.id?y.fork:null;y=null,p.props.page.state=o;let x;if(vt){const S=(await Promise.all(Array.from(on,B=>B(h.navigation)))).filter(B=>typeof B=="function");if(S.length>0){let B=function(){S.forEach(xt=>{z.delete(xt)})};S.push(B),S.forEach(xt=>{z.add(xt)})}m=p.state,p.props.page&&(p.props.page.url=e);const dt=b&&await b;dt?x=dt.commit():(Ee.$set(p.props),nn(p.props.page),x=(K=Oe)==null?void 0:K()),ke=!0}else await Le(p,Ot,!1);const{activeElement:$}=document;await x,await pt(),await pt();let N=null;if(ae){const S=n?n.scroll:a?q():null;S?scrollTo(S.x,S.y):(N=e.hash&&document.getElementById(Ie(e)))?N.scrollIntoView():scrollTo(0,0)}const ut=document.activeElement!==$&&document.activeElement!==document.body;!r&&!ut&&bn(e,!N),ae=!0,p.props.page&&Object.assign(R,p.props.page),Z=!1,t==="popstate"&&Re(L),h.fulfil(void 0),h.navigation.to&&(h.navigation.to.scroll=q()),z.forEach(S=>S(h.navigation)),C.navigating.set(J.current=null)}async function Te(t,e,n,r,a){return t.origin===Et&&t.pathname===location.pathname&&!be?await zt({status:r,error:n,url:t,route:e}):await Q(t,a)}function mn(){let t,e={element:void 0,href:void 0},n;O.addEventListener("mousemove",i=>{const l=i.target;clearTimeout(t),t=setTimeout(()=>{s(l,D.hover)},20)});function r(i){i.defaultPrevented||s(i.composedPath()[0],D.tap)}O.addEventListener("mousedown",r),O.addEventListener("touchstart",r,{passive:!0});const a=new IntersectionObserver(i=>{for(const l of i)l.isIntersecting&&(Tt(new URL(l.target.href)),a.unobserve(l.target))},{threshold:0});async function s(i,l){const c=me(i,O),d=c===e.element&&(c==null?void 0:c.href)===e.href&&l>=n;if(!c||d)return;const{url:u,external:v,download:f}=It(c,U,E.hash);if(v||f)return;const h=gt(c),_=u&&kt(m.url)===kt(u);if(!(h.reload||_))if(l<=h.preload_data){e={element:c,href:c.href},n=D.tap;const g=await Rt(u,!1);if(!g)return;ln(g)}else l<=h.preload_code&&(e={element:c,href:c.href},n=l,Tt(u))}function o(){a.disconnect();for(const i of O.querySelectorAll("a")){const{url:l,external:c,download:d}=It(i,U,E.hash);if(c||d)continue;const u=gt(i);u.reload||(u.preload_code===D.viewport&&a.observe(i),u.preload_code===D.eager&&Tt(l))}}z.add(o),o()}function tt(t,e){if(t instanceof Nt)return t.body;const n=Bt(t),r=tn(t);return E.hooks.handleError({error:t,event:e,status:n,message:r})??{message:r}}function In(t,e={}){return t=new URL(Kt(t)),t.origin!==Et?Promise.reject(new Error("goto: invalid URL")):xe(t,e,0)}function _n(t){if(typeof t=="function")_t.push(t);else{const{href:e}=new URL(t,location.href);_t.push(n=>n.href===e)}}function wn(){var e;history.scrollRestoration="manual",addEventListener("beforeunload",n=>{let r=!1;if(oe(),!Z){const a=Ht(m,void 0,null,"leave"),s={...a.navigation,cancel:()=>{r=!0,a.reject(new Error("navigation cancelled"))}};ye.forEach(o=>o(s))}r?(n.preventDefault(),n.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&oe()}),(e=navigator.connection)!=null&&e.saveData||mn(),O.addEventListener("click",async n=>{if(n.button||n.which!==1||n.metaKey||n.ctrlKey||n.shiftKey||n.altKey||n.defaultPrevented)return;const r=me(n.composedPath()[0],O);if(!r)return;const{url:a,external:s,target:o,download:i}=It(r,U,E.hash);if(!a)return;if(o==="_parent"||o==="_top"){if(window.parent!==window)return}else if(o&&o!=="_self")return;const l=gt(r);if(!(r instanceof SVGAElement)&&a.protocol!==location.protocol&&!(a.protocol==="https:"||a.protocol==="http:")||i)return;const[d,u]=(E.hash?a.hash.replace(/^#/,""):a.href).split("#"),v=d===Lt(location);if(s||l.reload&&(!v||!u)){Ae({url:a,type:"link",event:n})?Z=!0:n.preventDefault();return}if(u!==void 0&&v){const[,f]=m.url.href.split("#");if(f===u){if(n.preventDefault(),u===""||u==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const h=r.ownerDocument.getElementById(decodeURIComponent(u));h&&(h.scrollIntoView(),h.focus())}return}if(W=!0,Mt(k),t(a),!l.replace_state)return;W=!1}n.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await G({type:"link",url:a,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??a.href===location.href,event:n})}),O.addEventListener("submit",n=>{if(n.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(n.target),a=n.submitter;if(((a==null?void 0:a.formTarget)||r.target)==="_blank"||((a==null?void 0:a.formMethod)||r.method)!=="get")return;const i=new URL((a==null?void 0:a.hasAttribute("formaction"))&&(a==null?void 0:a.formAction)||r.action);if(St(i,U,!1))return;const l=n.target,c=gt(l);if(c.reload)return;n.preventDefault(),n.stopPropagation();const d=new FormData(l,a);i.search=new URLSearchParams(d).toString(),G({type:"form",url:i,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??i.href===location.href,event:n})}),addEventListener("popstate",async n=>{var r;if(!Ct){if((r=n.state)!=null&&r[F]){const a=n.state[F];if(V={},a===k)return;const s=j[a],o=n.state[pe]??{},i=new URL(n.state[Je]??location.href),l=n.state[H],c=m.url?Lt(location)===Lt(m.url):!1;if(l===L&&(ke||c)){o!==R.state&&(R.state=o),t(i),j[k]=q(),s&&scrollTo(s.x,s.y),k=a;return}const u=a-k;await G({type:"popstate",url:i,popped:{state:o,scroll:s,delta:u},accept:()=>{k=a,L=l},block:()=>{history.go(-u)},nav_token:V,event:n})}else if(!W){const a=new URL(location.href);t(a),E.hash&&location.reload()}}}),addEventListener("hashchange",()=>{W&&(W=!1,history.replaceState({...history.state,[F]:++k,[H]:L},"",location.href))});for(const n of document.querySelectorAll("link"))an.has(n.rel)&&(n.href=n.href);addEventListener("pageshow",n=>{n.persisted&&C.navigating.set(J.current=null)});function t(n){m.url=R.url=n,C.page.set(Jt(R)),C.page.notify()}}async function vn(t,{status:e=200,error:n,node_ids:r,params:a,route:s,server_route:o,data:i,form:l}){be=!0;const c=new URL(location.href);let d;({params:a={},route:s={id:null}}=await Rt(c,!1)||{}),d=Ft.find(({id:f})=>f===s.id);let u,v=!0;try{const f=r.map(async(_,g)=>{const p=i[g];return p!=null&&p.uses&&(p.uses=yn(p.uses)),Wt({loader:E.nodes[_],url:c,params:a,route:s,parent:async()=>{const b={};for(let x=0;x{const i=history.state;Ct=!0,location.replace(new URL(`#${r}`,location.href)),history.replaceState(i,"",t),e&&scrollTo(s,o),Ct=!1})}else{const s=document.body,o=s.getAttribute("tabindex");s.tabIndex=-1,s.focus({preventScroll:!0,focusVisible:!1}),o!==null?s.setAttribute("tabindex",o):s.removeAttribute("tabindex")}const a=getSelection();if(a&&a.type!=="None"){const s=[];for(let o=0;o{if(a.rangeCount===s.length){for(let o=0;o{s=u,o=v});return i.catch(()=>{}),{navigation:{from:{params:t.params,route:{id:((c=t.route)==null?void 0:c.id)??null},url:t.url,scroll:q()},to:n&&{params:(e==null?void 0:e.params)??null,route:{id:((d=e==null?void 0:e.route)==null?void 0:d.id)??null},url:n,scroll:a},willUnload:!e,type:r,complete:i},fulfil:s,reject:o}}function Jt(t){return{data:t.data,error:t.error,form:t.form,params:t.params,route:t.route,state:t.state,status:t.status,url:t.url}}function kn(t){const e=new URL(t);return e.hash=decodeURIComponent(t.hash),e}function Ie(t){let e;if(E.hash){const[,,n]=t.hash.split("#",3);e=n??""}else e=t.hash.slice(1);return decodeURIComponent(e)}export{Tn as a,In as g,xn as l,R as p,C as s}; diff --git a/web/build/_app/immutable/chunks/eiK12uJk.js b/web/build/_app/immutable/chunks/eiK12uJk.js deleted file mode 100644 index 3980c58..0000000 --- a/web/build/_app/immutable/chunks/eiK12uJk.js +++ /dev/null @@ -1 +0,0 @@ -import{h as d,u as g,i as c,j as m,k as l,l as b,g as p,o as h,q as k}from"./CUCwB180.js";function x(n=!1){const s=d,e=s.l.u;if(!e)return;let r=()=>h(s.s);if(n){let o=0,t={};const _=k(()=>{let i=!1;const a=s.s;for(const f in a)a[f]!==t[f]&&(t[f]=a[f],i=!0);return i&&o++,o});r=()=>p(_)}e.b.length&&g(()=>{u(s,r),l(e.b)}),c(()=>{const o=m(()=>e.m.map(b));return()=>{for(const t of o)typeof t=="function"&&t()}}),e.a.length&&c(()=>{u(s,r),l(e.a)})}function u(n,s){if(n.l.s)for(const e of n.l.s)p(e);s()}export{x as i}; diff --git a/web/build/_app/immutable/chunks/pTMRHjpX.js b/web/build/_app/immutable/chunks/pTMRHjpX.js deleted file mode 100644 index 2a6b109..0000000 --- a/web/build/_app/immutable/chunks/pTMRHjpX.js +++ /dev/null @@ -1 +0,0 @@ -import{x as h,y as d,z as _,A as l,B as p,T as E,C as g,D as u,E as s,R as y,F as x,G as A,H as M,I as N}from"./CUCwB180.js";var f;const i=((f=globalThis==null?void 0:globalThis.window)==null?void 0:f.trustedTypes)&&globalThis.window.trustedTypes.createPolicy("svelte-trusted-html",{createHTML:t=>t});function b(t){return(i==null?void 0:i.createHTML(t))??t}function L(t){var r=h("template");return r.innerHTML=b(t.replaceAll("","")),r.content}function n(t,r){var e=_;e.nodes===null&&(e.nodes={start:t,end:r,a:null,t:null})}function w(t,r){var e=(r&E)!==0,c=(r&g)!==0,a,m=!t.startsWith("");return()=>{if(u)return n(s,null),s;a===void 0&&(a=L(m?t:""+t),e||(a=l(a)));var o=c||p?document.importNode(a,!0):a.cloneNode(!0);if(e){var T=l(o),v=o.lastChild;n(T,v)}else n(o,o);return o}}function C(t=""){if(!u){var r=d(t+"");return n(r,r),r}var e=s;return e.nodeType!==A?(e.before(e=d()),M(e)):N(e),n(e,e),e}function D(){if(u)return n(s,null),s;var t=document.createDocumentFragment(),r=document.createComment(""),e=d();return t.append(r,e),n(r,e),t}function H(t,r){if(u){var e=_;((e.f&y)===0||e.nodes.end===null)&&(e.nodes.end=s),x();return}t!==null&&t.before(r)}export{H as a,n as b,D as c,w as f,C as t}; diff --git a/web/build/_app/immutable/entry/app.H3SWXino.js b/web/build/_app/immutable/entry/app.H3SWXino.js deleted file mode 100644 index a1fa41e..0000000 --- a/web/build/_app/immutable/entry/app.H3SWXino.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.D7-FTC_1.js","../chunks/Bzak7iHL.js","../chunks/CAYgxOZ1.js","../chunks/CUCwB180.js","../chunks/DNqN6DmX.js","../chunks/C5YqYP7P.js","../chunks/pTMRHjpX.js","../chunks/eiK12uJk.js","../chunks/YzYuob9f.js","../chunks/CGowzvwH.js","../nodes/1.BZR9od8C.js","../chunks/Db9w--lA.js","../nodes/2.Zg4cVoEY.js","../nodes/3.BjNotmmr.js","../nodes/4.D0WiVz9B.js","../nodes/5.B-zruxZU.js","../nodes/6.Cniq5yLG.js","../nodes/7.BjdHyPf8.js","../nodes/8.Chqc1uyl.js"])))=>i.map(i=>d[i]); -var be=Object.defineProperty;var $=t=>{throw TypeError(t)};var Re=(t,e,r)=>e in t?be(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var ee=(t,e,r)=>Re(t,typeof e!="symbol"?e+"":e,r),te=(t,e,r)=>e.has(t)||$("Cannot "+r);var a=(t,e,r)=>(te(t,e,"read from private field"),r?r.call(t):e.get(t)),O=(t,e,r)=>e.has(t)?$("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),M=(t,e,r,i)=>(te(t,e,"write to private field"),i?i.call(t,r):e.set(t,r),r);import{as as Se,a7 as Y,V as Ae,y as re,U as se,W as Oe,D as C,E as Z,X as Ie,at as Te,F as ie,S as oe,ae as ce,au as fe,a8 as ue,H as le,al as U,ai as we,av as Le,M as De,j as de,P as pe,aw as he,ax as ke,ay as xe,az as Ce,g as b,aA as Ve,e as x,aB as je,z as Be,aC as Me,aD as Fe,K as Ue,aE as qe,aF as Ne,q as Ye,aG as ze,aH as He,aI as _e,aJ as Ge,d as Ke,m as We,p as Je,u as Xe,i as Ze,aK as Qe,f as F,s as $e,a as et,aL as z,c as tt,r as rt,t as st,aM as H}from"../chunks/CUCwB180.js";import{h as at,m as nt,u as it,s as ot}from"../chunks/Db9w--lA.js";import"../chunks/Bzak7iHL.js";import{o as ct}from"../chunks/DNqN6DmX.js";import{a as p,f as me,c as G,t as ft}from"../chunks/pTMRHjpX.js";import{c as ut}from"../chunks/C5YqYP7P.js";var S,I,P,D,V,j,q;class ve{constructor(e,r=!0){ee(this,"anchor");O(this,S,new Map);O(this,I,new Map);O(this,P,new Map);O(this,D,new Set);O(this,V,!0);O(this,j,e=>{if(a(this,S).has(e)){var r=a(this,S).get(e),i=a(this,I).get(r);if(i)Se(i),a(this,D).delete(r);else{var c=a(this,P).get(r);c&&(a(this,I).set(r,c.effect),a(this,P).delete(r),c.fragment.lastChild.remove(),this.anchor.before(c.fragment),i=c.effect)}for(const[n,o]of a(this,S)){if(a(this,S).delete(n),n===e)break;const s=a(this,P).get(o);s&&(Y(s.effect),a(this,P).delete(o))}for(const[n,o]of a(this,I)){if(n===r||a(this,D).has(n))continue;const s=()=>{if(Array.from(a(this,S).values()).includes(n)){var h=document.createDocumentFragment();Ie(o,h),h.append(re()),a(this,P).set(n,{effect:o,fragment:h})}else Y(o);a(this,D).delete(n),a(this,I).delete(n)};a(this,V)||!i?(a(this,D).add(n),Ae(o,s,!1)):s()}}});O(this,q,e=>{a(this,S).delete(e);const r=Array.from(a(this,S).values());for(const[i,c]of a(this,P))r.includes(i)||(Y(c.effect),a(this,P).delete(i))});this.anchor=e,M(this,V,r)}ensure(e,r){var i=Oe,c=Te();if(r&&!a(this,I).has(e)&&!a(this,P).has(e))if(c){var n=document.createDocumentFragment(),o=re();n.append(o),a(this,P).set(e,{effect:se(()=>r(o)),fragment:n})}else a(this,I).set(e,se(()=>r(this.anchor)));if(a(this,S).set(i,e),c){for(const[s,f]of a(this,I))s===e?i.unskip_effect(f):i.skip_effect(f);for(const[s,f]of a(this,P))s===e?i.unskip_effect(f.effect):i.skip_effect(f.effect);i.oncommit(a(this,j)),i.ondiscard(a(this,q))}else C&&(this.anchor=Z),a(this,j).call(this,i)}}S=new WeakMap,I=new WeakMap,P=new WeakMap,D=new WeakMap,V=new WeakMap,j=new WeakMap,q=new WeakMap;function K(t,e,r=!1){var i;C&&(i=Z,ie());var c=new ve(t),n=r?ce:0;function o(s,f){if(C){var h=fe(i);if(s!==parseInt(h.substring(1))){var u=ue();le(u),c.anchor=u,U(!1),c.ensure(s,f),U(!0);return}}c.ensure(s,f)}oe(()=>{var s=!1;e((f,h=0)=>{s=!0,o(h,f)}),s||o(-1,null)},n)}function W(t,e,r){var i;C&&(i=Z,ie());var c=new ve(t);oe(()=>{var n=e()??null;if(C){var o=fe(i),s=o===we,f=n!==null;if(s!==f){var h=ue();le(h),c.anchor=h,U(!1),c.ensure(n,n&&(u=>r(u,n))),U(!0);return}}c.ensure(n,n&&(u=>r(u,n)))},ce)}function ae(t,e){return t===e||(t==null?void 0:t[he])===e}function J(t={},e,r,i){return Le(()=>{var c,n;return De(()=>{c=n,n=[],de(()=>{t!==r(...n)&&(e(t,...n),c&&ae(r(...c),t)&&e(null,...c))})}),()=>{pe(()=>{n&&ae(r(...n),t)&&e(null,...n)})}}),t}function X(t,e,r,i){var A;var c=!Ue||(r&qe)!==0,n=(r&Fe)!==0,o=(r&He)!==0,s=i,f=!0,h=()=>(f&&(f=!1,s=o?de(i):i),s);let u;if(n){var R=he in t||_e in t;u=((A=ke(t,e))==null?void 0:A.set)??(R&&e in t?l=>t[e]=l:void 0)}var g,k=!1;n?[g,k]=ut(()=>t[e]):g=t[e],g===void 0&&i!==void 0&&(g=h(),u&&(c&&xe(),u(g)));var _;if(c?_=()=>{var l=t[e];return l===void 0?h():(f=!0,l)}:_=()=>{var l=t[e];return l!==void 0&&(s=void 0),l===void 0?s:l},c&&(r&Ce)===0)return _;if(u){var d=t.$$legacy;return(function(l,v){return arguments.length>0?((!c||!v||d||k)&&u(v?_():l),l):_()})}var m=!1,E=((r&Ne)!==0?Ye:ze)(()=>(m=!1,_()));n&&b(E);var L=Be;return(function(l,v){if(arguments.length>0){const N=v?b(E):c&&n?Ve(l):l;return x(E,N),m=!0,s!==void 0&&(s=N),l}return je&&m||(L.f&Me)!==0?E.v:b(E)})}function lt(t){return class extends dt{constructor(e){super({component:t,...e})}}}var w,y;class dt{constructor(e){O(this,w);O(this,y);var n;var r=new Map,i=(o,s)=>{var f=We(s,!1,!1);return r.set(o,f),f};const c=new Proxy({...e.props||{},$$events:{}},{get(o,s){return b(r.get(s)??i(s,Reflect.get(o,s)))},has(o,s){return s===_e?!0:(b(r.get(s)??i(s,Reflect.get(o,s))),Reflect.has(o,s))},set(o,s,f){return x(r.get(s)??i(s,f),f),Reflect.set(o,s,f)}});M(this,y,(e.hydrate?at:nt)(e.component,{target:e.target,anchor:e.anchor,props:c,context:e.context,intro:e.intro??!1,recover:e.recover,transformError:e.transformError})),(!((n=e==null?void 0:e.props)!=null&&n.$$host)||e.sync===!1)&&Ge(),M(this,w,c.$$events);for(const o of Object.keys(a(this,y)))o==="$set"||o==="$destroy"||o==="$on"||Ke(this,o,{get(){return a(this,y)[o]},set(s){a(this,y)[o]=s},enumerable:!0});a(this,y).$set=o=>{Object.assign(c,o)},a(this,y).$destroy=()=>{it(a(this,y))}}$set(e){a(this,y).$set(e)}$on(e,r){a(this,w)[e]=a(this,w)[e]||[];const i=(...c)=>r.call(this,...c);return a(this,w)[e].push(i),()=>{a(this,w)[e]=a(this,w)[e].filter(c=>c!==i)}}$destroy(){a(this,y).$destroy()}}w=new WeakMap,y=new WeakMap;const ht="modulepreload",_t=function(t,e){return new URL(t,e).href},ne={},T=function(e,r,i){let c=Promise.resolve();if(r&&r.length>0){let o=function(u){return Promise.all(u.map(R=>Promise.resolve(R).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};const s=document.getElementsByTagName("link"),f=document.querySelector("meta[property=csp-nonce]"),h=(f==null?void 0:f.nonce)||(f==null?void 0:f.getAttribute("nonce"));c=o(r.map(u=>{if(u=_t(u,i),u in ne)return;ne[u]=!0;const R=u.endsWith(".css"),g=R?'[rel="stylesheet"]':"";if(!!i)for(let d=s.length-1;d>=0;d--){const m=s[d];if(m.href===u&&(!R||m.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${g}`))return;const _=document.createElement("link");if(_.rel=R?"stylesheet":ht,R||(_.as="script"),_.crossOrigin="",_.href=u,h&&_.setAttribute("nonce",h),document.head.appendChild(_),R)return new Promise((d,m)=>{_.addEventListener("load",d),_.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${u}`)))})}))}function n(o){const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=o,window.dispatchEvent(s),!s.defaultPrevented)throw o}return c.then(o=>{for(const s of o||[])s.status==="rejected"&&n(s.reason);return e().catch(n)})},It={};var mt=me('
'),vt=me(" ",1);function gt(t,e){Je(e,!0);let r=X(e,"components",23,()=>[]),i=X(e,"data_0",3,null),c=X(e,"data_1",3,null);Xe(()=>e.stores.page.set(e.page)),Ze(()=>{e.stores,e.page,e.constructors,r(),e.form,i(),c(),e.stores.page.notify()});let n=z(!1),o=z(!1),s=z(null);ct(()=>{const d=e.stores.page.subscribe(()=>{b(n)&&(x(o,!0),Qe().then(()=>{x(s,document.title||"untitled page",!0)}))});return x(n,!0),d});const f=H(()=>e.constructors[1]);var h=vt(),u=F(h);{var R=d=>{const m=H(()=>e.constructors[0]);var E=G(),L=F(E);W(L,()=>b(m),(A,l)=>{J(l(A,{get data(){return i()},get form(){return e.form},get params(){return e.page.params},children:(v,N)=>{var Q=G(),Ee=F(Q);W(Ee,()=>b(f),(Pe,ye)=>{J(ye(Pe,{get data(){return c()},get form(){return e.form},get params(){return e.page.params}}),B=>r()[1]=B,()=>{var B;return(B=r())==null?void 0:B[1]})}),p(v,Q)},$$slots:{default:!0}}),v=>r()[0]=v,()=>{var v;return(v=r())==null?void 0:v[0]})}),p(d,E)},g=d=>{const m=H(()=>e.constructors[0]);var E=G(),L=F(E);W(L,()=>b(m),(A,l)=>{J(l(A,{get data(){return i()},get form(){return e.form},get params(){return e.page.params}}),v=>r()[0]=v,()=>{var v;return(v=r())==null?void 0:v[0]})}),p(d,E)};K(u,d=>{e.constructors[1]?d(R):d(g,-1)})}var k=$e(u,2);{var _=d=>{var m=mt(),E=tt(m);{var L=A=>{var l=ft();st(()=>ot(l,b(s))),p(A,l)};K(E,A=>{b(o)&&A(L)})}rt(m),p(d,m)};K(k,d=>{b(n)&&d(_)})}p(t,h),et()}const Tt=lt(gt),wt=[()=>T(()=>import("../nodes/0.D7-FTC_1.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]),import.meta.url),()=>T(()=>import("../nodes/1.BZR9od8C.js"),__vite__mapDeps([10,1,2,3,11,6,7,8,4]),import.meta.url),()=>T(()=>import("../nodes/2.Zg4cVoEY.js"),__vite__mapDeps([12,1,2,3,4,7,8]),import.meta.url),()=>T(()=>import("../nodes/3.BjNotmmr.js"),__vite__mapDeps([13,1,2,3,6]),import.meta.url),()=>T(()=>import("../nodes/4.D0WiVz9B.js"),__vite__mapDeps([14,1,2,3,5,4,11,6,7,9,8]),import.meta.url),()=>T(()=>import("../nodes/5.B-zruxZU.js"),__vite__mapDeps([15,1,2,3,6]),import.meta.url),()=>T(()=>import("../nodes/6.Cniq5yLG.js"),__vite__mapDeps([16,1,2,3,5,4,11,6,7,9,8]),import.meta.url),()=>T(()=>import("../nodes/7.BjdHyPf8.js"),__vite__mapDeps([17,1,2,3,5,4,11,6,7,9,8]),import.meta.url),()=>T(()=>import("../nodes/8.Chqc1uyl.js"),__vite__mapDeps([18,1,2,3,6]),import.meta.url)],Lt=[],Dt={"/":[2],"/characters":[3],"/characters/[id]":[4],"/groups":[5],"/groups/[id]":[6],"/groups/[id]/settings":[7],"/login":[8]},ge={handleError:(({error:t})=>{console.error(t)}),reroute:(()=>{}),transport:{}},Et=Object.fromEntries(Object.entries(ge.transport).map(([t,e])=>[t,e.decode])),pt=Object.fromEntries(Object.entries(ge.transport).map(([t,e])=>[t,e.encode])),kt=!1,xt=(t,e)=>Et[t](e);export{xt as decode,Et as decoders,Dt as dictionary,pt as encoders,kt as hash,ge as hooks,It as matchers,wt as nodes,Tt as root,Lt as server_loads}; diff --git a/web/build/_app/immutable/entry/start.Pj34kLt-.js b/web/build/_app/immutable/entry/start.Pj34kLt-.js deleted file mode 100644 index 625288f..0000000 --- a/web/build/_app/immutable/entry/start.Pj34kLt-.js +++ /dev/null @@ -1 +0,0 @@ -import{l as o,a as r}from"../chunks/YzYuob9f.js";export{o as load_css,r as start}; diff --git a/web/build/_app/immutable/nodes/0.D7-FTC_1.js b/web/build/_app/immutable/nodes/0.D7-FTC_1.js deleted file mode 100644 index 40cc3ca..0000000 --- a/web/build/_app/immutable/nodes/0.D7-FTC_1.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{o as h}from"../chunks/DNqN6DmX.js";import{D as m,F as g,p as y,f as T,a as $}from"../chunks/CUCwB180.js";import{s as _,a as k}from"../chunks/C5YqYP7P.js";import{c as v,a as w}from"../chunks/pTMRHjpX.js";import{i as A}from"../chunks/eiK12uJk.js";import{g as u}from"../chunks/YzYuob9f.js";import{p as O}from"../chunks/CGowzvwH.js";function S(t,e,a,n,o){var f;m&&g();var s=(f=e.$$slots)==null?void 0:f[a],r=!1;s===!0&&(s=e.children,r=!0),s===void 0||s(t,r?()=>n:n)}const d="https://api.campaign-manager.example.com/v1";let i=null;function E(t){i=t}async function P(){const t=await fetch(`${d}/auth/refresh`,{method:"POST",credentials:"include"});return t.ok?(i=(await t.json()).accessToken,!0):(i=null,!1)}async function c(t,e={}){const{skipAuth:a=!1,...n}=e,o=new Headers(n.headers);!a&&i&&o.set("Authorization",`Bearer ${i}`),n.body&&!o.has("Content-Type")&&o.set("Content-Type","application/json");let s=await fetch(`${d}${t}`,{...n,headers:o,credentials:"include"});return s.status===401&&!a&&await P()&&i&&(o.set("Authorization",`Bearer ${i}`),s=await fetch(`${d}${t}`,{...n,headers:o,credentials:"include"})),s}const B={get:(t,e)=>c(t,{...e,method:"GET"}),post:(t,e,a)=>c(t,{...a,method:"POST",body:e?JSON.stringify(e):void 0}),put:(t,e,a)=>c(t,{...a,method:"PUT",body:e?JSON.stringify(e):void 0}),patch:(t,e,a)=>c(t,{...a,method:"PATCH",body:e?JSON.stringify(e):void 0}),delete:(t,e)=>c(t,{...e,method:"DELETE"})};function z(t,e){y(e,!1);const a=()=>k(O,"$page",n),[n,o]=_(),s=["/login"];h(async()=>{if(!s.includes(a().url.pathname))try{const l=await B.post("/auth/refresh",void 0,{skipAuth:!0});if(l.ok){const p=await l.json();E(p.accessToken)}else u("/login")}catch{u("/login")}}),A();var r=v(),f=T(r);S(f,e,"default",{}),w(t,r),$(),o()}export{z as component}; diff --git a/web/build/_app/immutable/nodes/1.BZR9od8C.js b/web/build/_app/immutable/nodes/1.BZR9od8C.js deleted file mode 100644 index 8973ffd..0000000 --- a/web/build/_app/immutable/nodes/1.BZR9od8C.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{p as h,f as g,t as l,a as v,c as e,r as o,s as d}from"../chunks/CUCwB180.js";import{s as p}from"../chunks/Db9w--lA.js";import{a as _,f as x}from"../chunks/pTMRHjpX.js";import{i as $}from"../chunks/eiK12uJk.js";import{s as k,p as m}from"../chunks/YzYuob9f.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const i=b;var E=x("

",1);function C(f,c){h(c,!1),$();var t=E(),r=g(t),n=e(r,!0);o(r);var s=d(r,2),u=e(s,!0);o(s),l(()=>{var a;p(n,i.status),p(u,(a=i.error)==null?void 0:a.message)}),_(f,t),v()}export{C as component}; diff --git a/web/build/_app/immutable/nodes/2.Zg4cVoEY.js b/web/build/_app/immutable/nodes/2.Zg4cVoEY.js deleted file mode 100644 index 21157b7..0000000 --- a/web/build/_app/immutable/nodes/2.Zg4cVoEY.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{o as p}from"../chunks/DNqN6DmX.js";import{p as r,a as t}from"../chunks/CUCwB180.js";import{i as m}from"../chunks/eiK12uJk.js";import{g as a}from"../chunks/YzYuob9f.js";function c(i,o){r(o,!1),p(()=>a("/groups")),m(),t()}export{c as component}; diff --git a/web/build/_app/immutable/nodes/3.BjNotmmr.js b/web/build/_app/immutable/nodes/3.BjNotmmr.js deleted file mode 100644 index 2dd2666..0000000 --- a/web/build/_app/immutable/nodes/3.BjNotmmr.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{a,f as t}from"../chunks/pTMRHjpX.js";var p=t("

Your Characters

");function n(o){var r=p();a(o,r)}export{n as component}; diff --git a/web/build/_app/immutable/nodes/4.D0WiVz9B.js b/web/build/_app/immutable/nodes/4.D0WiVz9B.js deleted file mode 100644 index acc7bfb..0000000 --- a/web/build/_app/immutable/nodes/4.D0WiVz9B.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{p as i,s as f,f as c,t as n,a as h,c as g,r as l}from"../chunks/CUCwB180.js";import{s as _,a as $}from"../chunks/C5YqYP7P.js";import{s as d}from"../chunks/Db9w--lA.js";import{a as u,f as v}from"../chunks/pTMRHjpX.js";import{i as x}from"../chunks/eiK12uJk.js";import{p as C}from"../chunks/CGowzvwH.js";var b=v("

Character Sheet

",1);function z(r,s){i(s,!1);const e=()=>$(C,"$page",p),[p,o]=_();x();var a=b(),t=f(c(a),2),m=g(t);l(t),n(()=>d(m,`Character ID: ${e().params.id??""}`)),u(r,a),h(),o()}export{z as component}; diff --git a/web/build/_app/immutable/nodes/5.B-zruxZU.js b/web/build/_app/immutable/nodes/5.B-zruxZU.js deleted file mode 100644 index 45a0b81..0000000 --- a/web/build/_app/immutable/nodes/5.B-zruxZU.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{a as p,f as a}from"../chunks/pTMRHjpX.js";var t=a("

Your Groups

");function f(o){var r=t();p(o,r)}export{f as component}; diff --git a/web/build/_app/immutable/nodes/6.Cniq5yLG.js b/web/build/_app/immutable/nodes/6.Cniq5yLG.js deleted file mode 100644 index ec08bd4..0000000 --- a/web/build/_app/immutable/nodes/6.Cniq5yLG.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{p as i,s as f,f as n,t as c,a as l,c as g,r as _}from"../chunks/CUCwB180.js";import{s as $,a as h}from"../chunks/C5YqYP7P.js";import{s as u}from"../chunks/Db9w--lA.js";import{a as d,f as v}from"../chunks/pTMRHjpX.js";import{i as x}from"../chunks/eiK12uJk.js";import{p as D}from"../chunks/CGowzvwH.js";var G=v("

Group Detail

",1);function A(s,r){i(r,!1);const p=()=>h(D,"$page",o),[o,e]=$();x();var a=G(),t=f(n(a),2),m=g(t);_(t),c(()=>u(m,`Group ID: ${p().params.id??""}`)),d(s,a),l(),e()}export{A as component}; diff --git a/web/build/_app/immutable/nodes/7.BjdHyPf8.js b/web/build/_app/immutable/nodes/7.BjdHyPf8.js deleted file mode 100644 index 1d3ad95..0000000 --- a/web/build/_app/immutable/nodes/7.BjdHyPf8.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{p as i,s as f,f as n,t as c,a as g,c as l,r as _}from"../chunks/CUCwB180.js";import{s as $,a as h}from"../chunks/C5YqYP7P.js";import{s as u}from"../chunks/Db9w--lA.js";import{a as d,f as v}from"../chunks/pTMRHjpX.js";import{i as x}from"../chunks/eiK12uJk.js";import{p as G}from"../chunks/CGowzvwH.js";var b=v("

Group Settings

",1);function z(a,r){i(r,!1);const p=()=>h(G,"$page",o),[o,e]=$();x();var t=b(),s=f(n(t),2),m=l(s);_(s),c(()=>u(m,`Group ID: ${p().params.id??""}`)),d(a,t),g(),e()}export{z as component}; diff --git a/web/build/_app/immutable/nodes/8.Chqc1uyl.js b/web/build/_app/immutable/nodes/8.Chqc1uyl.js deleted file mode 100644 index bd2e00d..0000000 --- a/web/build/_app/immutable/nodes/8.Chqc1uyl.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/Bzak7iHL.js";import"../chunks/CAYgxOZ1.js";import{v as r}from"../chunks/CUCwB180.js";import{a as m,f as n}from"../chunks/pTMRHjpX.js";var p=n("

Campaign Manager

Login — coming soon

",1);function g(o){var a=p();r(2),m(o,a)}export{g as component}; diff --git a/web/build/_app/version.json b/web/build/_app/version.json deleted file mode 100644 index 61edd9c..0000000 --- a/web/build/_app/version.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"1773071061170"} \ No newline at end of file diff --git a/web/package.json b/web/package.json index ce1e2a8..20d73c4 100644 --- a/web/package.json +++ b/web/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "vite dev", "build": "vite build", - "preview": "vite preview" + "preview": "node build", + "start": "node build" }, "dependencies": { "@sveltejs/kit": "^2.0.0", @@ -14,7 +15,7 @@ "@campaign-manager/rulesets": "workspace:*" }, "devDependencies": { - "@sveltejs/adapter-static": "^3.0.0", + "@sveltejs/adapter-node": "^5.5.4", "@sveltejs/vite-plugin-svelte": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0" diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 9c8fa4d..459c745 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -1,4 +1,6 @@ -export const BASE_URL = 'https://api.campaign-manager.example.com/v1'; +const CAMPAIGN_BASE_URL = '/api/campaign'; +const CONTENT_BASE_URL = '/api/content'; +const AUTH_BASE_URL = '/api/auth'; // Access token held in memory only — never persisted to localStorage let _accessToken: string | null = null; @@ -15,9 +17,14 @@ interface RequestOptions extends RequestInit { skipAuth?: boolean; } +function joinUrl(base: string, path: string): string { + if (!path) return base; + return `${base}${path.startsWith('/') ? path : `/${path}`}`; +} + async function silentRefresh(): Promise { // Refresh token is in an HttpOnly cookie; no manual credential needed - const res = await fetch(`${BASE_URL}/auth/refresh`, { + const res = await fetch(joinUrl(AUTH_BASE_URL, '/refresh'), { method: 'POST', credentials: 'include', }); @@ -32,7 +39,7 @@ async function silentRefresh(): Promise { return true; } -async function apiFetch(path: string, options: RequestOptions = {}): Promise { +async function apiFetch(baseUrl: string, path: string, options: RequestOptions = {}): Promise { const { skipAuth = false, ...fetchOptions } = options; const headers = new Headers(fetchOptions.headers); @@ -44,7 +51,9 @@ async function apiFetch(path: string, options: RequestOptions = {}): Promise - apiFetch(path, { ...options, method: 'GET' }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'GET' }), post: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), put: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), patch: (path: string, body?: unknown, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), delete: (path: string, options?: RequestOptions) => - apiFetch(path, { ...options, method: 'DELETE' }), + apiFetch(CAMPAIGN_BASE_URL, path, { ...options, method: 'DELETE' }), +}; + +export const contentApi = { + get: (path: string, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'GET' }), + + post: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), + + put: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'PUT', body: body ? JSON.stringify(body) : undefined }), + + patch: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'PATCH', body: body ? JSON.stringify(body) : undefined }), + + delete: (path: string, options?: RequestOptions) => + apiFetch(CONTENT_BASE_URL, path, { ...options, method: 'DELETE' }), +}; + +export const authApi = { + post: (path: string, body?: unknown, options?: RequestOptions) => + apiFetch(AUTH_BASE_URL, path, { ...options, method: 'POST', body: body ? JSON.stringify(body) : undefined }), }; diff --git a/web/src/lib/server/proxy.ts b/web/src/lib/server/proxy.ts new file mode 100644 index 0000000..1af547c --- /dev/null +++ b/web/src/lib/server/proxy.ts @@ -0,0 +1,79 @@ +import { error } from '@sveltejs/kit'; +import type { RequestEvent } from '@sveltejs/kit'; + +const FORWARDED_RESPONSE_HEADERS = new Set([ + 'cache-control', + 'content-type', + 'etag', + 'last-modified', + 'set-cookie', + 'vary', + 'www-authenticate', +]); + +function resolveBaseUrl(raw: string | undefined, name: string): string { + if (!raw) { + throw error(500, `${name} is not configured`); + } + + return raw.replace(/\/+$/, ''); +} + +function buildTargetUrl(baseUrl: string, path: string | undefined, search: string): string { + const normalizedPath = path ? `/${path}` : ''; + return `${baseUrl}${normalizedPath}${search}`; +} + +function copyRequestHeaders(headers: Headers): Headers { + const forwarded = new Headers(); + + for (const [key, value] of headers.entries()) { + const lowered = key.toLowerCase(); + if (lowered === 'host') continue; + if (lowered === 'content-length') continue; + forwarded.set(key, value); + } + + return forwarded; +} + +function copyResponseHeaders(headers: Headers): Headers { + const forwarded = new Headers(); + + for (const [key, value] of headers.entries()) { + if (FORWARDED_RESPONSE_HEADERS.has(key.toLowerCase())) { + forwarded.append(key, value); + } + } + + return forwarded; +} + +export async function proxyToService( + event: RequestEvent, + rawBaseUrl: string | undefined, + baseName: string, +): Promise { + const baseUrl = resolveBaseUrl(rawBaseUrl, baseName); + const url = new URL(event.request.url); + const targetUrl = buildTargetUrl(baseUrl, event.params.path, url.search); + + const init: RequestInit = { + method: event.request.method, + headers: copyRequestHeaders(event.request.headers), + redirect: 'manual', + }; + + if (!['GET', 'HEAD'].includes(event.request.method.toUpperCase())) { + init.body = await event.request.arrayBuffer(); + } + + const upstream = await fetch(targetUrl, init); + const headers = copyResponseHeaders(upstream.headers); + + return new Response(upstream.body, { + status: upstream.status, + statusText: upstream.statusText, + headers, + }); +} diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index c4cb838..cad003f 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -2,7 +2,7 @@ import { onMount } from 'svelte'; import { goto } from '$app/navigation'; import { page } from '$app/stores'; - import { api, setAccessToken } from '$lib/api'; + import { authApi, setAccessToken } from '$lib/api'; const PUBLIC_ROUTES = ['/login']; @@ -11,7 +11,7 @@ // Attempt silent token refresh via HttpOnly cookie before rendering try { - const res = await api.post('/auth/refresh', undefined, { skipAuth: true }); + const res = await authApi.post('/refresh', undefined, { skipAuth: true }); if (res.ok) { const data = await res.json() as { accessToken: string }; setAccessToken(data.accessToken); diff --git a/web/src/routes/api/auth/[...path]/+server.ts b/web/src/routes/api/auth/[...path]/+server.ts new file mode 100644 index 0000000..3122a00 --- /dev/null +++ b/web/src/routes/api/auth/[...path]/+server.ts @@ -0,0 +1,19 @@ +import { env } from '$env/dynamic/private'; +import { proxyToService } from '$lib/server/proxy'; +import type { RequestHandler } from './$types'; + +const CAMPAIGN_BASE = env.CAMPAIGN_API_BASE || 'http://localhost:3000/v1'; + +const handler: RequestHandler = (event) => + proxyToService( + event, + `${CAMPAIGN_BASE.replace(/\/+$/, '')}/auth`, + 'CAMPAIGN_API_BASE', + ); + +export const GET = handler; +export const POST = handler; +export const PUT = handler; +export const PATCH = handler; +export const DELETE = handler; +export const OPTIONS = handler; diff --git a/web/src/routes/api/campaign/[...path]/+server.ts b/web/src/routes/api/campaign/[...path]/+server.ts new file mode 100644 index 0000000..04b1e4d --- /dev/null +++ b/web/src/routes/api/campaign/[...path]/+server.ts @@ -0,0 +1,15 @@ +import { env } from '$env/dynamic/private'; +import { proxyToService } from '$lib/server/proxy'; +import type { RequestHandler } from './$types'; + +const CAMPAIGN_BASE = env.CAMPAIGN_API_BASE || 'http://localhost:3000/v1'; + +const handler: RequestHandler = (event) => + proxyToService(event, CAMPAIGN_BASE, 'CAMPAIGN_API_BASE'); + +export const GET = handler; +export const POST = handler; +export const PUT = handler; +export const PATCH = handler; +export const DELETE = handler; +export const OPTIONS = handler; diff --git a/web/src/routes/api/content/[...path]/+server.ts b/web/src/routes/api/content/[...path]/+server.ts new file mode 100644 index 0000000..002ee4c --- /dev/null +++ b/web/src/routes/api/content/[...path]/+server.ts @@ -0,0 +1,15 @@ +import { env } from '$env/dynamic/private'; +import { proxyToService } from '$lib/server/proxy'; +import type { RequestHandler } from './$types'; + +const CONTENT_BASE = env.CONTENT_API_BASE || 'http://localhost:3001/v1'; + +const handler: RequestHandler = (event) => + proxyToService(event, CONTENT_BASE, 'CONTENT_API_BASE'); + +export const GET = handler; +export const POST = handler; +export const PUT = handler; +export const PATCH = handler; +export const DELETE = handler; +export const OPTIONS = handler; diff --git a/web/svelte.config.js b/web/svelte.config.js index 41b4a3a..5dd3727 100644 --- a/web/svelte.config.js +++ b/web/svelte.config.js @@ -1,8 +1,8 @@ -import adapter from '@sveltejs/adapter-static'; +import adapter from '@sveltejs/adapter-node'; /** @type {import('@sveltejs/kit').Config} */ export default { kit: { - adapter: adapter({ fallback: '404.html' }), + adapter: adapter(), }, };