clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

Merge pull request #36 from FelineStateMachine/agent/deno-local-first-starter

FelineStateMachine committed 170728b
Recast the reference app as a generic minimal local-first starter; publish @nzip/lofi to JSR on tag
commit
170728bd1c3a46a90e7e51abb0f44f76a8509deb
parent
0559efb261e75b743f2fee4d9b866e979d81fc75
parent
5fd31784493f3dfd1bfc208192827dbe7f5f8b57
author
FelineStateMachine <dami.etoile@gmail.com>
72 files changed, +3784 -3830
A.github/workflows/publish.yml36+
Mapps/reference/README.md15+-
Aapps/reference/deno.json52+
Aapps/reference/deno.lock3131++++++++++++++++++++++++++++++
Mapps/reference/public/manifest.webmanifest4+-
Rapps/reference/src/_lofi/ReferenceShell.astro → apps/reference/src/_lofi/Shell.astro0
Aapps/reference/src/_lofi/diagnostics.ts39+
Mapps/reference/src/_lofi/runtime.ts61+-
Rapps/reference/src/_lofi/checklist-store.ts → apps/reference/src/_lofi/table-store.ts122+-
Rapps/reference/src/_lofi/checklist-store_test.ts → apps/reference/src/_lofi/table-store_test.ts71+-
Dapps/reference/src/_lofi/use-checklist.ts63-
Mapps/reference/src/app.ts4+-
Mapps/reference/src/env.d.ts3+
Dapps/reference/src/islands/ChecklistIsland.tsx135-
Aapps/reference/src/islands/TaskList.tsx63+
Aapps/reference/src/islands/use-tasks.ts74+
Dapps/reference/src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts28-
Dapps/reference/src/migrations/snapshots/20260715T194819-6c62fec42c35.json20-
Dapps/reference/src/migrations/snapshots/20260715T194947-ff85ac1d97ee.json27-
Mapps/reference/src/pages/index.astro23+-
Mapps/reference/src/permissions.ts2+-
Mapps/reference/src/styles/global.css42+-
Dapps/reference/src/ui-contract.ts10-
Mapps/reference/tests/author-boundary_test.ts2+-
Aapps/reference/tests/convergence_e2e_test.ts109+
Mdeno.json47+-
Ddocs/decisions/0001-jazz2-alpha53-baseline.md63-
Ddocs/decisions/0002-graduate-thin-preact-adapter.md33-
Ddocs/decisions/0003-use-static-astro-through-deno.md29-
Ddocs/decisions/0004-reject-alpha53-passkey-backup.md37-
Ddocs/decisions/0005-publish-one-nzip-lofi-package.md38-
Ddocs/decisions/0006-bound-layer3-inspection-and-testing.md80-
Ddocs/decisions/README.md20-
Ddocs/m2-abstraction-leaks.md24-
Rinit.md → docs/seed.md0
Rspikes/astro-deno/evidence/2026-07-15.md → docs/spikes/astro-deno/evidence/2026-07-15.md0
Rspikes/identity/evidence/2026-07-15.md → docs/spikes/identity/evidence/2026-07-15.md0
Rspikes/jazz2-baseline/README.md → docs/spikes/jazz2-baseline/README.md0
Rspikes/jazz2-baseline/evidence/2026-07-15.md → docs/spikes/jazz2-baseline/evidence/2026-07-15.md0
Rspikes/jazz2-baseline/index.html → docs/spikes/jazz2-baseline/index.html0
Rspikes/jazz2-baseline/permissions.ts → docs/spikes/jazz2-baseline/permissions.ts0
Rspikes/jazz2-baseline/schema.ts → docs/spikes/jazz2-baseline/schema.ts0
Rspikes/jazz2-baseline/src/import-meta.d.ts → docs/spikes/jazz2-baseline/src/import-meta.d.ts0
Rspikes/jazz2-baseline/src/main.ts → docs/spikes/jazz2-baseline/src/main.ts0
Rspikes/jazz2-baseline/src/style.css → docs/spikes/jazz2-baseline/src/style.css0
Rspikes/jazz2-baseline/vite.config.ts → docs/spikes/jazz2-baseline/vite.config.ts0
Rspikes/opfs-device/device-checklist.md → docs/spikes/opfs-device/device-checklist.md0
Rspikes/opfs-device/evidence/2026-07-15.md → docs/spikes/opfs-device/evidence/2026-07-15.md0
Rspikes/preact-integration/compat-control/index.html → docs/spikes/preact-integration/compat-control/index.html0
Rspikes/preact-integration/compat-control/src.tsx → docs/spikes/preact-integration/compat-control/src.tsx0
Rspikes/preact-integration/compat-control/vite.config.ts → docs/spikes/preact-integration/compat-control/vite.config.ts0
Rspikes/preact-integration/evidence/2026-07-15.md → docs/spikes/preact-integration/evidence/2026-07-15.md0
Djsr.json33-
Doutput/playwright/jazz2-alpha53-cloud-second-client.pngbin
Doutput/playwright/jazz2-alpha53-local-offline-multitab.pngbin
Dpackage/commands/check.ts47-
Mpackage/create_core.ts100+-
Mpackage/create_core_test.ts6+-
Mpackage/starter_template.ts46+-
Mpackage/testdata/starter.snapshot.json36+-
Dpackage/tooling/environment_test.ts22-
Mpackage/tooling/project.ts6+-
Dtools/check_env.ts21-
Dtools/check_migrations.ts161--
Dtools/check_secret_leaks.ts40-
Dtools/golden_path.ts1220------------
Dtools/golden_path_checkout.ts18-
Dtools/golden_path_core.ts707-------
Dtools/golden_path_core_test.ts340---
Dtools/golden_path_create.ts79-
Dtools/run_jazz2_spike.ts49-
Dtools/run_reference.ts176--
A .github/workflows/publish.yml +36 -0
M apps/reference/README.md +12 -3
@@ -25,9 +25,18 @@ runtime-owned files without turning them into public framework APIs. M4 may repl
2525 with proven `@nzip/lofi` subpath imports without changing product UI.2626 2727 Browser journeys import readiness, offline, two-client, and sanitized failure-artifact helpers from28-`@nzip/lofi/testing`. The normal `deno task test` verifies that generated projects resolve this29-surface without launching Chromium; real browser and cloud-convergence journeys remain explicit30-developer-run gates.28+`@nzip/lofi/testing`. `tests/convergence_e2e_test.ts` is a worked example: two clients add a task29+offline and converge after reconnecting. The normal `deno task test` skips it (and never launches30+Chromium); run it against a synced deployment with31+`LOFI_E2E_BASE_URL=http://127.0.0.1:4321/ deno test -A tests/convergence_e2e_test.ts`.32+33+`deno task build` produces a self-contained static PWA in `dist/` (the Preact islands compile to34+`dist/_astro/*.js`); `deno task preview` serves it locally.35+`deno task deploy:create --org <org>36+--app <app>` hosts it on Deno Deploy as a static site and37+`deno task deploy` pushes updates — both push the built `dist/` as the deploy root (nothing to build38+remotely, and no `src/app.ts` misdetection). These are generic, org/app-free scaffolding; releasing39+the `@nzip/lofi` package itself is a separate JSR publish (repo root), not a site deploy.3140 3241 Passkey backup and recovery are intentionally absent. The pinned Jazz alpha exposes a rejected3342 credential design, so this reference uses a device-local identity and does not imply recoverability.
A apps/reference/deno.json +52 -0
@@ -0,0 +1,52 @@
1+{2+ "imports": {3+ "@astrojs/check": "npm:@astrojs/check@0.9.9",4+ "@astrojs/preact": "npm:@astrojs/preact@6.0.1",5+ "@nzip/lofi/": "../../package/",6+ "@nzip/lofi/build": "../../package/commands/build.ts",7+ "@nzip/lofi/dev": "../../package/commands/dev.ts",8+ "@nzip/lofi/doctor": "../../package/commands/doctor.ts",9+ "@nzip/lofi/preview": "../../package/commands/preview.ts",10+ "@nzip/lofi/test": "../../package/commands/run_tests.ts",11+ "@nzip/lofi/testing": "../../package/testing/mod.ts",12+ "astro": "npm:astro@7.0.9",13+ "astro/config": "npm:astro@7.0.9/config",14+ "jazz-tools": "npm:jazz-tools@2.0.0-alpha.53",15+ "jazz-tools/dev/vite": "npm:jazz-tools@2.0.0-alpha.53/dev/vite",16+ "preact": "npm:preact@10.29.7",17+ "preact/hooks": "npm:preact@10.29.7/hooks",18+ "preact/jsx-dev-runtime": "npm:preact@10.29.7/jsx-dev-runtime",19+ "preact/jsx-runtime": "npm:preact@10.29.7/jsx-runtime",20+ "typescript": "npm:typescript@6.0.3",21+ "vite": "npm:vite@8.0.1"22+ },23+ "nodeModulesDir": "auto",24+ "compilerOptions": {25+ "lib": ["deno.ns", "dom", "dom.iterable", "esnext"],26+ "jsx": "react-jsx",27+ "jsxImportSource": "preact"28+ },29+ "tasks": {30+ "dev": "deno run -A @nzip/lofi/dev",31+ "doctor": "deno run -A @nzip/lofi/doctor",32+ "test": "deno run -A @nzip/lofi/test",33+ "build": "deno run -A @nzip/lofi/build",34+ "preview": "deno run -A @nzip/lofi/preview",35+ "deploy": "deno task build && deno deploy --prod dist",36+ "deploy:create": "deno task build && deno deploy create dist --source local --do-not-use-detected-build-config --runtime-mode static --static-dir . --region us",37+ "schema:validate": "deno run -A npm:jazz-tools@2.0.0-alpha.53 validate",38+ "schema:deploy": "deno run --env-file=.env -A npm:jazz-tools@2.0.0-alpha.53 deploy --migrations-dir src/migrations",39+ "migrations:create": "deno run -A npm:jazz-tools@2.0.0-alpha.53 migrations create --migrations-dir src/migrations",40+ "migrations:push": "deno run --env-file=.env -A npm:jazz-tools@2.0.0-alpha.53 migrations push --migrations-dir src/migrations"41+ },42+ "fmt": {43+ "lineWidth": 100,44+ "semiColons": true,45+ "singleQuote": false46+ },47+ "lint": {48+ "rules": {49+ "tags": ["recommended"]50+ }51+ }52+}
A apps/reference/deno.lock +3131 -0
@@ -0,0 +1,3131 @@
1+{2+ "version": "5",3+ "specifiers": {4+ "npm:@astrojs/check@0.9.9": "0.9.9_typescript@6.0.3",5+ "npm:@astrojs/preact@6.0.1": "6.0.1_preact@10.29.7__preact-render-to-string@6.7.0_@babel+core@7.29.7",6+ "npm:astro@7.0.9": "7.0.9_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1",7+ "npm:jazz-tools@2.0.0-alpha.53": "2.0.0-alpha.53",8+ "npm:preact@10.29.7": "10.29.7_preact-render-to-string@6.7.0",9+ "npm:typescript@6.0.3": "6.0.3",10+ "npm:vite@8.0.1": "8.0.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1"11+ },12+ "npm": {13+ "@astrojs/check@0.9.9_typescript@6.0.3": {14+ "integrity": "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg==",15+ "dependencies": [16+ "@astrojs/language-server",17+ "chokidar@4.0.3",18+ "kleur",19+ "typescript",20+ "yargs"21+ ],22+ "bin": true23+ },24+ "@astrojs/compiler-binding-darwin-arm64@0.3.1": {25+ "integrity": "sha512-IEmEF2fUIlTHtpeE/isyEGVOB14cEyh/LZOFYt6wn3jNyVpdC8aR5OZ+RzFUR/f+8ZDM1LaMwZKvoA7eMyJeFw==",26+ "os": ["darwin"],27+ "cpu": ["arm64"]28+ },29+ "@astrojs/compiler-binding-darwin-x64@0.3.1": {30+ "integrity": "sha512-GF2kIxjpPDLsn94zbZNMsxEmkU828QqnmM7kiQJnaooS3jmI+I7kk6+oI6EpwOsK3femCMdcm+wmOsEqtGrmjQ==",31+ "os": ["darwin"],32+ "cpu": ["x64"]33+ },34+ "@astrojs/compiler-binding-linux-arm64-gnu@0.3.1": {35+ "integrity": "sha512-XJL3SDmOtVrqFhCirNcHwE91+IesJqlgNo23I4qW9QUYfwzm/TBZuH61fgqsb1ttgR1mMYz6ooPWs0JDhwMqpQ==",36+ "os": ["linux"],37+ "cpu": ["arm64"]38+ },39+ "@astrojs/compiler-binding-linux-arm64-musl@0.3.1": {40+ "integrity": "sha512-xqE8BVbDoBueK/B47w30PtkVofUWJKGkwoMVE+EOMLf11rnoANxIAdA9FPqY+rng4oNI5ndHGsri1yPj2k8vZQ==",41+ "os": ["linux"],42+ "cpu": ["arm64"]43+ },44+ "@astrojs/compiler-binding-linux-x64-gnu@0.3.1": {45+ "integrity": "sha512-1y0StU1qiCuDFH3rmbRJXcxdfHxFPrES1Rd+RLffosvUR7I2cH5SF5SFnBN9vXpzpkmyElZm3Yr47iJBPN7vVA==",46+ "os": ["linux"],47+ "cpu": ["x64"]48+ },49+ "@astrojs/compiler-binding-linux-x64-musl@0.3.1": {50+ "integrity": "sha512-16q0fYf7kpbmdObZEeZJEup8hQv/whgNwVjrSvT8umrKwLDSnNIWiQpm09lQQu6bweZB0XyIvHwlPitvJhC+hg==",51+ "os": ["linux"],52+ "cpu": ["x64"]53+ },54+ "@astrojs/compiler-binding-wasm32-wasi@0.3.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {55+ "integrity": "sha512-cB456shIwDv/PrVT+2QG7LFndpHkVge5HjqADKZgGaAc9JHVktCtjSrcdkRQ+3tbkPazNKaTLRjXLIiz2NIx9g==",56+ "dependencies": [57+ "@napi-rs/wasm-runtime"58+ ],59+ "cpu": ["wasm32"]60+ },61+ "@astrojs/compiler-binding-win32-arm64-msvc@0.3.1": {62+ "integrity": "sha512-ur/9+If/yTE69mmeX5MqSZndL0HOyx67GeNZUy3N7wVdWpLz9UTJXwyWS4UR2PUQHitghjsM5xoX0Ge56WRVQQ==",63+ "os": ["win32"],64+ "cpu": ["arm64"]65+ },66+ "@astrojs/compiler-binding-win32-x64-msvc@0.3.1": {67+ "integrity": "sha512-k0W+kDBzDkNZOqu4kElDvCOIbKw5Ut9S1WZ1Krj3KTgNuBERNKXsMMsRLLcbgfdMdbe7bTekQLshZrrvmYpmwA==",68+ "os": ["win32"],69+ "cpu": ["x64"]70+ },71+ "@astrojs/compiler-binding@0.3.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {72+ "integrity": "sha512-DaAUj29AIBU2XdJ8uwcab8lW5O2pk9pY8AXkcMw0sw77nVa3oeTYRcO+Dvbbpoexf6ThMc0FMWYCQ/wN1/T7oQ==",73+ "optionalDependencies": [74+ "@astrojs/compiler-binding-darwin-arm64",75+ "@astrojs/compiler-binding-darwin-x64",76+ "@astrojs/compiler-binding-linux-arm64-gnu",77+ "@astrojs/compiler-binding-linux-arm64-musl",78+ "@astrojs/compiler-binding-linux-x64-gnu",79+ "@astrojs/compiler-binding-linux-x64-musl",80+ "@astrojs/compiler-binding-wasm32-wasi",81+ "@astrojs/compiler-binding-win32-arm64-msvc",82+ "@astrojs/compiler-binding-win32-x64-msvc"83+ ]84+ },85+ "@astrojs/compiler-rs@0.3.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {86+ "integrity": "sha512-aT7xkgsbNoS6nriY5qKpbihK43slFHO41iqgHCTdOvn1ifaQxLCc5yXy+6GzAtiafoaC1zA7OwVXCXMsvUZOkg==",87+ "dependencies": [88+ "@astrojs/compiler-binding"89+ ]90+ },91+ "@astrojs/compiler@2.13.1": {92+ "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="93+ },94+ "@astrojs/internal-helpers@0.10.1": {95+ "integrity": "sha512-5phcroT/vmOOrYuuAxtkbPixy5hePtlz9i8K4OeDv3dNK6/UQRuXPOSRTxIOBbUY5Sonw2UaxjbuVc43Mcir6Q==",96+ "dependencies": [97+ "@types/hast",98+ "@types/mdast",99+ "js-yaml",100+ "picomatch@4.0.5",101+ "retext-smartypants",102+ "shiki",103+ "smol-toml",104+ "unified"105+ ]106+ },107+ "@astrojs/language-server@2.16.12_typescript@6.0.3": {108+ "integrity": "sha512-3LpFphBCzveUgm5ZVDINB/v3YA4TgPa1EMOEFn3Zt/Ww6jojR25iN+kmzeUz7v/b9xkmq+hMACTX4hizN3VCEQ==",109+ "dependencies": [110+ "@astrojs/compiler",111+ "@astrojs/yaml2ts",112+ "@jridgewell/sourcemap-codec",113+ "@volar/kit",114+ "@volar/language-core",115+ "@volar/language-server",116+ "@volar/language-service",117+ "muggle-string",118+ "tinyglobby",119+ "volar-service-css",120+ "volar-service-emmet",121+ "volar-service-html",122+ "volar-service-prettier",123+ "volar-service-typescript",124+ "volar-service-typescript-twoslash-queries",125+ "volar-service-yaml",126+ "vscode-html-languageservice",127+ "vscode-uri"128+ ],129+ "bin": true130+ },131+ "@astrojs/markdown-satteri@0.3.4": {132+ "integrity": "sha512-6Lvt/bQZEBW+zzdhPblvfZEy5PGEYJaUsUqaCgwHeRPxZJL1gc9I+DRLKWJjjYTWDzVUTzXlMq4WwSK+X34CVw==",133+ "dependencies": [134+ "@astrojs/internal-helpers",135+ "@astrojs/prism",136+ "github-slugger",137+ "hast-util-from-html",138+ "satteri"139+ ]140+ },141+ "@astrojs/preact@6.0.1_preact@10.29.7__preact-render-to-string@6.7.0_@babel+core@7.29.7": {142+ "integrity": "sha512-jZgBe87lfaG1rmv4jQkeVmCmVX5WISHJyVaG9GjvqmgLSmSyd0EVXrflSMPBrKcNlQENYDBMk+q2g/5qfdREEg==",143+ "dependencies": [144+ "@astrojs/internal-helpers",145+ "@preact/preset-vite",146+ "@preact/signals",147+ "devalue",148+ "preact",149+ "preact-render-to-string",150+ "vite@8.1.4_esbuild@0.28.1"151+ ]152+ },153+ "@astrojs/prism@4.0.2": {154+ "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==",155+ "dependencies": [156+ "prismjs"157+ ]158+ },159+ "@astrojs/telemetry@3.3.3": {160+ "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==",161+ "dependencies": [162+ "ci-info",163+ "dset",164+ "is-docker",165+ "package-manager-detector"166+ ]167+ },168+ "@astrojs/yaml2ts@0.2.4": {169+ "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==",170+ "dependencies": [171+ "yaml"172+ ]173+ },174+ "@babel/code-frame@7.29.7": {175+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",176+ "dependencies": [177+ "@babel/helper-validator-identifier",178+ "js-tokens",179+ "picocolors"180+ ]181+ },182+ "@babel/compat-data@7.29.7": {183+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="184+ },185+ "@babel/core@7.29.7": {186+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",187+ "dependencies": [188+ "@babel/code-frame",189+ "@babel/generator",190+ "@babel/helper-compilation-targets",191+ "@babel/helper-module-transforms",192+ "@babel/helpers",193+ "@babel/parser",194+ "@babel/template",195+ "@babel/traverse",196+ "@babel/types",197+ "@jridgewell/remapping",198+ "convert-source-map",199+ "debug",200+ "gensync",201+ "json5",202+ "semver@6.3.1"203+ ]204+ },205+ "@babel/generator@7.29.7": {206+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",207+ "dependencies": [208+ "@babel/parser",209+ "@babel/types",210+ "@jridgewell/gen-mapping",211+ "@jridgewell/trace-mapping",212+ "jsesc"213+ ]214+ },215+ "@babel/helper-annotate-as-pure@7.29.7": {216+ "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==",217+ "dependencies": [218+ "@babel/types"219+ ]220+ },221+ "@babel/helper-compilation-targets@7.29.7": {222+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",223+ "dependencies": [224+ "@babel/compat-data",225+ "@babel/helper-validator-option",226+ "browserslist",227+ "lru-cache@5.1.1",228+ "semver@6.3.1"229+ ]230+ },231+ "@babel/helper-globals@7.29.7": {232+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="233+ },234+ "@babel/helper-module-imports@7.29.7": {235+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",236+ "dependencies": [237+ "@babel/traverse",238+ "@babel/types"239+ ]240+ },241+ "@babel/helper-module-transforms@7.29.7_@babel+core@7.29.7": {242+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",243+ "dependencies": [244+ "@babel/core",245+ "@babel/helper-module-imports",246+ "@babel/helper-validator-identifier",247+ "@babel/traverse"248+ ]249+ },250+ "@babel/helper-plugin-utils@7.29.7": {251+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="252+ },253+ "@babel/helper-string-parser@7.29.7": {254+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="255+ },256+ "@babel/helper-validator-identifier@7.29.7": {257+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="258+ },259+ "@babel/helper-validator-option@7.29.7": {260+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="261+ },262+ "@babel/helpers@7.29.7": {263+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",264+ "dependencies": [265+ "@babel/template",266+ "@babel/types"267+ ]268+ },269+ "@babel/parser@7.29.7": {270+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",271+ "dependencies": [272+ "@babel/types"273+ ],274+ "bin": true275+ },276+ "@babel/plugin-syntax-jsx@7.29.7_@babel+core@7.29.7": {277+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",278+ "dependencies": [279+ "@babel/core",280+ "@babel/helper-plugin-utils"281+ ]282+ },283+ "@babel/plugin-transform-react-jsx-development@7.29.7_@babel+core@7.29.7": {284+ "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==",285+ "dependencies": [286+ "@babel/core",287+ "@babel/plugin-transform-react-jsx"288+ ]289+ },290+ "@babel/plugin-transform-react-jsx@7.29.7_@babel+core@7.29.7": {291+ "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==",292+ "dependencies": [293+ "@babel/core",294+ "@babel/helper-annotate-as-pure",295+ "@babel/helper-module-imports",296+ "@babel/helper-plugin-utils",297+ "@babel/plugin-syntax-jsx",298+ "@babel/types"299+ ]300+ },301+ "@babel/runtime@7.29.7": {302+ "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="303+ },304+ "@babel/template@7.29.7": {305+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",306+ "dependencies": [307+ "@babel/code-frame",308+ "@babel/parser",309+ "@babel/types"310+ ]311+ },312+ "@babel/traverse@7.29.7": {313+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",314+ "dependencies": [315+ "@babel/code-frame",316+ "@babel/generator",317+ "@babel/helper-globals",318+ "@babel/parser",319+ "@babel/template",320+ "@babel/types",321+ "debug"322+ ]323+ },324+ "@babel/types@7.29.7": {325+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",326+ "dependencies": [327+ "@babel/helper-string-parser",328+ "@babel/helper-validator-identifier"329+ ]330+ },331+ "@bruits/satteri-darwin-arm64@0.9.5": {332+ "integrity": "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==",333+ "os": ["darwin"],334+ "cpu": ["arm64"]335+ },336+ "@bruits/satteri-darwin-x64@0.9.5": {337+ "integrity": "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==",338+ "os": ["darwin"],339+ "cpu": ["x64"]340+ },341+ "@bruits/satteri-linux-arm64-gnu@0.9.5": {342+ "integrity": "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==",343+ "os": ["linux"],344+ "cpu": ["arm64"]345+ },346+ "@bruits/satteri-linux-arm64-musl@0.9.5": {347+ "integrity": "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==",348+ "os": ["linux"],349+ "cpu": ["arm64"]350+ },351+ "@bruits/satteri-linux-x64-gnu@0.9.5": {352+ "integrity": "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==",353+ "os": ["linux"],354+ "cpu": ["x64"]355+ },356+ "@bruits/satteri-linux-x64-musl@0.9.5": {357+ "integrity": "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==",358+ "os": ["linux"],359+ "cpu": ["x64"]360+ },361+ "@bruits/satteri-wasm32-wasi@0.9.5": {362+ "integrity": "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==",363+ "dependencies": [364+ "@emnapi/core",365+ "@emnapi/runtime",366+ "@napi-rs/wasm-runtime"367+ ],368+ "cpu": ["wasm32"]369+ },370+ "@bruits/satteri-win32-arm64-msvc@0.9.5": {371+ "integrity": "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==",372+ "os": ["win32"],373+ "cpu": ["arm64"]374+ },375+ "@bruits/satteri-win32-x64-msvc@0.9.5": {376+ "integrity": "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==",377+ "os": ["win32"],378+ "cpu": ["x64"]379+ },380+ "@capsizecss/unpack@4.0.1": {381+ "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==",382+ "dependencies": [383+ "fontkitten"384+ ]385+ },386+ "@clack/core@1.4.3": {387+ "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==",388+ "dependencies": [389+ "fast-wrap-ansi",390+ "sisteransi"391+ ]392+ },393+ "@clack/prompts@1.7.0": {394+ "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==",395+ "dependencies": [396+ "@clack/core",397+ "fast-string-width",398+ "fast-wrap-ansi",399+ "sisteransi"400+ ]401+ },402+ "@emmetio/abbreviation@2.3.3": {403+ "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==",404+ "dependencies": [405+ "@emmetio/scanner"406+ ]407+ },408+ "@emmetio/css-abbreviation@2.1.8": {409+ "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==",410+ "dependencies": [411+ "@emmetio/scanner"412+ ]413+ },414+ "@emmetio/css-parser@0.4.1": {415+ "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==",416+ "dependencies": [417+ "@emmetio/stream-reader",418+ "@emmetio/stream-reader-utils"419+ ]420+ },421+ "@emmetio/html-matcher@1.3.0": {422+ "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==",423+ "dependencies": [424+ "@emmetio/scanner"425+ ]426+ },427+ "@emmetio/scanner@1.0.4": {428+ "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="429+ },430+ "@emmetio/stream-reader-utils@0.1.0": {431+ "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="432+ },433+ "@emmetio/stream-reader@2.2.0": {434+ "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="435+ },436+ "@emnapi/core@1.11.1": {437+ "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",438+ "dependencies": [439+ "@emnapi/wasi-threads",440+ "tslib"441+ ]442+ },443+ "@emnapi/runtime@1.11.1": {444+ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",445+ "dependencies": [446+ "tslib"447+ ]448+ },449+ "@emnapi/wasi-threads@1.2.2": {450+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",451+ "dependencies": [452+ "tslib"453+ ]454+ },455+ "@esbuild/aix-ppc64@0.27.7": {456+ "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",457+ "os": ["aix"],458+ "cpu": ["ppc64"]459+ },460+ "@esbuild/aix-ppc64@0.28.1": {461+ "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",462+ "os": ["aix"],463+ "cpu": ["ppc64"]464+ },465+ "@esbuild/android-arm64@0.27.7": {466+ "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",467+ "os": ["android"],468+ "cpu": ["arm64"]469+ },470+ "@esbuild/android-arm64@0.28.1": {471+ "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",472+ "os": ["android"],473+ "cpu": ["arm64"]474+ },475+ "@esbuild/android-arm@0.27.7": {476+ "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",477+ "os": ["android"],478+ "cpu": ["arm"]479+ },480+ "@esbuild/android-arm@0.28.1": {481+ "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",482+ "os": ["android"],483+ "cpu": ["arm"]484+ },485+ "@esbuild/android-x64@0.27.7": {486+ "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",487+ "os": ["android"],488+ "cpu": ["x64"]489+ },490+ "@esbuild/android-x64@0.28.1": {491+ "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",492+ "os": ["android"],493+ "cpu": ["x64"]494+ },495+ "@esbuild/darwin-arm64@0.27.7": {496+ "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",497+ "os": ["darwin"],498+ "cpu": ["arm64"]499+ },500+ "@esbuild/darwin-arm64@0.28.1": {501+ "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",502+ "os": ["darwin"],503+ "cpu": ["arm64"]504+ },505+ "@esbuild/darwin-x64@0.27.7": {506+ "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",507+ "os": ["darwin"],508+ "cpu": ["x64"]509+ },510+ "@esbuild/darwin-x64@0.28.1": {511+ "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",512+ "os": ["darwin"],513+ "cpu": ["x64"]514+ },515+ "@esbuild/freebsd-arm64@0.27.7": {516+ "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",517+ "os": ["freebsd"],518+ "cpu": ["arm64"]519+ },520+ "@esbuild/freebsd-arm64@0.28.1": {521+ "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",522+ "os": ["freebsd"],523+ "cpu": ["arm64"]524+ },525+ "@esbuild/freebsd-x64@0.27.7": {526+ "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",527+ "os": ["freebsd"],528+ "cpu": ["x64"]529+ },530+ "@esbuild/freebsd-x64@0.28.1": {531+ "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",532+ "os": ["freebsd"],533+ "cpu": ["x64"]534+ },535+ "@esbuild/linux-arm64@0.27.7": {536+ "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",537+ "os": ["linux"],538+ "cpu": ["arm64"]539+ },540+ "@esbuild/linux-arm64@0.28.1": {541+ "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",542+ "os": ["linux"],543+ "cpu": ["arm64"]544+ },545+ "@esbuild/linux-arm@0.27.7": {546+ "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",547+ "os": ["linux"],548+ "cpu": ["arm"]549+ },550+ "@esbuild/linux-arm@0.28.1": {551+ "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",552+ "os": ["linux"],553+ "cpu": ["arm"]554+ },555+ "@esbuild/linux-ia32@0.27.7": {556+ "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",557+ "os": ["linux"],558+ "cpu": ["ia32"]559+ },560+ "@esbuild/linux-ia32@0.28.1": {561+ "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",562+ "os": ["linux"],563+ "cpu": ["ia32"]564+ },565+ "@esbuild/linux-loong64@0.27.7": {566+ "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",567+ "os": ["linux"],568+ "cpu": ["loong64"]569+ },570+ "@esbuild/linux-loong64@0.28.1": {571+ "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",572+ "os": ["linux"],573+ "cpu": ["loong64"]574+ },575+ "@esbuild/linux-mips64el@0.27.7": {576+ "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",577+ "os": ["linux"],578+ "cpu": ["mips64el"]579+ },580+ "@esbuild/linux-mips64el@0.28.1": {581+ "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",582+ "os": ["linux"],583+ "cpu": ["mips64el"]584+ },585+ "@esbuild/linux-ppc64@0.27.7": {586+ "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",587+ "os": ["linux"],588+ "cpu": ["ppc64"]589+ },590+ "@esbuild/linux-ppc64@0.28.1": {591+ "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",592+ "os": ["linux"],593+ "cpu": ["ppc64"]594+ },595+ "@esbuild/linux-riscv64@0.27.7": {596+ "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",597+ "os": ["linux"],598+ "cpu": ["riscv64"]599+ },600+ "@esbuild/linux-riscv64@0.28.1": {601+ "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",602+ "os": ["linux"],603+ "cpu": ["riscv64"]604+ },605+ "@esbuild/linux-s390x@0.27.7": {606+ "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",607+ "os": ["linux"],608+ "cpu": ["s390x"]609+ },610+ "@esbuild/linux-s390x@0.28.1": {611+ "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",612+ "os": ["linux"],613+ "cpu": ["s390x"]614+ },615+ "@esbuild/linux-x64@0.27.7": {616+ "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",617+ "os": ["linux"],618+ "cpu": ["x64"]619+ },620+ "@esbuild/linux-x64@0.28.1": {621+ "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",622+ "os": ["linux"],623+ "cpu": ["x64"]624+ },625+ "@esbuild/netbsd-arm64@0.27.7": {626+ "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",627+ "os": ["netbsd"],628+ "cpu": ["arm64"]629+ },630+ "@esbuild/netbsd-arm64@0.28.1": {631+ "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",632+ "os": ["netbsd"],633+ "cpu": ["arm64"]634+ },635+ "@esbuild/netbsd-x64@0.27.7": {636+ "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",637+ "os": ["netbsd"],638+ "cpu": ["x64"]639+ },640+ "@esbuild/netbsd-x64@0.28.1": {641+ "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",642+ "os": ["netbsd"],643+ "cpu": ["x64"]644+ },645+ "@esbuild/openbsd-arm64@0.27.7": {646+ "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",647+ "os": ["openbsd"],648+ "cpu": ["arm64"]649+ },650+ "@esbuild/openbsd-arm64@0.28.1": {651+ "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",652+ "os": ["openbsd"],653+ "cpu": ["arm64"]654+ },655+ "@esbuild/openbsd-x64@0.27.7": {656+ "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",657+ "os": ["openbsd"],658+ "cpu": ["x64"]659+ },660+ "@esbuild/openbsd-x64@0.28.1": {661+ "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",662+ "os": ["openbsd"],663+ "cpu": ["x64"]664+ },665+ "@esbuild/openharmony-arm64@0.27.7": {666+ "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",667+ "os": ["openharmony"],668+ "cpu": ["arm64"]669+ },670+ "@esbuild/openharmony-arm64@0.28.1": {671+ "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",672+ "os": ["openharmony"],673+ "cpu": ["arm64"]674+ },675+ "@esbuild/sunos-x64@0.27.7": {676+ "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",677+ "os": ["sunos"],678+ "cpu": ["x64"]679+ },680+ "@esbuild/sunos-x64@0.28.1": {681+ "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",682+ "os": ["sunos"],683+ "cpu": ["x64"]684+ },685+ "@esbuild/win32-arm64@0.27.7": {686+ "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",687+ "os": ["win32"],688+ "cpu": ["arm64"]689+ },690+ "@esbuild/win32-arm64@0.28.1": {691+ "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",692+ "os": ["win32"],693+ "cpu": ["arm64"]694+ },695+ "@esbuild/win32-ia32@0.27.7": {696+ "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",697+ "os": ["win32"],698+ "cpu": ["ia32"]699+ },700+ "@esbuild/win32-ia32@0.28.1": {701+ "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",702+ "os": ["win32"],703+ "cpu": ["ia32"]704+ },705+ "@esbuild/win32-x64@0.27.7": {706+ "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",707+ "os": ["win32"],708+ "cpu": ["x64"]709+ },710+ "@esbuild/win32-x64@0.28.1": {711+ "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",712+ "os": ["win32"],713+ "cpu": ["x64"]714+ },715+ "@garden-co/jazz-napi-darwin-arm64@2.0.0-alpha.53": {716+ "integrity": "sha512-CqDtWl9+coVdCvMfhA5vQR8ZiqCztLj0QLG9NKg96nqZ/ZTB7Pt4JPT4ipfUf3COtzzkPY5MU6lv5zk92Kdp4Q==",717+ "os": ["darwin"],718+ "cpu": ["arm64"]719+ },720+ "@garden-co/jazz-napi-darwin-x64@2.0.0-alpha.53": {721+ "integrity": "sha512-WpFZq5nBOAuL8chWTSzqqcYfcjki57ngmgN0+TrFHbARNtX+BFl5HepIsHceJaDxV6iid9XWu0lGzBMZ+5osYw==",722+ "os": ["darwin"],723+ "cpu": ["x64"]724+ },725+ "@garden-co/jazz-napi-linux-x64-gnu@2.0.0-alpha.53": {726+ "integrity": "sha512-4hnSynKd5nOhwoV3W4KfQ5BRcqLaiBghDZQJG5187QdUOBvoOssJaBdO8cvvEAKPW4/c1jShwk1WSO1aCI8rtQ==",727+ "os": ["linux"],728+ "cpu": ["x64"]729+ },730+ "@garden-co/jazz-napi-win32-x64-msvc@2.0.0-alpha.53": {731+ "integrity": "sha512-TNPa9uHA29eq3q5LgaBP61D5ukLaSjcFGxcsMSMuFff5spXTMSFyo9YSeBe9DaLVQgdtmzjLgptOnZIVRXK0lw==",732+ "os": ["win32"],733+ "cpu": ["x64"]734+ },735+ "@img/colour@1.1.0": {736+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="737+ },738+ "@img/sharp-darwin-arm64@0.35.3": {739+ "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==",740+ "optionalDependencies": [741+ "@img/sharp-libvips-darwin-arm64"742+ ],743+ "os": ["darwin"],744+ "cpu": ["arm64"]745+ },746+ "@img/sharp-darwin-x64@0.35.3": {747+ "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==",748+ "optionalDependencies": [749+ "@img/sharp-libvips-darwin-x64"750+ ],751+ "os": ["darwin"],752+ "cpu": ["x64"]753+ },754+ "@img/sharp-freebsd-wasm32@0.35.3": {755+ "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==",756+ "dependencies": [757+ "@img/sharp-wasm32"758+ ],759+ "os": ["freebsd"]760+ },761+ "@img/sharp-libvips-darwin-arm64@1.3.2": {762+ "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==",763+ "os": ["darwin"],764+ "cpu": ["arm64"]765+ },766+ "@img/sharp-libvips-darwin-x64@1.3.2": {767+ "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==",768+ "os": ["darwin"],769+ "cpu": ["x64"]770+ },771+ "@img/sharp-libvips-linux-arm64@1.3.2": {772+ "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==",773+ "os": ["linux"],774+ "cpu": ["arm64"]775+ },776+ "@img/sharp-libvips-linux-arm@1.3.2": {777+ "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==",778+ "os": ["linux"],779+ "cpu": ["arm"]780+ },781+ "@img/sharp-libvips-linux-ppc64@1.3.2": {782+ "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==",783+ "os": ["linux"],784+ "cpu": ["ppc64"]785+ },786+ "@img/sharp-libvips-linux-riscv64@1.3.2": {787+ "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==",788+ "os": ["linux"],789+ "cpu": ["riscv64"]790+ },791+ "@img/sharp-libvips-linux-s390x@1.3.2": {792+ "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==",793+ "os": ["linux"],794+ "cpu": ["s390x"]795+ },796+ "@img/sharp-libvips-linux-x64@1.3.2": {797+ "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==",798+ "os": ["linux"],799+ "cpu": ["x64"]800+ },801+ "@img/sharp-libvips-linuxmusl-arm64@1.3.2": {802+ "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==",803+ "os": ["linux"],804+ "cpu": ["arm64"]805+ },806+ "@img/sharp-libvips-linuxmusl-x64@1.3.2": {807+ "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==",808+ "os": ["linux"],809+ "cpu": ["x64"]810+ },811+ "@img/sharp-linux-arm64@0.35.3": {812+ "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==",813+ "optionalDependencies": [814+ "@img/sharp-libvips-linux-arm64"815+ ],816+ "os": ["linux"],817+ "cpu": ["arm64"]818+ },819+ "@img/sharp-linux-arm@0.35.3": {820+ "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==",821+ "optionalDependencies": [822+ "@img/sharp-libvips-linux-arm"823+ ],824+ "os": ["linux"],825+ "cpu": ["arm"]826+ },827+ "@img/sharp-linux-ppc64@0.35.3": {828+ "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==",829+ "optionalDependencies": [830+ "@img/sharp-libvips-linux-ppc64"831+ ],832+ "os": ["linux"],833+ "cpu": ["ppc64"]834+ },835+ "@img/sharp-linux-riscv64@0.35.3": {836+ "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==",837+ "optionalDependencies": [838+ "@img/sharp-libvips-linux-riscv64"839+ ],840+ "os": ["linux"],841+ "cpu": ["riscv64"]842+ },843+ "@img/sharp-linux-s390x@0.35.3": {844+ "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==",845+ "optionalDependencies": [846+ "@img/sharp-libvips-linux-s390x"847+ ],848+ "os": ["linux"],849+ "cpu": ["s390x"]850+ },851+ "@img/sharp-linux-x64@0.35.3": {852+ "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==",853+ "optionalDependencies": [854+ "@img/sharp-libvips-linux-x64"855+ ],856+ "os": ["linux"],857+ "cpu": ["x64"]858+ },859+ "@img/sharp-linuxmusl-arm64@0.35.3": {860+ "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==",861+ "optionalDependencies": [862+ "@img/sharp-libvips-linuxmusl-arm64"863+ ],864+ "os": ["linux"],865+ "cpu": ["arm64"]866+ },867+ "@img/sharp-linuxmusl-x64@0.35.3": {868+ "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==",869+ "optionalDependencies": [870+ "@img/sharp-libvips-linuxmusl-x64"871+ ],872+ "os": ["linux"],873+ "cpu": ["x64"]874+ },875+ "@img/sharp-wasm32@0.35.3": {876+ "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==",877+ "dependencies": [878+ "@emnapi/runtime"879+ ]880+ },881+ "@img/sharp-webcontainers-wasm32@0.35.3": {882+ "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==",883+ "dependencies": [884+ "@img/sharp-wasm32"885+ ],886+ "cpu": ["wasm32"]887+ },888+ "@img/sharp-win32-arm64@0.35.3": {889+ "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==",890+ "os": ["win32"],891+ "cpu": ["arm64"]892+ },893+ "@img/sharp-win32-ia32@0.35.3": {894+ "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==",895+ "os": ["win32"],896+ "cpu": ["ia32"]897+ },898+ "@img/sharp-win32-x64@0.35.3": {899+ "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==",900+ "os": ["win32"],901+ "cpu": ["x64"]902+ },903+ "@jridgewell/gen-mapping@0.3.13": {904+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",905+ "dependencies": [906+ "@jridgewell/sourcemap-codec",907+ "@jridgewell/trace-mapping"908+ ]909+ },910+ "@jridgewell/remapping@2.3.5": {911+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",912+ "dependencies": [913+ "@jridgewell/gen-mapping",914+ "@jridgewell/trace-mapping"915+ ]916+ },917+ "@jridgewell/resolve-uri@3.1.2": {918+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="919+ },920+ "@jridgewell/sourcemap-codec@1.5.5": {921+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="922+ },923+ "@jridgewell/trace-mapping@0.3.31": {924+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",925+ "dependencies": [926+ "@jridgewell/resolve-uri",927+ "@jridgewell/sourcemap-codec"928+ ]929+ },930+ "@napi-rs/wasm-runtime@1.1.6_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {931+ "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",932+ "dependencies": [933+ "@emnapi/core",934+ "@emnapi/runtime",935+ "@tybys/wasm-util"936+ ]937+ },938+ "@noble/hashes@2.2.0": {939+ "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="940+ },941+ "@opentelemetry/api-logs@0.216.0": {942+ "integrity": "sha512-KmGTgvxTJ0J01d4mOeX1wMV5NUTNf9HebIuOOGDfIn0a/IrnXIQbOnlylDyl9tkDv4h0DUpdI/GqCdLzfTkUXg==",943+ "dependencies": [944+ "@opentelemetry/api"945+ ]946+ },947+ "@opentelemetry/api@1.9.1": {948+ "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="949+ },950+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1": {951+ "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==",952+ "dependencies": [953+ "@opentelemetry/api",954+ "@opentelemetry/semantic-conventions"955+ ]956+ },957+ "@opentelemetry/core@2.9.0_@opentelemetry+api@1.9.1": {958+ "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==",959+ "dependencies": [960+ "@opentelemetry/api",961+ "@opentelemetry/semantic-conventions"962+ ]963+ },964+ "@opentelemetry/exporter-logs-otlp-http@0.216.0_@opentelemetry+api@1.9.1": {965+ "integrity": "sha512-8SUzQY/aExKkz6Ab3vOf6gu690Xk4wHH90dGwXinejQzazn5HCIRR7yPVU/2fEuiZ73R92MU4qI3djHfYP7NJg==",966+ "dependencies": [967+ "@opentelemetry/api",968+ "@opentelemetry/api-logs",969+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",970+ "@opentelemetry/otlp-exporter-base",971+ "@opentelemetry/otlp-transformer",972+ "@opentelemetry/sdk-logs"973+ ]974+ },975+ "@opentelemetry/exporter-trace-otlp-http@0.216.0_@opentelemetry+api@1.9.1": {976+ "integrity": "sha512-DhWjvj0PUPFwFnhOEivpum8sJzj6FTuyx88zff+oHVLUhfd6cLyw4AIai/F4j0PZqYZBFuMT/OTMUd9wdXnBEQ==",977+ "dependencies": [978+ "@opentelemetry/api",979+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",980+ "@opentelemetry/otlp-exporter-base",981+ "@opentelemetry/otlp-transformer",982+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1",983+ "@opentelemetry/sdk-trace-base"984+ ]985+ },986+ "@opentelemetry/otlp-exporter-base@0.216.0_@opentelemetry+api@1.9.1": {987+ "integrity": "sha512-sSnvb5f+FYa4mfYxj03rmmUh+aDwo3jok62dgIWUDw8ZCUPzEbgtv/YhZyKUSlKNNey7Uc5xmJgmtTLLIV6UDQ==",988+ "dependencies": [989+ "@opentelemetry/api",990+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",991+ "@opentelemetry/otlp-transformer"992+ ]993+ },994+ "@opentelemetry/otlp-transformer@0.216.0_@opentelemetry+api@1.9.1": {995+ "integrity": "sha512-g4Rb6sAsxQAo11eDjixfKxelruBsQFdJ8Wo23FCj7D6OXbidgXMu2xaRSYs4RdlomzAXSJuc86RcS3xmE8A6uA==",996+ "dependencies": [997+ "@opentelemetry/api",998+ "@opentelemetry/api-logs",999+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",1000+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1",1001+ "@opentelemetry/sdk-logs",1002+ "@opentelemetry/sdk-metrics",1003+ "@opentelemetry/sdk-trace-base",1004+ "protobufjs"1005+ ]1006+ },1007+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1": {1008+ "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==",1009+ "dependencies": [1010+ "@opentelemetry/api",1011+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",1012+ "@opentelemetry/semantic-conventions"1013+ ]1014+ },1015+ "@opentelemetry/resources@2.9.0_@opentelemetry+api@1.9.1": {1016+ "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==",1017+ "dependencies": [1018+ "@opentelemetry/api",1019+ "@opentelemetry/core@2.9.0_@opentelemetry+api@1.9.1",1020+ "@opentelemetry/semantic-conventions"1021+ ]1022+ },1023+ "@opentelemetry/sdk-logs@0.216.0_@opentelemetry+api@1.9.1": {1024+ "integrity": "sha512-KB3rcwQuitq0JbbsCcNdqMhRJX3kArAYz/ovb0jGRaBQAIrt2roik3xQXuhYxS37zx0jSkUZcJu1z3Y2UCxbDA==",1025+ "dependencies": [1026+ "@opentelemetry/api",1027+ "@opentelemetry/api-logs",1028+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",1029+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1",1030+ "@opentelemetry/semantic-conventions"1031+ ]1032+ },1033+ "@opentelemetry/sdk-metrics@2.7.1_@opentelemetry+api@1.9.1": {1034+ "integrity": "sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==",1035+ "dependencies": [1036+ "@opentelemetry/api",1037+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",1038+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1"1039+ ]1040+ },1041+ "@opentelemetry/sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1": {1042+ "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==",1043+ "dependencies": [1044+ "@opentelemetry/api",1045+ "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1",1046+ "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1",1047+ "@opentelemetry/semantic-conventions"1048+ ]1049+ },1050+ "@opentelemetry/semantic-conventions@1.43.0": {1051+ "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="1052+ },1053+ "@oslojs/encoding@1.1.0": {1054+ "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="1055+ },1056+ "@oxc-project/types@0.120.0": {1057+ "integrity": "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg=="1058+ },1059+ "@oxc-project/types@0.139.0": {1060+ "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw=="1061+ },1062+ "@preact/preset-vite@2.10.5_@babel+core@7.29.7_vite@8.1.4__esbuild@0.28.1_preact@10.29.7__preact-render-to-string@6.7.0_preact-render-to-string@6.7.0__preact@10.29.7": {1063+ "integrity": "sha512-p0vJpxiVO7KWWazWny3LUZ+saXyZKWv6Ju0bYMWNJRp2YveufRPgSUB1C4MTqGJfz07EehMgfN+AJNwQy+w6Iw==",1064+ "dependencies": [1065+ "@babel/core",1066+ "@babel/plugin-transform-react-jsx",1067+ "@babel/plugin-transform-react-jsx-development",1068+ "@prefresh/vite",1069+ "@rollup/pluginutils@5.4.0",1070+ "babel-plugin-transform-hook-names",1071+ "debug",1072+ "magic-string",1073+ "picocolors",1074+ "vite@8.1.4_esbuild@0.28.1",1075+ "vite-prerender-plugin",1076+ "zimmerframe"1077+ ]1078+ },1079+ "@preact/signals-core@1.14.4": {1080+ "integrity": "sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA=="1081+ },1082+ "@preact/signals@2.9.3_preact@10.29.7__preact-render-to-string@6.7.0_preact-render-to-string@6.7.0__preact@10.29.7": {1083+ "integrity": "sha512-4g3L/dYgUt0PPE6mnYsgCP/3DEhmAYTQxjzwfSPnXQ7Lj1WPBBEY83F48X0RcNEP3ycr57T8Hcpg4PVU5VM7pg==",1084+ "dependencies": [1085+ "@preact/signals-core",1086+ "preact"1087+ ]1088+ },1089+ "@prefresh/babel-plugin@0.5.3": {1090+ "integrity": "sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ=="1091+ },1092+ "@prefresh/core@1.5.10_preact@10.29.7__preact-render-to-string@6.7.0_preact-render-to-string@6.7.0__preact@10.29.7": {1093+ "integrity": "sha512-7yPTFbG56sutaFu8krp3B4a200KOFUvrtlllKWRuLjsYXo9UUucHOZRcer+gtgMkFTpv6ob8TGcTwA32bSwa1w==",1094+ "dependencies": [1095+ "preact"1096+ ]1097+ },1098+ "@prefresh/utils@1.2.1": {1099+ "integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw=="1100+ },1101+ "@prefresh/vite@2.4.12_preact@10.29.7__preact-render-to-string@6.7.0_vite@8.1.4__esbuild@0.28.1_preact-render-to-string@6.7.0__preact@10.29.7": {1102+ "integrity": "sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==",1103+ "dependencies": [1104+ "@babel/core",1105+ "@prefresh/babel-plugin",1106+ "@prefresh/core",1107+ "@prefresh/utils",1108+ "@rollup/pluginutils@4.2.1",1109+ "preact",1110+ "vite@8.1.4_esbuild@0.28.1"1111+ ]1112+ },1113+ "@protobufjs/aspromise@1.1.2": {1114+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="1115+ },1116+ "@protobufjs/base64@1.1.2": {1117+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="1118+ },1119+ "@protobufjs/codegen@2.0.5": {1120+ "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="1121+ },1122+ "@protobufjs/eventemitter@1.1.1": {1123+ "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="1124+ },1125+ "@protobufjs/fetch@1.1.1": {1126+ "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==",1127+ "dependencies": [1128+ "@protobufjs/aspromise"1129+ ]1130+ },1131+ "@protobufjs/float@1.0.2": {1132+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="1133+ },1134+ "@protobufjs/inquire@1.1.2": {1135+ "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw=="1136+ },1137+ "@protobufjs/path@1.1.2": {1138+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="1139+ },1140+ "@protobufjs/pool@1.1.0": {1141+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="1142+ },1143+ "@protobufjs/utf8@1.1.2": {1144+ "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="1145+ },1146+ "@rolldown/binding-android-arm64@1.0.0-rc.10": {1147+ "integrity": "sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==",1148+ "os": ["android"],1149+ "cpu": ["arm64"]1150+ },1151+ "@rolldown/binding-android-arm64@1.1.5": {1152+ "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==",1153+ "os": ["android"],1154+ "cpu": ["arm64"]1155+ },1156+ "@rolldown/binding-darwin-arm64@1.0.0-rc.10": {1157+ "integrity": "sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==",1158+ "os": ["darwin"],1159+ "cpu": ["arm64"]1160+ },1161+ "@rolldown/binding-darwin-arm64@1.1.5": {1162+ "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==",1163+ "os": ["darwin"],1164+ "cpu": ["arm64"]1165+ },1166+ "@rolldown/binding-darwin-x64@1.0.0-rc.10": {1167+ "integrity": "sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==",1168+ "os": ["darwin"],1169+ "cpu": ["x64"]1170+ },1171+ "@rolldown/binding-darwin-x64@1.1.5": {1172+ "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==",1173+ "os": ["darwin"],1174+ "cpu": ["x64"]1175+ },1176+ "@rolldown/binding-freebsd-x64@1.0.0-rc.10": {1177+ "integrity": "sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==",1178+ "os": ["freebsd"],1179+ "cpu": ["x64"]1180+ },1181+ "@rolldown/binding-freebsd-x64@1.1.5": {1182+ "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==",1183+ "os": ["freebsd"],1184+ "cpu": ["x64"]1185+ },1186+ "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10": {1187+ "integrity": "sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==",1188+ "os": ["linux"],1189+ "cpu": ["arm"]1190+ },1191+ "@rolldown/binding-linux-arm-gnueabihf@1.1.5": {1192+ "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==",1193+ "os": ["linux"],1194+ "cpu": ["arm"]1195+ },1196+ "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10": {1197+ "integrity": "sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==",1198+ "os": ["linux"],1199+ "cpu": ["arm64"]1200+ },1201+ "@rolldown/binding-linux-arm64-gnu@1.1.5": {1202+ "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==",1203+ "os": ["linux"],1204+ "cpu": ["arm64"]1205+ },1206+ "@rolldown/binding-linux-arm64-musl@1.0.0-rc.10": {1207+ "integrity": "sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==",1208+ "os": ["linux"],1209+ "cpu": ["arm64"]1210+ },1211+ "@rolldown/binding-linux-arm64-musl@1.1.5": {1212+ "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==",1213+ "os": ["linux"],1214+ "cpu": ["arm64"]1215+ },1216+ "@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10": {1217+ "integrity": "sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==",1218+ "os": ["linux"],1219+ "cpu": ["ppc64"]1220+ },1221+ "@rolldown/binding-linux-ppc64-gnu@1.1.5": {1222+ "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==",1223+ "os": ["linux"],1224+ "cpu": ["ppc64"]1225+ },1226+ "@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10": {1227+ "integrity": "sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==",1228+ "os": ["linux"],1229+ "cpu": ["s390x"]1230+ },1231+ "@rolldown/binding-linux-s390x-gnu@1.1.5": {1232+ "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==",1233+ "os": ["linux"],1234+ "cpu": ["s390x"]1235+ },1236+ "@rolldown/binding-linux-x64-gnu@1.0.0-rc.10": {1237+ "integrity": "sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==",1238+ "os": ["linux"],1239+ "cpu": ["x64"]1240+ },1241+ "@rolldown/binding-linux-x64-gnu@1.1.5": {1242+ "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==",1243+ "os": ["linux"],1244+ "cpu": ["x64"]1245+ },1246+ "@rolldown/binding-linux-x64-musl@1.0.0-rc.10": {1247+ "integrity": "sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==",1248+ "os": ["linux"],1249+ "cpu": ["x64"]1250+ },1251+ "@rolldown/binding-linux-x64-musl@1.1.5": {1252+ "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==",1253+ "os": ["linux"],1254+ "cpu": ["x64"]1255+ },1256+ "@rolldown/binding-openharmony-arm64@1.0.0-rc.10": {1257+ "integrity": "sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==",1258+ "os": ["openharmony"],1259+ "cpu": ["arm64"]1260+ },1261+ "@rolldown/binding-openharmony-arm64@1.1.5": {1262+ "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==",1263+ "os": ["openharmony"],1264+ "cpu": ["arm64"]1265+ },1266+ "@rolldown/binding-wasm32-wasi@1.0.0-rc.10_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {1267+ "integrity": "sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==",1268+ "dependencies": [1269+ "@napi-rs/wasm-runtime"1270+ ],1271+ "cpu": ["wasm32"]1272+ },1273+ "@rolldown/binding-wasm32-wasi@1.1.5": {1274+ "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==",1275+ "dependencies": [1276+ "@emnapi/core",1277+ "@emnapi/runtime",1278+ "@napi-rs/wasm-runtime"1279+ ],1280+ "cpu": ["wasm32"]1281+ },1282+ "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10": {1283+ "integrity": "sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==",1284+ "os": ["win32"],1285+ "cpu": ["arm64"]1286+ },1287+ "@rolldown/binding-win32-arm64-msvc@1.1.5": {1288+ "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==",1289+ "os": ["win32"],1290+ "cpu": ["arm64"]1291+ },1292+ "@rolldown/binding-win32-x64-msvc@1.0.0-rc.10": {1293+ "integrity": "sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==",1294+ "os": ["win32"],1295+ "cpu": ["x64"]1296+ },1297+ "@rolldown/binding-win32-x64-msvc@1.1.5": {1298+ "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==",1299+ "os": ["win32"],1300+ "cpu": ["x64"]1301+ },1302+ "@rolldown/pluginutils@1.0.0-rc.10": {1303+ "integrity": "sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg=="1304+ },1305+ "@rolldown/pluginutils@1.0.1": {1306+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="1307+ },1308+ "@rollup/pluginutils@4.2.1": {1309+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",1310+ "dependencies": [1311+ "estree-walker",1312+ "picomatch@2.3.2"1313+ ]1314+ },1315+ "@rollup/pluginutils@5.4.0": {1316+ "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==",1317+ "dependencies": [1318+ "@types/estree",1319+ "estree-walker",1320+ "picomatch@4.0.5"1321+ ]1322+ },1323+ "@scure/base@2.2.0": {1324+ "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg=="1325+ },1326+ "@scure/bip39@2.2.0": {1327+ "integrity": "sha512-T/Bj/YvYMNkIPq6EENO6/rcs2e7qTNuyoUXf0KBFDmp0ZDu0H2X4Lq6yC3i0c8PcWkov5EbW+yQZZbdMmk154A==",1328+ "dependencies": [1329+ "@noble/hashes",1330+ "@scure/base"1331+ ]1332+ },1333+ "@shikijs/core@4.3.1": {1334+ "integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==",1335+ "dependencies": [1336+ "@shikijs/primitive",1337+ "@shikijs/types",1338+ "@shikijs/vscode-textmate",1339+ "@types/hast",1340+ "hast-util-to-html"1341+ ]1342+ },1343+ "@shikijs/engine-javascript@4.3.1": {1344+ "integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==",1345+ "dependencies": [1346+ "@shikijs/types",1347+ "@shikijs/vscode-textmate",1348+ "oniguruma-to-es"1349+ ]1350+ },1351+ "@shikijs/engine-oniguruma@4.3.1": {1352+ "integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==",1353+ "dependencies": [1354+ "@shikijs/types",1355+ "@shikijs/vscode-textmate"1356+ ]1357+ },1358+ "@shikijs/langs@4.3.1": {1359+ "integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==",1360+ "dependencies": [1361+ "@shikijs/types"1362+ ]1363+ },1364+ "@shikijs/primitive@4.3.1": {1365+ "integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==",1366+ "dependencies": [1367+ "@shikijs/types",1368+ "@shikijs/vscode-textmate",1369+ "@types/hast"1370+ ]1371+ },1372+ "@shikijs/themes@4.3.1": {1373+ "integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==",1374+ "dependencies": [1375+ "@shikijs/types"1376+ ]1377+ },1378+ "@shikijs/types@4.3.1": {1379+ "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==",1380+ "dependencies": [1381+ "@shikijs/vscode-textmate",1382+ "@types/hast"1383+ ]1384+ },1385+ "@shikijs/vscode-textmate@10.0.2": {1386+ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="1387+ },1388+ "@standard-schema/spec@1.1.0": {1389+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="1390+ },1391+ "@tybys/wasm-util@0.10.3": {1392+ "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",1393+ "dependencies": [1394+ "tslib"1395+ ]1396+ },1397+ "@types/estree-jsx@1.0.5": {1398+ "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",1399+ "dependencies": [1400+ "@types/estree"1401+ ]1402+ },1403+ "@types/estree@1.0.9": {1404+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="1405+ },1406+ "@types/hast@3.0.5": {1407+ "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",1408+ "dependencies": [1409+ "@types/unist"1410+ ]1411+ },1412+ "@types/mdast@4.0.4": {1413+ "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",1414+ "dependencies": [1415+ "@types/unist"1416+ ]1417+ },1418+ "@types/nlcst@2.0.3": {1419+ "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==",1420+ "dependencies": [1421+ "@types/unist"1422+ ]1423+ },1424+ "@types/node@26.1.1": {1425+ "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",1426+ "dependencies": [1427+ "undici-types"1428+ ]1429+ },1430+ "@types/unist@3.0.3": {1431+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="1432+ },1433+ "@ungap/structured-clone@1.3.3": {1434+ "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg=="1435+ },1436+ "@volar/kit@2.4.28_typescript@6.0.3": {1437+ "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==",1438+ "dependencies": [1439+ "@volar/language-service",1440+ "@volar/typescript",1441+ "typesafe-path",1442+ "typescript",1443+ "vscode-languageserver-textdocument",1444+ "vscode-uri"1445+ ]1446+ },1447+ "@volar/language-core@2.4.28": {1448+ "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==",1449+ "dependencies": [1450+ "@volar/source-map"1451+ ]1452+ },1453+ "@volar/language-server@2.4.28": {1454+ "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==",1455+ "dependencies": [1456+ "@volar/language-core",1457+ "@volar/language-service",1458+ "@volar/typescript",1459+ "path-browserify",1460+ "request-light@0.7.0",1461+ "vscode-languageserver",1462+ "vscode-languageserver-protocol",1463+ "vscode-languageserver-textdocument",1464+ "vscode-uri"1465+ ]1466+ },1467+ "@volar/language-service@2.4.28": {1468+ "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==",1469+ "dependencies": [1470+ "@volar/language-core",1471+ "vscode-languageserver-protocol",1472+ "vscode-languageserver-textdocument",1473+ "vscode-uri"1474+ ]1475+ },1476+ "@volar/source-map@2.4.28": {1477+ "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="1478+ },1479+ "@volar/typescript@2.4.28": {1480+ "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==",1481+ "dependencies": [1482+ "@volar/language-core",1483+ "path-browserify",1484+ "vscode-uri"1485+ ]1486+ },1487+ "@vscode/emmet-helper@2.11.0": {1488+ "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==",1489+ "dependencies": [1490+ "emmet",1491+ "jsonc-parser@2.3.1",1492+ "vscode-languageserver-textdocument",1493+ "vscode-languageserver-types@3.18.0",1494+ "vscode-uri"1495+ ]1496+ },1497+ "@vscode/l10n@0.0.18": {1498+ "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="1499+ },1500+ "ajv-draft-04@1.0.0_ajv@8.20.0": {1501+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",1502+ "dependencies": [1503+ "ajv"1504+ ],1505+ "optionalPeers": [1506+ "ajv"1507+ ]1508+ },1509+ "ajv-i18n@4.2.0_ajv@8.20.0": {1510+ "integrity": "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg==",1511+ "dependencies": [1512+ "ajv"1513+ ]1514+ },1515+ "ajv@8.20.0": {1516+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",1517+ "dependencies": [1518+ "fast-deep-equal",1519+ "fast-uri",1520+ "json-schema-traverse",1521+ "require-from-string"1522+ ]1523+ },1524+ "am-i-vibing@0.4.0": {1525+ "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==",1526+ "dependencies": [1527+ "process-ancestry"1528+ ],1529+ "bin": true1530+ },1531+ "ansi-regex@5.0.1": {1532+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="1533+ },1534+ "ansi-styles@4.3.0": {1535+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",1536+ "dependencies": [1537+ "color-convert"1538+ ]1539+ },1540+ "anymatch@3.1.3": {1541+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",1542+ "dependencies": [1543+ "normalize-path",1544+ "picomatch@2.3.2"1545+ ]1546+ },1547+ "argparse@2.0.1": {1548+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="1549+ },1550+ "aria-query@5.3.2": {1551+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="1552+ },1553+ "astro@7.0.9_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {1554+ "integrity": "sha512-WB5pA4LLQnmqjBh6EIu0z8aUV4q2/AoThgSZq57Rsp+oqqvPu7OwZ5eF+W4ku20TUTxIhiJW8dccuGvJPiW2UA==",1555+ "dependencies": [1556+ "@astrojs/compiler-rs",1557+ "@astrojs/internal-helpers",1558+ "@astrojs/markdown-satteri",1559+ "@astrojs/telemetry",1560+ "@capsizecss/unpack",1561+ "@clack/prompts",1562+ "@oslojs/encoding",1563+ "@rollup/pluginutils@5.4.0",1564+ "am-i-vibing",1565+ "aria-query",1566+ "axobject-query",1567+ "ci-info",1568+ "clsx",1569+ "common-ancestor-path",1570+ "cookie",1571+ "devalue",1572+ "diff",1573+ "dset",1574+ "es-module-lexer",1575+ "esbuild@0.28.1",1576+ "flattie",1577+ "fontace",1578+ "get-tsconfig",1579+ "github-slugger",1580+ "html-escaper",1581+ "http-cache-semantics",1582+ "js-yaml",1583+ "jsonc-parser@3.3.1",1584+ "magic-string",1585+ "magicast",1586+ "mrmime",1587+ "neotraverse",1588+ "obug",1589+ "p-limit",1590+ "p-queue",1591+ "package-manager-detector",1592+ "piccolore",1593+ "picomatch@4.0.5",1594+ "semver@7.8.5",1595+ "shiki",1596+ "smol-toml",1597+ "svgo",1598+ "tinyclip",1599+ "tinyexec",1600+ "tinyglobby",1601+ "ultrahtml",1602+ "unifont",1603+ "unstorage",1604+ "vite@8.1.4_esbuild@0.28.1",1605+ "vitefu",1606+ "xxhash-wasm",1607+ "yargs-parser@22.0.0",1608+ "zod"1609+ ],1610+ "optionalDependencies": [1611+ "sharp"1612+ ],1613+ "bin": true1614+ },1615+ "axobject-query@4.1.0": {1616+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="1617+ },1618+ "babel-plugin-transform-hook-names@1.0.2_@babel+core@7.29.7": {1619+ "integrity": "sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==",1620+ "dependencies": [1621+ "@babel/core"1622+ ]1623+ },1624+ "bail@2.0.2": {1625+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="1626+ },1627+ "baseline-browser-mapping@2.10.43": {1628+ "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==",1629+ "bin": true1630+ },1631+ "boolbase@1.0.0": {1632+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="1633+ },1634+ "browserslist@4.28.6": {1635+ "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==",1636+ "dependencies": [1637+ "baseline-browser-mapping",1638+ "caniuse-lite",1639+ "electron-to-chromium",1640+ "node-releases",1641+ "update-browserslist-db"1642+ ],1643+ "bin": true1644+ },1645+ "caniuse-lite@1.0.30001805": {1646+ "integrity": "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA=="1647+ },1648+ "ccount@2.0.1": {1649+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="1650+ },1651+ "character-entities-html4@2.1.0": {1652+ "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="1653+ },1654+ "character-entities-legacy@3.0.0": {1655+ "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="1656+ },1657+ "chokidar@4.0.3": {1658+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",1659+ "dependencies": [1660+ "readdirp@4.1.2"1661+ ]1662+ },1663+ "chokidar@5.0.0": {1664+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",1665+ "dependencies": [1666+ "readdirp@5.0.0"1667+ ]1668+ },1669+ "ci-info@4.4.0": {1670+ "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="1671+ },1672+ "cliui@8.0.1": {1673+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",1674+ "dependencies": [1675+ "string-width",1676+ "strip-ansi",1677+ "wrap-ansi"1678+ ]1679+ },1680+ "clsx@2.1.1": {1681+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="1682+ },1683+ "color-convert@2.0.1": {1684+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",1685+ "dependencies": [1686+ "color-name"1687+ ]1688+ },1689+ "color-name@1.1.4": {1690+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="1691+ },1692+ "comma-separated-tokens@2.0.3": {1693+ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="1694+ },1695+ "commander@11.1.0": {1696+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="1697+ },1698+ "common-ancestor-path@2.0.0": {1699+ "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="1700+ },1701+ "convert-source-map@2.0.0": {1702+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="1703+ },1704+ "cookie-es@1.2.3": {1705+ "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw=="1706+ },1707+ "cookie@1.1.1": {1708+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="1709+ },1710+ "crossws@0.3.5": {1711+ "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==",1712+ "dependencies": [1713+ "uncrypto"1714+ ]1715+ },1716+ "css-select@5.2.2": {1717+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",1718+ "dependencies": [1719+ "boolbase",1720+ "css-what",1721+ "domhandler",1722+ "domutils",1723+ "nth-check"1724+ ]1725+ },1726+ "css-tree@2.2.1": {1727+ "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",1728+ "dependencies": [1729+ "mdn-data@2.0.28",1730+ "source-map-js"1731+ ]1732+ },1733+ "css-tree@3.2.1": {1734+ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",1735+ "dependencies": [1736+ "mdn-data@2.27.1",1737+ "source-map-js"1738+ ]1739+ },1740+ "css-what@6.2.2": {1741+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="1742+ },1743+ "csso@5.0.5": {1744+ "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",1745+ "dependencies": [1746+ "css-tree@2.2.1"1747+ ]1748+ },1749+ "debug@4.4.3": {1750+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",1751+ "dependencies": [1752+ "ms"1753+ ]1754+ },1755+ "defu@6.1.7": {1756+ "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="1757+ },1758+ "dequal@2.0.3": {1759+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="1760+ },1761+ "destr@2.0.5": {1762+ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="1763+ },1764+ "detect-libc@2.1.2": {1765+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="1766+ },1767+ "devalue@5.8.1": {1768+ "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="1769+ },1770+ "devlop@1.1.0": {1771+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",1772+ "dependencies": [1773+ "dequal"1774+ ]1775+ },1776+ "diff@8.0.4": {1777+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="1778+ },1779+ "dom-serializer@2.0.0": {1780+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",1781+ "dependencies": [1782+ "domelementtype",1783+ "domhandler",1784+ "entities@4.5.0"1785+ ]1786+ },1787+ "domelementtype@2.3.0": {1788+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="1789+ },1790+ "domhandler@5.0.3": {1791+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",1792+ "dependencies": [1793+ "domelementtype"1794+ ]1795+ },1796+ "domutils@3.2.2": {1797+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",1798+ "dependencies": [1799+ "dom-serializer",1800+ "domelementtype",1801+ "domhandler"1802+ ]1803+ },1804+ "dset@3.1.4": {1805+ "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="1806+ },1807+ "electron-to-chromium@1.5.391": {1808+ "integrity": "sha512-YmCu4856jkgKT1Nh6fwRdeVrM6Ydf/fBnq51tpmSfX+jOcUMTxh31yH6hjKScRenhB2oDSvA9oooxcpjogPeig=="1809+ },1810+ "emmet@2.4.11": {1811+ "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==",1812+ "dependencies": [1813+ "@emmetio/abbreviation",1814+ "@emmetio/css-abbreviation"1815+ ]1816+ },1817+ "emoji-regex@8.0.0": {1818+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="1819+ },1820+ "entities@4.5.0": {1821+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="1822+ },1823+ "entities@6.0.1": {1824+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="1825+ },1826+ "es-module-lexer@2.3.1": {1827+ "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA=="1828+ },1829+ "esbuild@0.27.7": {1830+ "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",1831+ "optionalDependencies": [1832+ "@esbuild/aix-ppc64@0.27.7",1833+ "@esbuild/android-arm@0.27.7",1834+ "@esbuild/android-arm64@0.27.7",1835+ "@esbuild/android-x64@0.27.7",1836+ "@esbuild/darwin-arm64@0.27.7",1837+ "@esbuild/darwin-x64@0.27.7",1838+ "@esbuild/freebsd-arm64@0.27.7",1839+ "@esbuild/freebsd-x64@0.27.7",1840+ "@esbuild/linux-arm@0.27.7",1841+ "@esbuild/linux-arm64@0.27.7",1842+ "@esbuild/linux-ia32@0.27.7",1843+ "@esbuild/linux-loong64@0.27.7",1844+ "@esbuild/linux-mips64el@0.27.7",1845+ "@esbuild/linux-ppc64@0.27.7",1846+ "@esbuild/linux-riscv64@0.27.7",1847+ "@esbuild/linux-s390x@0.27.7",1848+ "@esbuild/linux-x64@0.27.7",1849+ "@esbuild/netbsd-arm64@0.27.7",1850+ "@esbuild/netbsd-x64@0.27.7",1851+ "@esbuild/openbsd-arm64@0.27.7",1852+ "@esbuild/openbsd-x64@0.27.7",1853+ "@esbuild/openharmony-arm64@0.27.7",1854+ "@esbuild/sunos-x64@0.27.7",1855+ "@esbuild/win32-arm64@0.27.7",1856+ "@esbuild/win32-ia32@0.27.7",1857+ "@esbuild/win32-x64@0.27.7"1858+ ],1859+ "scripts": true,1860+ "bin": true1861+ },1862+ "esbuild@0.28.1": {1863+ "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",1864+ "optionalDependencies": [1865+ "@esbuild/aix-ppc64@0.28.1",1866+ "@esbuild/android-arm@0.28.1",1867+ "@esbuild/android-arm64@0.28.1",1868+ "@esbuild/android-x64@0.28.1",1869+ "@esbuild/darwin-arm64@0.28.1",1870+ "@esbuild/darwin-x64@0.28.1",1871+ "@esbuild/freebsd-arm64@0.28.1",1872+ "@esbuild/freebsd-x64@0.28.1",1873+ "@esbuild/linux-arm@0.28.1",1874+ "@esbuild/linux-arm64@0.28.1",1875+ "@esbuild/linux-ia32@0.28.1",1876+ "@esbuild/linux-loong64@0.28.1",1877+ "@esbuild/linux-mips64el@0.28.1",1878+ "@esbuild/linux-ppc64@0.28.1",1879+ "@esbuild/linux-riscv64@0.28.1",1880+ "@esbuild/linux-s390x@0.28.1",1881+ "@esbuild/linux-x64@0.28.1",1882+ "@esbuild/netbsd-arm64@0.28.1",1883+ "@esbuild/netbsd-x64@0.28.1",1884+ "@esbuild/openbsd-arm64@0.28.1",1885+ "@esbuild/openbsd-x64@0.28.1",1886+ "@esbuild/openharmony-arm64@0.28.1",1887+ "@esbuild/sunos-x64@0.28.1",1888+ "@esbuild/win32-arm64@0.28.1",1889+ "@esbuild/win32-ia32@0.28.1",1890+ "@esbuild/win32-x64@0.28.1"1891+ ],1892+ "scripts": true,1893+ "bin": true1894+ },1895+ "escalade@3.2.0": {1896+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="1897+ },1898+ "estree-walker@2.0.2": {1899+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="1900+ },1901+ "eventemitter3@5.0.4": {1902+ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="1903+ },1904+ "extend@3.0.2": {1905+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="1906+ },1907+ "fast-deep-equal@3.1.3": {1908+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="1909+ },1910+ "fast-string-truncated-width@3.0.3": {1911+ "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="1912+ },1913+ "fast-string-width@3.0.2": {1914+ "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",1915+ "dependencies": [1916+ "fast-string-truncated-width"1917+ ]1918+ },1919+ "fast-uri@3.1.3": {1920+ "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg=="1921+ },1922+ "fast-wrap-ansi@0.2.2": {1923+ "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==",1924+ "dependencies": [1925+ "fast-string-width"1926+ ]1927+ },1928+ "fdir@6.5.0_picomatch@4.0.5": {1929+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",1930+ "dependencies": [1931+ "picomatch@4.0.5"1932+ ],1933+ "optionalPeers": [1934+ "picomatch@4.0.5"1935+ ]1936+ },1937+ "flattie@1.1.1": {1938+ "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="1939+ },1940+ "fontace@0.4.1": {1941+ "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==",1942+ "dependencies": [1943+ "fontkitten"1944+ ]1945+ },1946+ "fontkitten@1.0.3": {1947+ "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==",1948+ "dependencies": [1949+ "tiny-inflate"1950+ ]1951+ },1952+ "fsevents@2.3.3": {1953+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",1954+ "os": ["darwin"],1955+ "scripts": true1956+ },1957+ "gensync@1.0.0-beta.2": {1958+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="1959+ },1960+ "get-caller-file@2.0.5": {1961+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="1962+ },1963+ "get-tsconfig@5.0.0-beta.4": {1964+ "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==",1965+ "dependencies": [1966+ "resolve-pkg-maps"1967+ ]1968+ },1969+ "github-slugger@2.0.0": {1970+ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="1971+ },1972+ "h3@1.15.11": {1973+ "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==",1974+ "dependencies": [1975+ "cookie-es",1976+ "crossws",1977+ "defu",1978+ "destr",1979+ "iron-webcrypto",1980+ "node-mock-http",1981+ "radix3",1982+ "ufo",1983+ "uncrypto"1984+ ]1985+ },1986+ "hast-util-from-html@2.0.3": {1987+ "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",1988+ "dependencies": [1989+ "@types/hast",1990+ "devlop",1991+ "hast-util-from-parse5",1992+ "parse5",1993+ "vfile",1994+ "vfile-message"1995+ ]1996+ },1997+ "hast-util-from-parse5@8.0.3": {1998+ "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==",1999+ "dependencies": [2000+ "@types/hast",2001+ "@types/unist",2002+ "devlop",2003+ "hastscript",2004+ "property-information",2005+ "vfile",2006+ "vfile-location",2007+ "web-namespaces"2008+ ]2009+ },2010+ "hast-util-parse-selector@4.0.0": {2011+ "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",2012+ "dependencies": [2013+ "@types/hast"2014+ ]2015+ },2016+ "hast-util-to-html@9.0.5": {2017+ "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",2018+ "dependencies": [2019+ "@types/hast",2020+ "@types/unist",2021+ "ccount",2022+ "comma-separated-tokens",2023+ "hast-util-whitespace",2024+ "html-void-elements",2025+ "mdast-util-to-hast",2026+ "property-information",2027+ "space-separated-tokens",2028+ "stringify-entities",2029+ "zwitch"2030+ ]2031+ },2032+ "hast-util-whitespace@3.0.0": {2033+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",2034+ "dependencies": [2035+ "@types/hast"2036+ ]2037+ },2038+ "hastscript@9.0.1": {2039+ "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==",2040+ "dependencies": [2041+ "@types/hast",2042+ "comma-separated-tokens",2043+ "hast-util-parse-selector",2044+ "property-information",2045+ "space-separated-tokens"2046+ ]2047+ },2048+ "he@1.2.0": {2049+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",2050+ "bin": true2051+ },2052+ "html-escaper@3.0.3": {2053+ "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="2054+ },2055+ "html-void-elements@3.0.0": {2056+ "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="2057+ },2058+ "http-cache-semantics@4.2.0": {2059+ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="2060+ },2061+ "iron-webcrypto@1.2.1": {2062+ "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="2063+ },2064+ "is-docker@4.0.0": {2065+ "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==",2066+ "bin": true2067+ },2068+ "is-fullwidth-code-point@3.0.0": {2069+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="2070+ },2071+ "is-plain-obj@4.1.0": {2072+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="2073+ },2074+ "jazz-napi@2.0.0-alpha.53": {2075+ "integrity": "sha512-5+EEUoahaNA2d0IqvYDlmrx9bjhLjpvkbt5Nab+C09EeKGnJcz7JJbofC0xuJDe++9I7/8cnYps7YcAYjdK3Ug==",2076+ "optionalDependencies": [2077+ "@garden-co/jazz-napi-darwin-arm64",2078+ "@garden-co/jazz-napi-darwin-x64",2079+ "@garden-co/jazz-napi-linux-x64-gnu",2080+ "@garden-co/jazz-napi-win32-x64-msvc"2081+ ]2082+ },2083+ "jazz-tools@2.0.0-alpha.53": {2084+ "integrity": "sha512-GSAt9axXPaZY3g0bZxEPeAmq/q4IWfJRdVMWmNYxLnaKzFHD3vYQf1y4VK9/ZAGCdabcxS8Im3dreISRHXkHSg==",2085+ "dependencies": [2086+ "@opentelemetry/api",2087+ "@opentelemetry/exporter-logs-otlp-http",2088+ "@opentelemetry/exporter-trace-otlp-http",2089+ "@opentelemetry/resources@2.9.0_@opentelemetry+api@1.9.1",2090+ "@opentelemetry/sdk-logs",2091+ "@opentelemetry/sdk-trace-base",2092+ "@scure/bip39",2093+ "@standard-schema/spec",2094+ "esbuild@0.27.7",2095+ "jazz-wasm",2096+ "jose",2097+ "json-schema-to-ts",2098+ "pluralize-esm",2099+ "web-streams-polyfill"2100+ ],2101+ "optionalDependencies": [2102+ "jazz-napi"2103+ ],2104+ "bin": true2105+ },2106+ "jazz-wasm@2.0.0-alpha.53": {2107+ "integrity": "sha512-0Aqnldh3pPvH582g4H2TtbycoFujBpnMpL4dcS0uhMRsBzr8ycIIi3GCWMP43Gn2DG5X5cutqpGqNKMzZbY6BQ=="2108+ },2109+ "jose@6.2.3": {2110+ "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="2111+ },2112+ "js-tokens@4.0.0": {2113+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="2114+ },2115+ "js-yaml@4.3.0": {2116+ "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",2117+ "dependencies": [2118+ "argparse"2119+ ],2120+ "bin": true2121+ },2122+ "jsesc@3.1.0": {2123+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",2124+ "bin": true2125+ },2126+ "json-schema-to-ts@3.1.1": {2127+ "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==",2128+ "dependencies": [2129+ "@babel/runtime",2130+ "ts-algebra"2131+ ]2132+ },2133+ "json-schema-traverse@1.0.0": {2134+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="2135+ },2136+ "json5@2.2.3": {2137+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",2138+ "bin": true2139+ },2140+ "jsonc-parser@2.3.1": {2141+ "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="2142+ },2143+ "jsonc-parser@3.3.1": {2144+ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="2145+ },2146+ "kleur@4.1.5": {2147+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="2148+ },2149+ "kolorist@1.8.0": {2150+ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="2151+ },2152+ "lightningcss-android-arm64@1.32.0": {2153+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",2154+ "os": ["android"],2155+ "cpu": ["arm64"]2156+ },2157+ "lightningcss-darwin-arm64@1.32.0": {2158+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",2159+ "os": ["darwin"],2160+ "cpu": ["arm64"]2161+ },2162+ "lightningcss-darwin-x64@1.32.0": {2163+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",2164+ "os": ["darwin"],2165+ "cpu": ["x64"]2166+ },2167+ "lightningcss-freebsd-x64@1.32.0": {2168+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",2169+ "os": ["freebsd"],2170+ "cpu": ["x64"]2171+ },2172+ "lightningcss-linux-arm-gnueabihf@1.32.0": {2173+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",2174+ "os": ["linux"],2175+ "cpu": ["arm"]2176+ },2177+ "lightningcss-linux-arm64-gnu@1.32.0": {2178+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",2179+ "os": ["linux"],2180+ "cpu": ["arm64"]2181+ },2182+ "lightningcss-linux-arm64-musl@1.32.0": {2183+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",2184+ "os": ["linux"],2185+ "cpu": ["arm64"]2186+ },2187+ "lightningcss-linux-x64-gnu@1.32.0": {2188+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",2189+ "os": ["linux"],2190+ "cpu": ["x64"]2191+ },2192+ "lightningcss-linux-x64-musl@1.32.0": {2193+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",2194+ "os": ["linux"],2195+ "cpu": ["x64"]2196+ },2197+ "lightningcss-win32-arm64-msvc@1.32.0": {2198+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",2199+ "os": ["win32"],2200+ "cpu": ["arm64"]2201+ },2202+ "lightningcss-win32-x64-msvc@1.32.0": {2203+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",2204+ "os": ["win32"],2205+ "cpu": ["x64"]2206+ },2207+ "lightningcss@1.32.0": {2208+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",2209+ "dependencies": [2210+ "detect-libc"2211+ ],2212+ "optionalDependencies": [2213+ "lightningcss-android-arm64",2214+ "lightningcss-darwin-arm64",2215+ "lightningcss-darwin-x64",2216+ "lightningcss-freebsd-x64",2217+ "lightningcss-linux-arm-gnueabihf",2218+ "lightningcss-linux-arm64-gnu",2219+ "lightningcss-linux-arm64-musl",2220+ "lightningcss-linux-x64-gnu",2221+ "lightningcss-linux-x64-musl",2222+ "lightningcss-win32-arm64-msvc",2223+ "lightningcss-win32-x64-msvc"2224+ ]2225+ },2226+ "long@5.3.2": {2227+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="2228+ },2229+ "lru-cache@11.5.2": {2230+ "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="2231+ },2232+ "lru-cache@5.1.1": {2233+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",2234+ "dependencies": [2235+ "yallist"2236+ ]2237+ },2238+ "magic-string@0.30.21": {2239+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",2240+ "dependencies": [2241+ "@jridgewell/sourcemap-codec"2242+ ]2243+ },2244+ "magicast@0.5.3": {2245+ "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==",2246+ "dependencies": [2247+ "@babel/parser",2248+ "@babel/types",2249+ "source-map-js"2250+ ]2251+ },2252+ "mdast-util-to-hast@13.2.1": {2253+ "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",2254+ "dependencies": [2255+ "@types/hast",2256+ "@types/mdast",2257+ "@ungap/structured-clone",2258+ "devlop",2259+ "micromark-util-sanitize-uri",2260+ "trim-lines",2261+ "unist-util-position",2262+ "unist-util-visit",2263+ "vfile"2264+ ]2265+ },2266+ "mdn-data@2.0.28": {2267+ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="2268+ },2269+ "mdn-data@2.27.1": {2270+ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="2271+ },2272+ "micromark-util-character@2.1.1": {2273+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",2274+ "dependencies": [2275+ "micromark-util-symbol",2276+ "micromark-util-types"2277+ ]2278+ },2279+ "micromark-util-encode@2.0.1": {2280+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="2281+ },2282+ "micromark-util-sanitize-uri@2.0.1": {2283+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",2284+ "dependencies": [2285+ "micromark-util-character",2286+ "micromark-util-encode",2287+ "micromark-util-symbol"2288+ ]2289+ },2290+ "micromark-util-symbol@2.0.1": {2291+ "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="2292+ },2293+ "micromark-util-types@2.0.2": {2294+ "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="2295+ },2296+ "mrmime@2.0.1": {2297+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="2298+ },2299+ "ms@2.1.3": {2300+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="2301+ },2302+ "muggle-string@0.4.1": {2303+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="2304+ },2305+ "nanoid@3.3.16": {2306+ "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",2307+ "bin": true2308+ },2309+ "neotraverse@0.6.18": {2310+ "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="2311+ },2312+ "nlcst-to-string@4.0.0": {2313+ "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==",2314+ "dependencies": [2315+ "@types/nlcst"2316+ ]2317+ },2318+ "node-fetch-native@1.6.7": {2319+ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="2320+ },2321+ "node-html-parser@6.1.13": {2322+ "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==",2323+ "dependencies": [2324+ "css-select",2325+ "he"2326+ ]2327+ },2328+ "node-mock-http@1.0.4": {2329+ "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="2330+ },2331+ "node-releases@2.0.51": {2332+ "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="2333+ },2334+ "normalize-path@3.0.0": {2335+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="2336+ },2337+ "nth-check@2.1.1": {2338+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",2339+ "dependencies": [2340+ "boolbase"2341+ ]2342+ },2343+ "obug@2.1.3": {2344+ "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg=="2345+ },2346+ "ofetch@1.5.1": {2347+ "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==",2348+ "dependencies": [2349+ "destr",2350+ "node-fetch-native",2351+ "ufo"2352+ ]2353+ },2354+ "ohash@2.0.11": {2355+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="2356+ },2357+ "oniguruma-parser@0.12.2": {2358+ "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="2359+ },2360+ "oniguruma-to-es@4.3.6": {2361+ "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==",2362+ "dependencies": [2363+ "oniguruma-parser",2364+ "regex",2365+ "regex-recursion"2366+ ]2367+ },2368+ "p-limit@7.3.0": {2369+ "integrity": "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==",2370+ "dependencies": [2371+ "yocto-queue"2372+ ]2373+ },2374+ "p-queue@9.3.1": {2375+ "integrity": "sha512-POWdiIPmsUPGwb4FeQ4OBg46aqmcInSWe45CKDsGHiOBiVQM9chqfQTuqhuTzcg2Vz9faTI65at0KkVyVEiCHw==",2376+ "dependencies": [2377+ "eventemitter3",2378+ "p-timeout"2379+ ]2380+ },2381+ "p-timeout@7.0.1": {2382+ "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="2383+ },2384+ "package-manager-detector@1.7.0": {2385+ "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ=="2386+ },2387+ "parse5@7.3.0": {2388+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",2389+ "dependencies": [2390+ "entities@6.0.1"2391+ ]2392+ },2393+ "path-browserify@1.0.1": {2394+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="2395+ },2396+ "piccolore@0.1.3": {2397+ "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="2398+ },2399+ "picocolors@1.1.1": {2400+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="2401+ },2402+ "picomatch@2.3.2": {2403+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="2404+ },2405+ "picomatch@4.0.5": {2406+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="2407+ },2408+ "pluralize-esm@9.0.5": {2409+ "integrity": "sha512-Kb2dcpMsIutFw2hYrN0EhsAXOUJTd6FVMIxvNAkZCMQLVt9NGZqQczvGpYDxNWCZeCWLHUPxQIBudWzt1h7VVA=="2410+ },2411+ "postcss@8.5.19": {2412+ "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==",2413+ "dependencies": [2414+ "nanoid",2415+ "picocolors",2416+ "source-map-js"2417+ ]2418+ },2419+ "preact-render-to-string@6.7.0_preact@10.29.7": {2420+ "integrity": "sha512-Z4WR8fmLMRpdYqJ9i7vrlXSsSrxVJydwrkEXHapexfARbWfGb7vGcnvNQnIzN0cXciMVOlz/XLoiMCi9gUsy9Q==",2421+ "dependencies": [2422+ "preact"2423+ ]2424+ },2425+ "preact@10.29.7_preact-render-to-string@6.7.0": {2426+ "integrity": "sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==",2427+ "dependencies": [2428+ "preact-render-to-string"2429+ ],2430+ "optionalPeers": [2431+ "preact-render-to-string"2432+ ]2433+ },2434+ "prettier@3.9.5": {2435+ "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==",2436+ "bin": true2437+ },2438+ "prismjs@1.30.0": {2439+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="2440+ },2441+ "process-ancestry@0.1.0": {2442+ "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg=="2443+ },2444+ "property-information@7.2.0": {2445+ "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="2446+ },2447+ "protobufjs@8.0.1": {2448+ "integrity": "sha512-NWWCCscLjs+cOKF/s/XVNFRW7Yih0fdH+9brffR5NZCy8k42yRdl5KlWKMVXuI1vfCoy4o1z80XR/W/QUb3V3w==",2449+ "dependencies": [2450+ "@protobufjs/aspromise",2451+ "@protobufjs/base64",2452+ "@protobufjs/codegen",2453+ "@protobufjs/eventemitter",2454+ "@protobufjs/fetch",2455+ "@protobufjs/float",2456+ "@protobufjs/inquire",2457+ "@protobufjs/path",2458+ "@protobufjs/pool",2459+ "@protobufjs/utf8",2460+ "@types/node",2461+ "long"2462+ ],2463+ "scripts": true2464+ },2465+ "radix3@1.1.2": {2466+ "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="2467+ },2468+ "readdirp@4.1.2": {2469+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="2470+ },2471+ "readdirp@5.0.0": {2472+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="2473+ },2474+ "regex-recursion@6.0.2": {2475+ "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==",2476+ "dependencies": [2477+ "regex-utilities"2478+ ]2479+ },2480+ "regex-utilities@2.3.0": {2481+ "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="2482+ },2483+ "regex@6.1.0": {2484+ "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==",2485+ "dependencies": [2486+ "regex-utilities"2487+ ]2488+ },2489+ "request-light@0.5.8": {2490+ "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="2491+ },2492+ "request-light@0.7.0": {2493+ "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="2494+ },2495+ "require-directory@2.1.1": {2496+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="2497+ },2498+ "require-from-string@2.0.2": {2499+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="2500+ },2501+ "resolve-pkg-maps@1.0.0": {2502+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="2503+ },2504+ "retext-smartypants@6.2.0": {2505+ "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==",2506+ "dependencies": [2507+ "@types/nlcst",2508+ "nlcst-to-string",2509+ "unist-util-visit"2510+ ]2511+ },2512+ "rolldown@1.0.0-rc.10_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {2513+ "integrity": "sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==",2514+ "dependencies": [2515+ "@oxc-project/types@0.120.0",2516+ "@rolldown/pluginutils@1.0.0-rc.10"2517+ ],2518+ "optionalDependencies": [2519+ "@rolldown/binding-android-arm64@1.0.0-rc.10",2520+ "@rolldown/binding-darwin-arm64@1.0.0-rc.10",2521+ "@rolldown/binding-darwin-x64@1.0.0-rc.10",2522+ "@rolldown/binding-freebsd-x64@1.0.0-rc.10",2523+ "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10",2524+ "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10",2525+ "@rolldown/binding-linux-arm64-musl@1.0.0-rc.10",2526+ "@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10",2527+ "@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10",2528+ "@rolldown/binding-linux-x64-gnu@1.0.0-rc.10",2529+ "@rolldown/binding-linux-x64-musl@1.0.0-rc.10",2530+ "@rolldown/binding-openharmony-arm64@1.0.0-rc.10",2531+ "@rolldown/binding-wasm32-wasi@1.0.0-rc.10_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1",2532+ "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10",2533+ "@rolldown/binding-win32-x64-msvc@1.0.0-rc.10"2534+ ],2535+ "bin": true2536+ },2537+ "rolldown@1.1.5": {2538+ "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==",2539+ "dependencies": [2540+ "@oxc-project/types@0.139.0",2541+ "@rolldown/pluginutils@1.0.1"2542+ ],2543+ "optionalDependencies": [2544+ "@rolldown/binding-android-arm64@1.1.5",2545+ "@rolldown/binding-darwin-arm64@1.1.5",2546+ "@rolldown/binding-darwin-x64@1.1.5",2547+ "@rolldown/binding-freebsd-x64@1.1.5",2548+ "@rolldown/binding-linux-arm-gnueabihf@1.1.5",2549+ "@rolldown/binding-linux-arm64-gnu@1.1.5",2550+ "@rolldown/binding-linux-arm64-musl@1.1.5",2551+ "@rolldown/binding-linux-ppc64-gnu@1.1.5",2552+ "@rolldown/binding-linux-s390x-gnu@1.1.5",2553+ "@rolldown/binding-linux-x64-gnu@1.1.5",2554+ "@rolldown/binding-linux-x64-musl@1.1.5",2555+ "@rolldown/binding-openharmony-arm64@1.1.5",2556+ "@rolldown/binding-wasm32-wasi@1.1.5",2557+ "@rolldown/binding-win32-arm64-msvc@1.1.5",2558+ "@rolldown/binding-win32-x64-msvc@1.1.5"2559+ ],2560+ "bin": true2561+ },2562+ "satteri@0.9.5": {2563+ "integrity": "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==",2564+ "dependencies": [2565+ "@types/estree-jsx",2566+ "@types/hast",2567+ "@types/mdast",2568+ "@types/unist"2569+ ],2570+ "optionalDependencies": [2571+ "@bruits/satteri-darwin-arm64",2572+ "@bruits/satteri-darwin-x64",2573+ "@bruits/satteri-linux-arm64-gnu",2574+ "@bruits/satteri-linux-arm64-musl",2575+ "@bruits/satteri-linux-x64-gnu",2576+ "@bruits/satteri-linux-x64-musl",2577+ "@bruits/satteri-wasm32-wasi",2578+ "@bruits/satteri-win32-arm64-msvc",2579+ "@bruits/satteri-win32-x64-msvc"2580+ ]2581+ },2582+ "sax@1.6.0": {2583+ "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="2584+ },2585+ "semver@6.3.1": {2586+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",2587+ "bin": true2588+ },2589+ "semver@7.8.5": {2590+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",2591+ "bin": true2592+ },2593+ "sharp@0.35.3": {2594+ "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==",2595+ "dependencies": [2596+ "@img/colour",2597+ "detect-libc",2598+ "semver@7.8.5"2599+ ],2600+ "optionalDependencies": [2601+ "@img/sharp-darwin-arm64",2602+ "@img/sharp-darwin-x64",2603+ "@img/sharp-freebsd-wasm32",2604+ "@img/sharp-libvips-darwin-arm64",2605+ "@img/sharp-libvips-darwin-x64",2606+ "@img/sharp-libvips-linux-arm",2607+ "@img/sharp-libvips-linux-arm64",2608+ "@img/sharp-libvips-linux-ppc64",2609+ "@img/sharp-libvips-linux-riscv64",2610+ "@img/sharp-libvips-linux-s390x",2611+ "@img/sharp-libvips-linux-x64",2612+ "@img/sharp-libvips-linuxmusl-arm64",2613+ "@img/sharp-libvips-linuxmusl-x64",2614+ "@img/sharp-linux-arm",2615+ "@img/sharp-linux-arm64",2616+ "@img/sharp-linux-ppc64",2617+ "@img/sharp-linux-riscv64",2618+ "@img/sharp-linux-s390x",2619+ "@img/sharp-linux-x64",2620+ "@img/sharp-linuxmusl-arm64",2621+ "@img/sharp-linuxmusl-x64",2622+ "@img/sharp-webcontainers-wasm32",2623+ "@img/sharp-win32-arm64",2624+ "@img/sharp-win32-ia32",2625+ "@img/sharp-win32-x64"2626+ ]2627+ },2628+ "shiki@4.3.1": {2629+ "integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==",2630+ "dependencies": [2631+ "@shikijs/core",2632+ "@shikijs/engine-javascript",2633+ "@shikijs/engine-oniguruma",2634+ "@shikijs/langs",2635+ "@shikijs/themes",2636+ "@shikijs/types",2637+ "@shikijs/vscode-textmate",2638+ "@types/hast"2639+ ]2640+ },2641+ "simple-code-frame@1.3.0": {2642+ "integrity": "sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==",2643+ "dependencies": [2644+ "kolorist"2645+ ]2646+ },2647+ "sisteransi@1.0.5": {2648+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="2649+ },2650+ "smol-toml@1.7.0": {2651+ "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ=="2652+ },2653+ "source-map-js@1.2.1": {2654+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="2655+ },2656+ "source-map@0.7.6": {2657+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="2658+ },2659+ "space-separated-tokens@2.0.2": {2660+ "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="2661+ },2662+ "stack-trace@1.0.0": {2663+ "integrity": "sha512-H6D7134xi6qONvh7ZHKgviXf+rd3vhGBSvebPZCaUkd8zvQ+7PtDw6CljPTe4cXWNf2IKZGNqw6VJXSb9IgBpA=="2664+ },2665+ "string-width@4.2.3": {2666+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",2667+ "dependencies": [2668+ "emoji-regex",2669+ "is-fullwidth-code-point",2670+ "strip-ansi"2671+ ]2672+ },2673+ "stringify-entities@4.0.4": {2674+ "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",2675+ "dependencies": [2676+ "character-entities-html4",2677+ "character-entities-legacy"2678+ ]2679+ },2680+ "strip-ansi@6.0.1": {2681+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",2682+ "dependencies": [2683+ "ansi-regex"2684+ ]2685+ },2686+ "svgo@4.0.2": {2687+ "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==",2688+ "dependencies": [2689+ "commander",2690+ "css-select",2691+ "css-tree@3.2.1",2692+ "css-what",2693+ "csso",2694+ "picocolors",2695+ "sax"2696+ ],2697+ "bin": true2698+ },2699+ "tiny-inflate@1.0.3": {2700+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="2701+ },2702+ "tinyclip@0.1.15": {2703+ "integrity": "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A=="2704+ },2705+ "tinyexec@1.2.4": {2706+ "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="2707+ },2708+ "tinyglobby@0.2.17": {2709+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",2710+ "dependencies": [2711+ "fdir",2712+ "picomatch@4.0.5"2713+ ]2714+ },2715+ "trim-lines@3.0.1": {2716+ "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="2717+ },2718+ "trough@2.2.0": {2719+ "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="2720+ },2721+ "ts-algebra@2.0.0": {2722+ "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="2723+ },2724+ "tslib@2.8.1": {2725+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="2726+ },2727+ "typesafe-path@0.2.2": {2728+ "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="2729+ },2730+ "typescript-auto-import-cache@0.3.6": {2731+ "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==",2732+ "dependencies": [2733+ "semver@7.8.5"2734+ ]2735+ },2736+ "typescript@6.0.3": {2737+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",2738+ "bin": true2739+ },2740+ "ufo@1.6.4": {2741+ "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="2742+ },2743+ "ultrahtml@1.7.0": {2744+ "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g=="2745+ },2746+ "uncrypto@0.1.3": {2747+ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="2748+ },2749+ "undici-types@8.3.0": {2750+ "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="2751+ },2752+ "unified@11.0.5": {2753+ "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",2754+ "dependencies": [2755+ "@types/unist",2756+ "bail",2757+ "devlop",2758+ "extend",2759+ "is-plain-obj",2760+ "trough",2761+ "vfile"2762+ ]2763+ },2764+ "unifont@0.7.4": {2765+ "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==",2766+ "dependencies": [2767+ "css-tree@3.2.1",2768+ "ofetch",2769+ "ohash"2770+ ]2771+ },2772+ "unist-util-is@6.0.1": {2773+ "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",2774+ "dependencies": [2775+ "@types/unist"2776+ ]2777+ },2778+ "unist-util-position@5.0.0": {2779+ "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",2780+ "dependencies": [2781+ "@types/unist"2782+ ]2783+ },2784+ "unist-util-stringify-position@4.0.0": {2785+ "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",2786+ "dependencies": [2787+ "@types/unist"2788+ ]2789+ },2790+ "unist-util-visit-parents@6.0.2": {2791+ "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",2792+ "dependencies": [2793+ "@types/unist",2794+ "unist-util-is"2795+ ]2796+ },2797+ "unist-util-visit@5.1.0": {2798+ "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",2799+ "dependencies": [2800+ "@types/unist",2801+ "unist-util-is",2802+ "unist-util-visit-parents"2803+ ]2804+ },2805+ "unstorage@1.17.5": {2806+ "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==",2807+ "dependencies": [2808+ "anymatch",2809+ "chokidar@5.0.0",2810+ "destr",2811+ "h3",2812+ "lru-cache@11.5.2",2813+ "node-fetch-native",2814+ "ofetch",2815+ "ufo"2816+ ]2817+ },2818+ "update-browserslist-db@1.2.3_browserslist@4.28.6": {2819+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",2820+ "dependencies": [2821+ "browserslist",2822+ "escalade",2823+ "picocolors"2824+ ],2825+ "bin": true2826+ },2827+ "vfile-location@5.0.3": {2828+ "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",2829+ "dependencies": [2830+ "@types/unist",2831+ "vfile"2832+ ]2833+ },2834+ "vfile-message@4.0.3": {2835+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",2836+ "dependencies": [2837+ "@types/unist",2838+ "unist-util-stringify-position"2839+ ]2840+ },2841+ "vfile@6.0.3": {2842+ "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",2843+ "dependencies": [2844+ "@types/unist",2845+ "vfile-message"2846+ ]2847+ },2848+ "vite-prerender-plugin@0.5.13_vite@8.1.4__esbuild@0.28.1": {2849+ "integrity": "sha512-IKSpYkzDBsKAxa05naRbj7GvNVMSdww/Z/E89oO3xndz+gWnOBOKOAbEXv7qDhktY/j3vHgJmoV1pPzqU2tx9g==",2850+ "dependencies": [2851+ "kolorist",2852+ "magic-string",2853+ "node-html-parser",2854+ "simple-code-frame",2855+ "source-map",2856+ "stack-trace",2857+ "vite@8.1.4_esbuild@0.28.1"2858+ ]2859+ },2860+ "vite@8.0.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1": {2861+ "integrity": "sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==",2862+ "dependencies": [2863+ "lightningcss",2864+ "picomatch@4.0.5",2865+ "postcss",2866+ "rolldown@1.0.0-rc.10_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1",2867+ "tinyglobby"2868+ ],2869+ "optionalDependencies": [2870+ "fsevents"2871+ ],2872+ "bin": true2873+ },2874+ "vite@8.1.4_esbuild@0.28.1": {2875+ "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==",2876+ "dependencies": [2877+ "esbuild@0.28.1",2878+ "lightningcss",2879+ "picomatch@4.0.5",2880+ "postcss",2881+ "rolldown@1.1.5",2882+ "tinyglobby"2883+ ],2884+ "optionalDependencies": [2885+ "fsevents"2886+ ],2887+ "optionalPeers": [2888+ "esbuild@0.28.1"2889+ ],2890+ "bin": true2891+ },2892+ "vitefu@1.1.3_vite@8.1.4__esbuild@0.28.1_esbuild@0.28.1": {2893+ "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",2894+ "dependencies": [2895+ "vite@8.1.4_esbuild@0.28.1"2896+ ],2897+ "optionalPeers": [2898+ "vite@8.1.4_esbuild@0.28.1"2899+ ]2900+ },2901+ "volar-service-css@0.0.71_@volar+language-service@2.4.28": {2902+ "integrity": "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw==",2903+ "dependencies": [2904+ "@volar/language-service",2905+ "vscode-css-languageservice",2906+ "vscode-languageserver-textdocument",2907+ "vscode-uri"2908+ ],2909+ "optionalPeers": [2910+ "@volar/language-service"2911+ ]2912+ },2913+ "volar-service-emmet@0.0.71_@volar+language-service@2.4.28": {2914+ "integrity": "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA==",2915+ "dependencies": [2916+ "@emmetio/css-parser",2917+ "@emmetio/html-matcher",2918+ "@volar/language-service",2919+ "@vscode/emmet-helper",2920+ "vscode-uri"2921+ ],2922+ "optionalPeers": [2923+ "@volar/language-service"2924+ ]2925+ },2926+ "volar-service-html@0.0.71_@volar+language-service@2.4.28": {2927+ "integrity": "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw==",2928+ "dependencies": [2929+ "@volar/language-service",2930+ "vscode-html-languageservice",2931+ "vscode-languageserver-textdocument",2932+ "vscode-uri"2933+ ],2934+ "optionalPeers": [2935+ "@volar/language-service"2936+ ]2937+ },2938+ "volar-service-prettier@0.0.71_@volar+language-service@2.4.28": {2939+ "integrity": "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg==",2940+ "dependencies": [2941+ "@volar/language-service",2942+ "vscode-uri"2943+ ],2944+ "optionalPeers": [2945+ "@volar/language-service"2946+ ]2947+ },2948+ "volar-service-typescript-twoslash-queries@0.0.71_@volar+language-service@2.4.28": {2949+ "integrity": "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A==",2950+ "dependencies": [2951+ "@volar/language-service",2952+ "vscode-uri"2953+ ],2954+ "optionalPeers": [2955+ "@volar/language-service"2956+ ]2957+ },2958+ "volar-service-typescript@0.0.71_@volar+language-service@2.4.28": {2959+ "integrity": "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw==",2960+ "dependencies": [2961+ "@volar/language-service",2962+ "path-browserify",2963+ "semver@7.8.5",2964+ "typescript-auto-import-cache",2965+ "vscode-languageserver-textdocument",2966+ "vscode-nls",2967+ "vscode-uri"2968+ ],2969+ "optionalPeers": [2970+ "@volar/language-service"2971+ ]2972+ },2973+ "volar-service-yaml@0.0.71_@volar+language-service@2.4.28": {2974+ "integrity": "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q==",2975+ "dependencies": [2976+ "@volar/language-service",2977+ "vscode-uri",2978+ "yaml-language-server"2979+ ],2980+ "optionalPeers": [2981+ "@volar/language-service"2982+ ]2983+ },2984+ "vscode-css-languageservice@6.3.10": {2985+ "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==",2986+ "dependencies": [2987+ "@vscode/l10n",2988+ "vscode-languageserver-textdocument",2989+ "vscode-languageserver-types@3.17.5",2990+ "vscode-uri"2991+ ]2992+ },2993+ "vscode-html-languageservice@5.6.2": {2994+ "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==",2995+ "dependencies": [2996+ "@vscode/l10n",2997+ "vscode-languageserver-textdocument",2998+ "vscode-languageserver-types@3.18.0",2999+ "vscode-uri"3000+ ]
diff truncated
M apps/reference/public/manifest.webmanifest +2 -2
R apps/reference/src/_lofi/ReferenceShell.astro → apps/reference/src/_lofi/Shell.astro +0 -0

No content changes.

A apps/reference/src/_lofi/diagnostics.ts +39 -0
M apps/reference/src/_lofi/runtime.ts +28 -33
@@ -1,7 +1,13 @@
11 import { BrowserAuthSecretStore, createDb, type Db } from "jazz-tools";2-import { ChecklistStore, type RuntimeDiagnostics } from "./checklist-store.ts";3-import { appId, databaseConfig } from "./config.ts";2+import { createDiagnostics, type RuntimeDiagnostics } from "./diagnostics.ts";3+import { appId, databaseConfig, serverUrl } from "./config.ts";44 import { assertDurableBrowser } from "./device-capabilities.ts";5+import {6+ createTableStore,7+ type TableHandle,8+ type TableRow,9+ type TableStore,10+} from "./table-store.ts";511 import {612 AdapterLifecycle,713 createSerializedResourceState,
@@ -13,8 +19,12 @@ import {
1319 1420 export type LofiRuntime = {1521 db: Db;16- checklist: ChecklistStore;1722 diagnostics: RuntimeDiagnostics;23+ /**24+ * A reactive store bound to one declared table. Repeated calls with the same25+ * table return the same store, so every consumer shares one subscription.26+ */27+ store<T extends TableRow, Init>(table: TableHandle<T, Init>): TableStore<T, Init>;1828 shutdown(): Promise<void>;1929 };2030
@@ -32,22 +42,7 @@ const browserGlobal = globalThis as typeof globalThis & { [slotName]?: RuntimeSl
3242 function slot(): RuntimeSlot {3343 browserGlobal[slotName] ??= {3444 client: createSerializedResourceState<Db>(),35- diagnostics: {36- storageState: "persistent-requested",37- clientsCreated: 0,38- activeClients: 0,39- activeConsumers: 0,40- activeVendorSubscriptions: 0,41- totalVendorSubscriptions: 0,42- activeMutationListeners: 0,43- totalMutationListeners: 0,44- unsubscribeCalls: 0,45- localWaitCalls: 0,46- pendingLocalWrites: 0,47- pendingGlobalWrites: 0,48- lastWriteDurability: "none",49- mutationErrors: 0,50- },45+ diagnostics: createDiagnostics(),5146 diagnosticListeners: new Set(),5247 };5348 return browserGlobal[slotName];
@@ -84,27 +79,27 @@ let recreationPromise: Promise<LofiRuntime> | null = null;
8479 let shutdownPromise: Promise<void> | null = null;8580 8681 function attachRuntime(state: RuntimeSlot, db: Db): LofiRuntime {87- const checklist = new ChecklistStore(88- db,89- state.diagnostics,90- undefined,91- () => notifyDiagnostics(state),92- );93- const stopMutationErrors = db.onMutationError((event) => checklist.reportMutationError(event));94- state.diagnostics.activeMutationListeners += 1;95- state.diagnostics.totalMutationListeners += 1;96- notifyDiagnostics(state);82+ const stores = new Map<object, TableStore<TableRow, unknown>>();9783 let active = true;9884 const runtime: LofiRuntime = {9985 db,100- checklist,10186 diagnostics: state.diagnostics,87+ store<T extends TableRow, Init>(table: TableHandle<T, Init>): TableStore<T, Init> {88+ let store = stores.get(table);89+ if (!store) {90+ store = createTableStore(db, table, state.diagnostics, {91+ syncConfigured: Boolean(serverUrl),92+ onDiagnosticsChange: () => notifyDiagnostics(state),93+ }) as TableStore<TableRow, unknown>;94+ stores.set(table, store);95+ }96+ return store as unknown as TableStore<T, Init>;97+ },10298 shutdown() {10399 if (!active) return Promise.resolve();104100 active = false;105- checklist.close();106- stopMutationErrors();107- state.diagnostics.activeMutationListeners -= 1;101+ for (const store of stores.values()) store.close();102+ stores.clear();108103 notifyDiagnostics(state);109104 return Promise.resolve();110105 },
R apps/reference/src/_lofi/checklist-store.ts → apps/reference/src/_lofi/table-store.ts +63 -59
@@ -1,71 +1,77 @@
1-import type { Db, MutationErrorEvent } from "jazz-tools";2-import { referenceApp } from "../app.ts";3-import { serverUrl } from "./config.ts";4-5-export type ChecklistTask = {6- id: string;7- text: string;8- completed: boolean;9- createdAt: Date;10-};1+import type { Db, MutationErrorEvent, QueryBuilder, TableProxy } from "jazz-tools";2+import type { RuntimeDiagnostics } from "./diagnostics.ts";3+4+/** The minimum shape every persisted row exposes to the framework. */5+export type TableRow = { id: string };116 12-export type ChecklistSnapshot = {7+/**8+ * A declared schema table (`schema.<name>`). It is both an insert/update/delete9+ * target and a query source, so the store accepts the intersection Jazz expects.10+ * `T` is the row type and `Init` the insert type (row minus server-owned fields).11+ */12+export type TableHandle<T extends TableRow, Init> = TableProxy<T, Init> & QueryBuilder<T>;13+14+export type TableSnapshot<T extends TableRow> = {1315 status: "loading" | "ready" | "error";14- tasks: ChecklistTask[];16+ rows: T[];1517 durability: "none" | "local" | "global" | "failed";1618 error: string | null;1719 };1820 19-export type RuntimeDiagnostics = {20- storageState: "persistent-requested" | "persistent-driver-open" | "failed";21- clientsCreated: number;22- activeClients: number;23- activeConsumers: number;24- activeVendorSubscriptions: number;25- totalVendorSubscriptions: number;26- activeMutationListeners: number;27- totalMutationListeners: number;28- unsubscribeCalls: number;29- localWaitCalls: number;30- pendingLocalWrites: number;31- pendingGlobalWrites: number;32- lastWriteDurability: "none" | "local" | "global" | "failed";33- mutationErrors: number;34-};35-3621 type Listener = () => void;3722 type MutationHandle = {3823 wait(options: { tier: "local" | "global" }): Promise<unknown>;3924 };4025 41-export class ChecklistStore {26+export type TableStoreOptions = {27+ /** Whether managed sync is configured; gates global-durability waits. */28+ syncConfigured?: boolean;29+ /** Called whenever a diagnostics counter changes. */30+ onDiagnosticsChange?: () => void;31+};32+33+/**34+ * A generic, reactive store over a single declared table. It has no knowledge of35+ * the application schema beyond {@link TableRow}: callers bind it to one of their36+ * own `schema.<name>` tables and read/write typed rows through it.37+ */38+export class TableStore<T extends TableRow, Init> {4239 readonly #db: Db;40+ readonly #table: TableHandle<T, Init>;4341 readonly #diagnostics: RuntimeDiagnostics;4442 readonly #syncConfigured: boolean;4543 readonly #diagnosticsChanged: () => void;4644 readonly #listeners = new Set<Listener>();45+ readonly #stopMutationErrors: () => void;4746 #vendorUnsubscribe: (() => void) | null = null;4847 #writeGeneration = 0;49- #snapshot: ChecklistSnapshot = {48+ #snapshot: TableSnapshot<T> = {5049 status: "loading",51- tasks: [],50+ rows: [],5251 durability: "none",5352 error: null,5453 };5554 5655 constructor(5756 db: Db,57+ table: TableHandle<T, Init>,5858 diagnostics: RuntimeDiagnostics,59- syncConfigured = Boolean(serverUrl),60- diagnosticsChanged: () => void = () => undefined,59+ options: TableStoreOptions = {},6160 ) {6261 this.#db = db;62+ this.#table = table;6363 this.#diagnostics = diagnostics;64- this.#syncConfigured = syncConfigured;65- this.#diagnosticsChanged = diagnosticsChanged;64+ this.#syncConfigured = options.syncConfigured ?? false;65+ this.#diagnosticsChanged = options.onDiagnosticsChange ?? (() => undefined);66+ // Asynchronous write rejections that are not tied to an awaited mutation67+ // still have to reach diagnostics and the UI, so the store owns this listener.68+ this.#stopMutationErrors = db.onMutationError((event) => this.reportMutationError(event));69+ this.#diagnostics.activeMutationListeners += 1;70+ this.#diagnostics.totalMutationListeners += 1;71+ this.#diagnosticsChanged();6672 }6773 68- getSnapshot = (): ChecklistSnapshot => this.#snapshot;74+ getSnapshot = (): TableSnapshot<T> => this.#snapshot;6975 7076 subscribe = (listener: Listener): () => void => {7177 this.#listeners.add(listener);
@@ -85,29 +91,16 @@ export class ChecklistStore {
8591 };8692 };8793 88- async create(text: string): Promise<void> {89- const now = new Date();90- await this.#settle(this.#db.insert(referenceApp.schema.tasks, {91- text,92- completed: false,93- createdAt: now,94- }));95- }96-97- async update(id: string, text: string): Promise<void> {98- await this.#settle(99- this.#db.update(referenceApp.schema.tasks, id, { text }),100- );94+ async insert(values: Init): Promise<void> {95+ await this.#settle(this.#db.insert(this.#table, values));10196 }10297 103- async setCompleted(id: string, completed: boolean): Promise<void> {104- await this.#settle(105- this.#db.update(referenceApp.schema.tasks, id, { completed }),106- );98+ async update(id: string, patch: Partial<Init>): Promise<void> {99+ await this.#settle(this.#db.update(this.#table, id, patch));107100 }108101 109102 async delete(id: string): Promise<void> {110- await this.#settle(this.#db.delete(referenceApp.schema.tasks, id));103+ await this.#settle(this.#db.delete(this.#table, id));111104 }112105 113106 reportMutationError(event: MutationErrorEvent): void {
@@ -119,8 +112,10 @@ export class ChecklistStore {
119112 close(): void {120113 this.#listeners.clear();121114 this.#diagnostics.activeConsumers = 0;122- this.#diagnosticsChanged();123115 this.#closeVendorSubscription();116+ this.#stopMutationErrors();117+ this.#diagnostics.activeMutationListeners -= 1;118+ this.#diagnosticsChanged();124119 }125120 126121 async #settle(mutation: MutationHandle): Promise<void> {
@@ -169,11 +164,11 @@ export class ChecklistStore {
169164 #openVendorSubscription(): void {170165 if (this.#vendorUnsubscribe) return;171166 try {172- this.#vendorUnsubscribe = this.#db.subscribeAll(referenceApp.schema.tasks, (delta) => {167+ this.#vendorUnsubscribe = this.#db.subscribeAll(this.#table, (delta) => {173168 this.#snapshot = {174169 ...this.#snapshot,175170 status: "ready",176- tasks: delta.all as ChecklistTask[],171+ rows: delta.all,177172 error: null,178173 };179174 this.#emit();
@@ -195,7 +190,7 @@ export class ChecklistStore {
195190 this.#diagnosticsChanged();196191 }197192 198- #set(change: Partial<ChecklistSnapshot>): void {193+ #set(change: Partial<TableSnapshot<T>>): void {199194 this.#snapshot = { ...this.#snapshot, ...change };200195 if (change.durability) {201196 this.#diagnostics.lastWriteDurability = change.durability;
@@ -220,3 +215,12 @@ export class ChecklistStore {
220215 for (const listener of this.#listeners) listener();221216 }222217 }218+219+export function createTableStore<T extends TableRow, Init>(220+ db: Db,221+ table: TableHandle<T, Init>,222+ diagnostics: RuntimeDiagnostics,223+ options: TableStoreOptions = {},224+): TableStore<T, Init> {225+ return new TableStore<T, Init>(db, table, diagnostics, options);226+}
R apps/reference/src/_lofi/checklist-store_test.ts → apps/reference/src/_lofi/table-store_test.ts +37 -34
@@ -1,27 +1,23 @@
11 import type { Db, MutationErrorEvent } from "jazz-tools";2-import { ChecklistStore, type RuntimeDiagnostics } from "./checklist-store.ts";2+import { createDiagnostics, type RuntimeDiagnostics } from "./diagnostics.ts";3+import { createTableStore, type TableHandle } from "./table-store.ts";34 import { assert, assertCount } from "./test-assert.ts";45 56 const test = (globalThis as unknown as {67 Deno: { test(name: string, body: () => void | Promise<void>): void };78 }).Deno.test;89 10+type Row = { id: string; text: string; completed: boolean; createdAt: Date };11+type RowInit = Omit<Row, "id">;12+13+const table = {} as unknown as TableHandle<Row, RowInit>;14+915 function diagnostics(): RuntimeDiagnostics {1016 return {17+ ...createDiagnostics(),1118 storageState: "persistent-driver-open",1219 clientsCreated: 1,1320 activeClients: 1,14- activeConsumers: 0,15- activeVendorSubscriptions: 0,16- totalVendorSubscriptions: 0,17- activeMutationListeners: 1,18- totalMutationListeners: 1,19- unsubscribeCalls: 0,20- localWaitCalls: 0,21- pendingLocalWrites: 0,22- pendingGlobalWrites: 0,23- lastWriteDurability: "none",24- mutationErrors: 0,2521 };2622 }2723
@@ -68,6 +64,9 @@ function fakeDb(options: { allowGlobal?: boolean } = {}) {
6864 subscriber = null;6965 };7066 },67+ onMutationError(_callback: (event: MutationErrorEvent) => void) {68+ return () => undefined;69+ },7170 insert(_collection: unknown, next: unknown) {7271 writes.push({ operation: "insert", value: next });7372 return handle();
@@ -107,10 +106,10 @@ function fakeDb(options: { allowGlobal?: boolean } = {}) {
107106 };108107 }109108 110-test("two consumers share one task subscription and clean up idempotently", () => {109+test("two consumers share one table subscription and clean up idempotently", () => {111110 const db = fakeDb();112111 const counts = diagnostics();113- const store = new ChecklistStore(db.value, counts);112+ const store = createTableStore<Row, RowInit>(db.value, table, counts);114113 let firstUpdates = 0;115114 let secondUpdates = 0;116115
@@ -121,13 +120,13 @@ test("two consumers share one task subscription and clean up idempotently", () =
121120 assertCount(counts.totalVendorSubscriptions, 1, "the underlying query should open once");122121 123122 db.publish([{124- id: "task-1",123+ id: "row-1",125124 text: "shared",126125 completed: false,127126 createdAt: new Date(0),128127 }]);129128 assert(store.getSnapshot().status === "ready", "the first query result must end loading");130- assert(store.getSnapshot().tasks.length === 1, "the query result must be published");129+ assert(store.getSnapshot().rows.length === 1, "the query result must be published");131130 assert(firstUpdates > 0 && secondUpdates > 0, "both roots must receive reactive updates");132131 133132 stopFirst();
@@ -142,27 +141,27 @@ test("two consumers share one task subscription and clean up idempotently", () =
142141 assertCount(counts.unsubscribeCalls, 1, "cleanup must remain externally diagnosable");143142 });144143 145-test("every checklist mutation exposes pending work and waits for local durability", async () => {144+test("every mutation exposes pending work and waits for local durability", async () => {146145 const db = fakeDb();147146 const counts = diagnostics();148- const store = new ChecklistStore(db.value, counts);147+ const store = createTableStore<Row, RowInit>(db.value, table, counts);149148 150149 const deferred = db.deferNextWrite();151- const first = store.create("first");150+ const first = store.insert({ text: "first", completed: false, createdAt: new Date(0) });152151 await Promise.resolve();153152 assertCount(counts.pendingLocalWrites, 1, "an unsettled local write must be observable");154153 assert(String(counts.lastWriteDurability) === "none", "pending work must not claim durability");155154 deferred.resolve();156155 await first;157156 assertCount(counts.pendingLocalWrites, 0, "a retained local write must leave no pending work");158- await store.update("task-1", "edited");159- await store.setCompleted("task-1", true);160- await store.delete("task-1");157+ await store.update("row-1", { text: "edited" });158+ await store.update("row-1", { completed: true });159+ await store.delete("row-1");161160 162161 assertCount(counts.localWaitCalls, 4, "each accepted mutation must await local durability");163162 assert(164163 db.writes.map((write) => write.operation).join(",") === "insert,update,update,delete",165- "create, edit, complete, and delete must reach the Jazz boundary",164+ "insert, edit, complete, and delete must reach the Jazz boundary",166165 );167166 assert(store.getSnapshot().durability === "local", "the UI may claim local after the wait");168167 assert(
@@ -178,8 +177,10 @@ test("every checklist mutation exposes pending work and waits for local durabili
178177 179178 test("configured sync advances the latest write from local to global durability", async () => {180179 const db = fakeDb({ allowGlobal: true });181- const store = new ChecklistStore(db.value, diagnostics(), true);182- await store.create("sync after reconnect");180+ const store = createTableStore<Row, RowInit>(db.value, table, diagnostics(), {181+ syncConfigured: true,182+ });183+ await store.insert({ text: "sync after reconnect", completed: false, createdAt: new Date(0) });183184 await Promise.resolve();184185 assert(185186 store.getSnapshot().durability === "global",
@@ -190,11 +191,11 @@ test("configured sync advances the latest write from local to global durability"
190191 191192 test("local write failures remain visible and reject the mutation", async () => {192193 const db = fakeDb();193- const store = new ChecklistStore(db.value, diagnostics());194+ const store = createTableStore<Row, RowInit>(db.value, table, diagnostics());194195 db.failNextWrite("disk full");195196 let rejected = false;196197 try {197- await store.create("cannot persist");198+ await store.insert({ text: "cannot persist", completed: false, createdAt: new Date(0) });198199 } catch {199200 rejected = true;200201 }
@@ -206,12 +207,12 @@ test("local write failures remain visible and reject the mutation", async () =>
206207 test("a superseded local-write failure remains visible", async () => {207208 const db = fakeDb();208209 const counts = diagnostics();209- const store = new ChecklistStore(db.value, counts);210+ const store = createTableStore<Row, RowInit>(db.value, table, counts);210211 const firstWrite = db.deferNextWrite();211212 212- const firstMutation = store.create("first");213+ const firstMutation = store.insert({ text: "first", completed: false, createdAt: new Date(0) });213214 await Promise.resolve();214- await store.create("newer");215+ await store.insert({ text: "newer", completed: false, createdAt: new Date(0) });215216 firstWrite.reject(new Error("first write lost"));216217 217218 let rejected = false;
@@ -229,12 +230,14 @@ test("a superseded local-write failure remains visible", async () => {
229230 230231 test("retrying after failure clears the error status immediately", async () => {231232 const db = fakeDb();232- const store = new ChecklistStore(db.value, diagnostics());233+ const store = createTableStore<Row, RowInit>(db.value, table, diagnostics());233234 db.failNextWrite("disk full");234- await store.create("fails").catch(() => undefined);235+ await store.insert({ text: "fails", completed: false, createdAt: new Date(0) }).catch(() =>236+ undefined237+ );235238 const retryWrite = db.deferNextWrite();236239 237- const retry = store.create("retry");240+ const retry = store.insert({ text: "retry", completed: false, createdAt: new Date(0) });238241 await Promise.resolve();239242 assert(store.getSnapshot().status === "ready", "retry must leave the failed list status");240243 assert(store.getSnapshot().error === null, "retry must not render a null error message");
@@ -245,7 +248,7 @@ test("retrying after failure clears the error status immediately", async () => {
245248 246249 test("public mutation errors update observable diagnostics", () => {247250 const counts = diagnostics();248- const store = new ChecklistStore(fakeDb().value, counts);251+ const store = createTableStore<Row, RowInit>(fakeDb().value, table, counts);249252 store.reportMutationError({250253 code: "WriteRejected",251254 reason: "permission denied",
D apps/reference/src/_lofi/use-checklist.ts +0 -63
@@ -1,63 +0,0 @@
1-import { useCallback, useEffect, useState } from "preact/hooks";2-import type { ChecklistSnapshot } from "./checklist-store.ts";3-import { getRuntime, runtimeRecreatedEvent } from "./runtime.ts";4-5-const initial: ChecklistSnapshot = {6- status: "loading",7- tasks: [],8- durability: "none",9- error: null,10-};11-12-export function useChecklist() {13- const [snapshot, setSnapshot] = useState(initial);14-15- useEffect(() => {16- let cancelled = false;17- let connectionGeneration = 0;18- let unsubscribe: (() => void) | undefined;19- const connect = () => {20- const generation = ++connectionGeneration;21- unsubscribe?.();22- unsubscribe = undefined;23- setSnapshot(initial);24- void getRuntime().then((runtime) => {25- if (cancelled || generation !== connectionGeneration) return;26- const update = () => setSnapshot(runtime.checklist.getSnapshot());27- unsubscribe = runtime.checklist.subscribe(update);28- update();29- }, (error) => {30- if (cancelled || generation !== connectionGeneration) return;31- setSnapshot({32- ...initial,33- status: "error",34- durability: "failed",35- error: error instanceof Error ? error.message : String(error),36- });37- });38- };39- connect();40- globalThis.addEventListener(runtimeRecreatedEvent, connect);41- return () => {42- cancelled = true;43- connectionGeneration += 1;44- globalThis.removeEventListener(runtimeRecreatedEvent, connect);45- unsubscribe?.();46- };47- }, []);48-49- const create = useCallback(async (text: string) => {50- await (await getRuntime()).checklist.create(text);51- }, []);52- const update = useCallback(async (id: string, text: string) => {53- await (await getRuntime()).checklist.update(id, text);54- }, []);55- const setCompleted = useCallback(async (id: string, completed: boolean) => {56- await (await getRuntime()).checklist.setCompleted(id, completed);57- }, []);58- const remove = useCallback(async (id: string) => {59- await (await getRuntime()).checklist.delete(id);60- }, []);61-62- return { ...snapshot, create, update, setCompleted, remove };63-}
M apps/reference/src/app.ts +1 -3
M apps/reference/src/env.d.ts +3 -0
D apps/reference/src/islands/ChecklistIsland.tsx +0 -135
@@ -1,135 +0,0 @@
1-import { useEffect, useState } from "preact/hooks";2-import type { ChecklistTask } from "../_lofi/checklist-store.ts";3-import { settleUiMutation } from "../_lofi/ui-mutation.ts";4-import { useChecklist } from "../_lofi/use-checklist.ts";5-import { checklistUi } from "../ui-contract.ts";6-7-export interface ChecklistIslandProps {8- label: string;9-}10-11-type ChecklistRowProps = {12- task: ChecklistTask;13- update(id: string, text: string): Promise<void>;14- setCompleted(id: string, completed: boolean): Promise<void>;15- remove(id: string): Promise<void>;16-};17-18-function ChecklistRow({ task, update, setCompleted, remove }: ChecklistRowProps) {19- const [editing, setEditing] = useState(false);20- const [draft, setDraft] = useState(task.text);21- const editId = `edit-${task.id}`;22-23- useEffect(() => {24- if (!editing) setDraft(task.text);25- }, [editing, task.text]);26-27- return (28- <li class={task.completed ? "task task-complete" : "task"} data-task-id={task.id}>29- <label class="task-toggle">30- <input31- type="checkbox"32- checked={task.completed}33- aria-label={checklistUi.complete(task.text)}34- onChange={(event) =>35- void settleUiMutation(setCompleted(task.id, event.currentTarget.checked))}36- />37- <span>{task.text}</span>38- </label>39- {editing40- ? (41- <form42- class="edit-form"43- onSubmit={(event) => {44- event.preventDefault();45- const next = draft.trim();46- if (!next) return;47- setEditing(false);48- void settleUiMutation(update(task.id, next));49- }}50- >51- <label class="visually-hidden" for={editId}>{checklistUi.edit(task.text)}</label>52- <input53- id={editId}54- value={draft}55- onInput={(event) => setDraft(event.currentTarget.value)}56- autocomplete="off"57- />58- <button type="submit" aria-label={checklistUi.save(task.text)}>Save</button>59- <button type="button" onClick={() => setEditing(false)}>Cancel</button>60- </form>61- )62- : (63- <div class="task-actions">64- <button65- type="button"66- aria-label={checklistUi.edit(task.text)}67- onClick={() => setEditing(true)}68- >69- Edit70- </button>71- <button72- type="button"73- class="button-danger"74- aria-label={checklistUi.delete(task.text)}75- onClick={() => void settleUiMutation(remove(task.id))}76- >77- Delete78- </button>79- </div>80- )}81- </li>82- );83-}84-85-export default function ChecklistIsland({ label }: ChecklistIslandProps) {86- const checklist = useChecklist();87- const [text, setText] = useState("");88- const inputId = `task-${label.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-")}`;89-90- return (91- <section class="island" data-island={label}>92- <header>93- <p class="eyebrow">{label}</p>94- <h2>Shared checklist</h2>95- </header>96- <form97- onSubmit={(event) => {98- event.preventDefault();99- const next = text.trim();100- if (!next) return;101- setText("");102- void settleUiMutation(checklist.create(next));103- }}104- >105- <label for={inputId}>{checklistUi.newItem}</label>106- <div class="composer">107- <input108- id={inputId}109- value={text}110- onInput={(event) => setText(event.currentTarget.value)}111- autocomplete="off"112- />113- <button type="submit">{checklistUi.addFrom(label)}</button>114- </div>115- </form>116- <p class="state" role="status">117- {checklist.status === "loading" && "Opening persistent storage…"}118- {checklist.status === "error" && `${checklistUi.writeFailed} ${checklist.error}`}119- {checklist.status === "ready" &&120- `${checklist.tasks.length} item(s) · last write ${checklist.durability}`}121- </p>122- <ul aria-label={`${label} checklist`}>123- {checklist.tasks.map((task) => (124- <ChecklistRow125- key={task.id}126- task={task}127- update={checklist.update}128- setCompleted={checklist.setCompleted}129- remove={checklist.remove}130- />131- ))}132- </ul>133- </section>134- );135-}
A apps/reference/src/islands/TaskList.tsx +63 -0
@@ -0,0 +1,63 @@
1+import { useState } from "preact/hooks";2+import { settleUiMutation } from "../_lofi/ui-mutation.ts";3+import { useTasks } from "./use-tasks.ts";4+5+/**6+ * Author-owned starter UI. One island over one table: add a row, list rows, and7+ * toggle a boolean. Replace it with your own schema and components — the runtime8+ * under `src/_lofi/` stays the same.9+ */10+export default function TaskList() {11+ const { status, error, durability, tasks, create, setCompleted } = useTasks();12+ const [text, setText] = useState("");13+14+ return (15+ <section class="island" data-island="tasks">16+ <header>17+ <p class="eyebrow">Local-first</p>18+ <h2>Tasks</h2>19+ </header>20+ <form21+ onSubmit={(event) => {22+ event.preventDefault();23+ const next = text.trim();24+ if (!next) return;25+ setText("");26+ void settleUiMutation(create(next));27+ }}28+ >29+ <label for="new-task">New task</label>30+ <div class="composer">31+ <input32+ id="new-task"33+ value={text}34+ onInput={(event) => setText(event.currentTarget.value)}35+ autocomplete="off"36+ />37+ <button type="submit">Add</button>38+ </div>39+ </form>40+ <p class="state" role="status">41+ {status === "loading" && "Opening persistent storage…"}42+ {status === "error" && `Write failed: ${error}`}43+ {status === "ready" && `${tasks.length} item(s) · last write ${durability}`}44+ </p>45+ <ul aria-label="Tasks">46+ {tasks.map((task) => (47+ <li key={task.id} class={task.completed ? "task task-complete" : "task"}>48+ <label class="task-toggle">49+ <input50+ type="checkbox"51+ checked={task.completed}52+ aria-label={`Complete ${task.text}`}53+ onChange={(event) =>54+ void settleUiMutation(setCompleted(task.id, event.currentTarget.checked))}55+ />56+ <span>{task.text}</span>57+ </label>58+ </li>59+ ))}60+ </ul>61+ </section>62+ );63+}
A apps/reference/src/islands/use-tasks.ts +74 -0
@@ -0,0 +1,74 @@
1+import { useCallback, useEffect, useState } from "preact/hooks";2+import { schema as s } from "jazz-tools";3+import { referenceApp } from "../app.ts";4+import { getRuntime, runtimeRecreatedEvent } from "../_lofi/runtime.ts";5+import type { TableSnapshot } from "../_lofi/table-store.ts";6+7+/**8+ * Author-owned example. This is the whole binding between a declared table and9+ * the UI: pick a table from your schema, derive its row type, and wrap the10+ * generic store's writes in domain verbs. Replace `tasks` and the methods below11+ * with your own model — nothing under `src/_lofi/` needs to change.12+ */13+const tasksTable = referenceApp.schema.tasks;14+15+/** Row and insert types come straight from the declared schema. */16+export type Task = s.RowOf<typeof tasksTable>;17+18+const initial: TableSnapshot<Task> = {19+ status: "loading",20+ rows: [],21+ durability: "none",22+ error: null,23+};24+25+export function useTasks() {26+ const [snapshot, setSnapshot] = useState(initial);27+28+ useEffect(() => {29+ let cancelled = false;30+ let connectionGeneration = 0;31+ let unsubscribe: (() => void) | undefined;32+ const connect = () => {33+ const generation = ++connectionGeneration;34+ unsubscribe?.();35+ unsubscribe = undefined;36+ setSnapshot(initial);37+ void getRuntime().then((runtime) => {38+ if (cancelled || generation !== connectionGeneration) return;39+ const store = runtime.store(tasksTable);40+ const update = () => setSnapshot(store.getSnapshot());41+ unsubscribe = store.subscribe(update);42+ update();43+ }, (error) => {44+ if (cancelled || generation !== connectionGeneration) return;45+ setSnapshot({46+ ...initial,47+ status: "error",48+ durability: "failed",49+ error: error instanceof Error ? error.message : String(error),50+ });51+ });52+ };53+ connect();54+ globalThis.addEventListener(runtimeRecreatedEvent, connect);55+ return () => {56+ cancelled = true;57+ connectionGeneration += 1;58+ globalThis.removeEventListener(runtimeRecreatedEvent, connect);59+ unsubscribe?.();60+ };61+ }, []);62+63+ // The generic store also exposes `update` (for edits) and `delete`; this64+ // starter only needs insert and a boolean toggle. Add more verbs as you grow.65+ const store = useCallback(async () => (await getRuntime()).store(tasksTable), []);66+ const create = useCallback(async (text: string) => {67+ await (await store()).insert({ text, completed: false, createdAt: new Date() });68+ }, [store]);69+ const setCompleted = useCallback(async (id: string, completed: boolean) => {70+ await (await store()).update(id, { completed });71+ }, [store]);72+73+ return { ...snapshot, tasks: snapshot.rows, create, setCompleted };74+}
D apps/reference/src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts +0 -28
D apps/reference/src/migrations/snapshots/20260715T194819-6c62fec42c35.json +0 -20
D apps/reference/src/migrations/snapshots/20260715T194947-ff85ac1d97ee.json +0 -27
M apps/reference/src/pages/index.astro +10 -13
@@ -1,27 +1,24 @@
11 ---2-import ChecklistIsland from "../islands/ChecklistIsland";2+import TaskList from "../islands/TaskList";33 import DeviceStatus from "../_lofi/DeviceStatus";4-import ReferenceShell from "../_lofi/ReferenceShell.astro";4+import Shell from "../_lofi/Shell.astro";55 import "../styles/global.css";66 ---77 8-<ReferenceShell title="lofi checklist">8+<Shell title="lofi starter">99 <header class="hero">10- <p class="eyebrow">lofi reference application</p>11- <h1>A checklist that starts local.</h1>10+ <p class="eyebrow">lofi</p>11+ <h1>Local-first, by default.</h1>1212 <p>13- Create, edit, complete, and delete work without waiting for the network. Both independent14- islands render the same durable local data.13+ Add a task and it persists on this device immediately - the UI never waits on the network.14+ This starter is one island over one table; replace it with your own schema and components.1515 </p>1616 </header>17- <div class="island-grid">18- <ChecklistIsland label="North island" client:load />19- <ChecklistIsland label="South island" client:load />20- </div>17+ <TaskList client:load />2118 <aside class="identity-note" aria-label="Identity and recovery">2219 <strong>Identity stays on this device.</strong> Clearing site data removes access because23- passkey backup and recovery are not enabled in this reference application.20+ passkey backup and recovery are not enabled in this starter.2421 </aside>2522 <DeviceStatus client:load />2623 <footer>Thin Preact adapter · static Astro shell · Deno command surface</footer>27-</ReferenceShell>24+</Shell>
M apps/reference/src/permissions.ts +1 -1
M apps/reference/src/styles/global.css +4 -38
@@ -45,17 +45,11 @@ h1 {
4545 max-width: 48rem;4646 }4747 48-.island-grid {49- display: grid;50- gap: 1rem;51- grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));52- margin-top: 3rem;53-}54-5548 .island {5649 background: #22332c;5750 border: 1px solid #3b594c;5851 border-radius: 0.7rem;52+ margin-top: 3rem;5953 min-height: 24rem;6054 padding: 1.4rem;6155 }
@@ -105,9 +99,7 @@ label {
10599 margin-bottom: 0.5rem;106100 }107101 108-.composer,109-.edit-form,110-.task-actions {102+.composer {111103 display: flex;112104 gap: 0.5rem;113105 }
@@ -141,11 +133,6 @@ input:focus-visible {
141133 outline-offset: 2px;142134 }143135 144-.button-danger {145- background: transparent;146- color: #ffd6d6;147-}148-149136 .state {150137 color: #bed0c6;151138 min-height: 1.5rem;
@@ -162,9 +149,8 @@ ul {
162149 align-items: center;163150 background: #18231f;164151 border-left: 3px solid #99e5bd;165- display: grid;152+ display: flex;166153 gap: 0.75rem;167- grid-template-columns: minmax(0, 1fr) auto;168154 padding: 0.75rem 0.9rem;169155 }170156
@@ -190,10 +176,6 @@ ul {
190176 text-decoration: line-through;191177 }192178 193-.edit-form {194- grid-column: 1 / -1;195-}196-197179 .identity-note {198180 background: #1d2b25;199181 border: 1px solid #3b594c;
@@ -208,16 +190,6 @@ ul {
208190 color: #eff8f2;209191 }210192 211-.visually-hidden {212- clip: rect(0 0 0 0);213- clip-path: inset(50%);214- height: 1px;215- overflow: hidden;216- position: absolute;217- white-space: nowrap;218- width: 1px;219-}220-221193 footer {222194 color: #9bc9b1;223195 margin-top: 2rem;
@@ -228,14 +200,8 @@ footer {
228200 padding: 2.5rem 1rem;229201 }230202 231- .composer,232- .edit-form,233- .task-actions {203+ .composer {234204 align-items: stretch;235205 flex-direction: column;236206 }237-238- .task {239- grid-template-columns: 1fr;240- }241207 }
D apps/reference/src/ui-contract.ts +0 -10
M apps/reference/tests/author-boundary_test.ts +1 -1
A apps/reference/tests/convergence_e2e_test.ts +109 -0
@@ -0,0 +1,109 @@
1+import type {2+ BrowserTestClient,3+ ConcurrentOfflineScenario,4+ TwoClientFixture,5+} from "@nzip/lofi/testing";6+7+/**8+ * A real, worked example of the `@nzip/lofi/testing` toolkit: two browser9+ * clients each add a task while offline, then reconnect and converge on both.10+ *11+ * This is an opt-in browser gate, not part of `deno task test`:12+ * 1. Configure managed sync (JAZZ_APP_ID + JAZZ_SERVER_URL in .env) so two13+ * clients share one synced account, then serve the app — for example14+ * `deno task build` followed by `deno task preview`, or `deno task dev`.15+ * 2. Point the test at that URL and run it directly:16+ * LOFI_E2E_BASE_URL=http://127.0.0.1:4321/ deno test -A tests/convergence_e2e_test.ts17+ *18+ * Without LOFI_E2E_BASE_URL (or without Chromium installed) it skips, so the19+ * default suite stays fast and never launches a browser.20+ */21+22+function e2eBaseURL(): string | undefined {23+ // The default suite runs without --allow-env; treat a denied read as "skip".24+ try {25+ return Deno.env.get("LOFI_E2E_BASE_URL") || undefined;26+ } catch {27+ return undefined;28+ }29+}30+31+// Runs inside the browser page, so it may only touch DOM APIs: the status line32+// reports "N item(s) …" once the local store has hydrated.33+const taskListReady = () => {34+ const status = document.querySelector('[role="status"]');35+ return status !== null && /item\(s\)/.test(status.textContent ?? "");36+};37+38+Deno.test("two clients converge on concurrent offline task edits", async () => {39+ const baseURL = e2eBaseURL();40+ if (!baseURL) {41+ console.log(42+ "skipping convergence example; set LOFI_E2E_BASE_URL to a synced deployment to run it",43+ );44+ return;45+ }46+47+ // Imported lazily so the default suite never loads Playwright.48+ const {49+ BrowserUnavailableError,50+ createTwoClientFixture,51+ runConcurrentOfflineConvergence,52+ waitForReady,53+ } = await import("@nzip/lofi/testing");54+55+ const ready = (client: BrowserTestClient) =>56+ waitForReady(client.page, taskListReady, undefined, { description: `${client.name} ready` });57+ const addTask = async (client: BrowserTestClient, text: string) => {58+ await client.page.fill("#new-task", text);59+ await client.page.press("#new-task", "Enter");60+ };61+ const seeTask = (client: BrowserTestClient, text: string) =>62+ client.page.locator(".task", { hasText: text }).first().waitFor({63+ state: "visible",64+ timeout: 15_000,65+ });66+67+ let fixture: TwoClientFixture | undefined;68+ try {69+ fixture = await createTwoClientFixture({70+ baseURL,71+ // Shared identity clones the first client's device key in memory, so both72+ // browser contexts act as the same synced account.73+ identity: { mode: "shared", preparePrimary: ready },74+ artifacts: { directory: "test-results" },75+ });76+ } catch (error) {77+ if (error instanceof BrowserUnavailableError) {78+ console.log(error.message);79+ return;80+ }81+ throw error;82+ }83+84+ try {85+ const scenario: ConcurrentOfflineScenario<string> = {86+ edits: ["first client task", "second client task"],87+ ready,88+ apply: addTask,89+ locallyApplied: seeTask,90+ converged: async ({ clients }) => {91+ await Promise.all(clients.map((client) =>92+ Promise.all([93+ seeTask(client, "first client task"),94+ seeTask(client, "second client task"),95+ ])96+ ));97+ },98+ // Failure artifacts stay value-free: counts and booleans only, no task text.99+ snapshot: async (client) => ({100+ online: !client.offline,101+ items: await client.page.locator(".task").count(),102+ }),103+ failureLabel: "task-convergence",104+ };105+ await runConcurrentOfflineConvergence(fixture, scenario);106+ } finally {107+ await fixture.close();108+ }109+});
M deno.json +31 -16
@@ -1,4 +1,16 @@
11 {2+ "name": "@nzip/lofi",3+ "version": "0.1.0",4+ "license": "MIT",5+ "exports": {6+ "./build": "./package/commands/build.ts",7+ "./create": "./package/create.ts",8+ "./dev": "./package/commands/dev.ts",9+ "./doctor": "./package/commands/doctor.ts",10+ "./preview": "./package/commands/preview.ts",11+ "./testing": "./package/testing/mod.ts",12+ "./test": "./package/commands/run_tests.ts"13+ },214 "imports": {315 "@astrojs/check": "npm:@astrojs/check@0.9.9",416 "@astrojs/preact": "npm:@astrojs/preact@6.0.1",
@@ -22,26 +34,11 @@
2234 "jsxImportSource": "preact"2335 },2436 "tasks": {25- "check:env": "deno run --allow-env=JAZZ_APP_ID,JAZZ_SERVER_URL,JAZZ_ADMIN_SECRET,BACKEND_SECRET --allow-read=.env tools/check_env.ts",26- "check:secrets": "deno run --allow-env=JAZZ_ADMIN_SECRET,BACKEND_SECRET --allow-read --allow-run=git tools/check_secret_leaks.ts",27- "check:migrations": "deno run --allow-read=apps/reference/src/migrations --allow-run tools/check_migrations.ts",28- "check:astro": "LOFI_SKIP_JAZZ_MANAGED=1 JAZZ_ADMIN_SECRET= BACKEND_SECRET= deno run -A npm:astro@7.0.9 check --root apps/reference",29- "check": "deno fmt --check && deno lint && deno check package/**/*.ts tools/*.ts spikes/jazz2-baseline/*.ts spikes/jazz2-baseline/src/*.ts apps/reference/*.ts apps/reference/src/**/*.ts apps/reference/src/**/*.tsx && deno task check:astro && deno task check:env && deno task check:secrets && deno task check:migrations && deno task test",3037 "test:unit": "deno test --allow-env=LOFI_UPDATE_SNAPSHOT --allow-net=127.0.0.1 --allow-read --allow-write=. --allow-run tools package apps/reference/src/_lofi apps/reference/tests",3138 "test:update:create": "LOFI_UPDATE_SNAPSHOT=1 deno test --allow-env=LOFI_UPDATE_SNAPSHOT --allow-read --allow-write=. --allow-run package/create_core_test.ts",3239 "test": "deno task test:unit",3340 "test:browser:install": "deno run -A npm:playwright@1.61.1 install chromium",34- "test:golden:checkout": "deno run -A tools/golden_path_checkout.ts",35- "test:golden:create": "deno run -A tools/golden_path_create.ts",36- "dev": "deno run --allow-env=JAZZ_APP_ID,JAZZ_SERVER_URL,JAZZ_ADMIN_SECRET,BACKEND_SECRET --allow-read=.env,apps/reference/.env --allow-write=apps/reference/.env --allow-run tools/run_reference.ts dev",37- "build": "deno run --allow-env=JAZZ_APP_ID,JAZZ_SERVER_URL,JAZZ_ADMIN_SECRET,BACKEND_SECRET --allow-read=.env,apps/reference/.env,apps/reference/dist --allow-write=apps/reference/.env,apps/reference/dist --allow-run tools/run_reference.ts build",38- "schema:validate": "deno run -A npm:jazz-tools@2.0.0-alpha.53 validate --schema-dir apps/reference/src",39- "schema:deploy": "deno run --env-file=.env -A npm:jazz-tools@2.0.0-alpha.53 deploy --schema-dir apps/reference/src --migrations-dir apps/reference/src/migrations",40- "preview": "deno run --allow-net --allow-read=apps/reference/dist tools/preview.ts",41- "spike:jazz2:dev": "deno run --allow-read=spikes/jazz2-baseline/.env --allow-write=spikes/jazz2-baseline/.env --allow-run tools/run_jazz2_spike.ts local",42- "spike:jazz2:cloud": "deno run --allow-read=spikes/jazz2-baseline/.env --allow-write=spikes/jazz2-baseline/.env --allow-run tools/run_jazz2_spike.ts cloud",43- "spike:jazz2:build": "deno run -A npm:vite@8.0.1 build spikes/jazz2-baseline --config spikes/jazz2-baseline/vite.config.ts",44- "spike:jazz2:preview": "deno run -A npm:vite@8.0.1 preview spikes/jazz2-baseline --config spikes/jazz2-baseline/vite.config.ts --host 127.0.0.1"41+ "publish:dry": "deno publish --dry-run"4542 },4643 "fmt": {4744 "lineWidth": 100,
@@ -52,5 +49,23 @@
5249 "rules": {5350 "tags": ["recommended"]5451 }52+ },53+ "publish": {54+ "include": [55+ "LICENSE",56+ "README.md",57+ "apps/reference/astro.config.ts",58+ "apps/reference/deno.json",59+ "apps/reference/public",60+ "apps/reference/src",61+ "apps/reference/tests",62+ "apps/reference/tsconfig.json",63+ "package"64+ ],65+ "exclude": [66+ "package/**/*_test.ts",67+ "package/testing/fixture_integration.ts",68+ "package/testdata"69+ ]5570 }5671 }
D docs/decisions/0001-jazz2-alpha53-baseline.md +0 -63
@@ -1,63 +0,0 @@
1-# 0001: Graduate the Jazz 2.0.0-alpha.53 data path with lofi-owned edges2-3-Status: accepted for M1 integration\4-Date: 2026-07-15\5-Issue: #7\6-Evidence:7-[`spikes/jazz2-baseline/evidence/2026-07-15.md`](../../spikes/jazz2-baseline/evidence/2026-07-15.md)8-9-## Decision10-11-Use the relational Jazz 2 API from the exact `jazz-tools@2.0.0-alpha.53` npm pin for the M112-prototype:13-14-- declare the schema with `schema.table` and `schema.defineApp`;15-- create one browser `Db` with the persistent driver and a namespaced `BrowserAuthSecretStore`16- identity;17-- render reactive state from `Db.subscribeAll`;18-- treat a write as locally retained only after `wait({ tier: "local" })`;19-- treat a cloud write as confirmed only after `wait({ tier: "global" })`; and20-- keep raw Jazz setup, worker configuration, and transport details behind lofi's runtime module.21-22-Keep `JAZZ_APP_ID` and `JAZZ_SERVER_URL` as lofi's public configuration names. The Deno/Vite edge23-maps the complete validated pair to Jazz's internal `VITE_JAZZ_*` names. `JAZZ_ADMIN_SECRET` and24-`BACKEND_SECRET` remain server-only and unprefixed.25-26-## Contract deltas27-28-- Revise `DX-OBS-01`: configuration proves only that sync is configured. This pin has no public live29- connection-state or pending-operation-count API. lofi may report per-write local/global30- confirmation and explicitly unavailable detail, but not fabricate “connected”.31-- Retain the persistent driver as the default for `DX-DUR-01`; unsupported browser capabilities fail32- boot rather than silently selecting memory.33-- Validate the desktop/browser portion of `DX-LOCAL-01` and the vendor portion of `DX-SYNC-01`.34- Integrated Astro/Preact ownership remains for #5/#6.35-- Confirm the lofi-owned environment names for `DX-ENV-01`; the final Astro build still has to pass36- server-secret scanning.37-38-## Why39-40-The exact package passed local writes, subscription updates, reload retention, offline writes,41-multi-tab propagation, managed-cloud global durability, and a clean second-client download. Its42-relational API matches lofi's intended author model without inventing a second schema language.43-44-The package is alpha and its framework integration assumes a conventional npm layout. Keeping the45-edge lofi-owned lets the product absorb the required Deno/Vite filesystem allowance, first-run env46-pre-seeding, singleton lifecycle, and secret-safe command output without leaking those mechanics47-into product UI.48-49-## Rejected alternatives50-51-- **Use Jazz Classic 0.20 APIs from `init.md`:** those CoValue APIs do not describe this package.52-- **Wrap Jazz in a provider-neutral data abstraction now:** M1 has no second provider and would53- merely create an untested shadow API.54-- **Report connection state from configuration:** a configured URL is not transport evidence.55-- **Fall back to memory automatically:** this violates retained-write and failure-honesty promises.56-- **Track the generated Vite-prefixed `.env`:** it makes vendor implementation names part of the57- public contract and does not solve secret-safe cloud configuration.58-59-## Sources60-61-- [Exact npm package](https://www.npmjs.com/package/jazz-tools/v/2.0.0-alpha.53)62-- [Jazz source snapshot inspected for context](https://github.com/garden-co/jazz/tree/3384730e1c4509524b38c52fc9102fc6753411aa)63-- [Official TypeScript local-first starter at that snapshot](https://github.com/garden-co/jazz/tree/3384730e1c4509524b38c52fc9102fc6753411aa/starters/ts-localfirst)
D docs/decisions/0002-graduate-thin-preact-adapter.md +0 -33
@@ -1,33 +0,0 @@
1-# ADR 0002: Graduate the thin Preact adapter2-3-Status: accepted\4-Date: 2026-07-15\5-Issues: #5, #66-7-## Decision8-9-Use Preact directly over a small lofi-owned external store backed by Jazz's vanilla `Db` API. Keep10-one browser-global database promise, share one vendor query subscription across equivalent island11-consumers, and replace adapter instances during HMR without shutting down the database.12-13-Product components may use Preact, lofi hooks, and application types. They may not import Jazz,14-construct a client/provider, choose a transport, or branch on storage implementation.15-16-## Why17-18-Jazz 2.0.0-alpha.53's React bindings require React 19's `use`. Preact 10.29.7 compat does not export19-that API, so the alias-only control fails its production build. A custom semantic polyfill would be20-a larger and riskier compatibility layer than the adapter it was meant to avoid.21-22-The thin path passed two-root reactivity, retained local writes, explicit and concurrent client23-recreation, teardown, error visibility, deferred-initialization disposal, and five HMR cycles. Its24-reachable JavaScript is 6,983 gzip bytes larger than the single-view vanilla API control; that is an25-indicative floor rather than an equivalent-UI bundle claim.26-27-## Consequences28-29-- Jazz alpha churn is isolated to `apps/reference/src/_lofi` and schema/config files.30-- Component authors get context-free hooks that work across independent Astro islands.31-- The adapter owns query snapshot identity, cleanup, mutation error mapping, and HMR lifecycle.32-- Deferred asynchronous subscription failures remain limited by Jazz's public API and must not be33- represented as observable UI errors until the vendor exposes a channel.
D docs/decisions/0003-use-static-astro-through-deno.md +0 -29
D docs/decisions/0004-reject-alpha53-passkey-backup.md +0 -37
@@ -1,37 +0,0 @@
1-# ADR 0004: Reject Jazz alpha.53 passkey backup2-3-Status: accepted\4-Date: 2026-07-15\5-Issue: #86-7-## Decision8-9-Do not ship or invoke `BrowserPasskeyBackup` from `jazz-tools@2.0.0-alpha.53`. Present the identity10-as a device-local auth key. State explicitly that passkey backup is blocked by security review and11-that clearing site data can make the identity unrecoverable.12-13-Do not expose 24-word phrase export/import in M1. Retain its exact semantics for a later deliberate14-UX: it is a reversible encoding of the full-control auth seed and recovers identity authority, not15-unsynced local data.16-17-## Why18-19-The exact package stores the raw 32-byte Jazz auth secret in the WebAuthn user handle and reads it20-back from `AuthenticatorAssertionResponse.userHandle`. The WebAuthn specification defines that field21-as an account identifier and warns that authenticators may reveal it without prior user22-verification. Ceremony flags and credProtect do not establish a general confidentiality contract for23-the field.24-25-The API also cannot prove that a created credential is synced or manage/revoke its credentials.26-Physical-device success would therefore not establish the security or recovery promise lofi needs.27-28-## Replacement acceptance29-30-A replacement must:31-32-- keep the auth seed out of WebAuthn identifiers and non-confidential metadata;33-- wrap/encrypt the seed using an authenticator-derived or otherwise reviewed secret;34-- bind a stable RP ID and verify the complete ceremony/server record as applicable;35-- distinguish local credential creation from ecosystem backup state;36-- support duplicate prevention, inventory, replacement, and recovery failure UX;37-- retain real iOS and Android browser/installed-app evidence before graduation.
D docs/decisions/0005-publish-one-nzip-lofi-package.md +0 -38
@@ -1,38 +0,0 @@
1-# ADR 0005: Publish one `@nzip/lofi` package2-3-Status: accepted\4-Date: 2026-07-155-6-Owner confirmation: FelineStateMachine explicitly confirmed `@nzip/lofi` as the canonical package7-after #21 and superseded the earlier `@lofi-cat/*` direction. The `@nzip` JSR scope is the owned8-nzip publishing surface and already lists the reserved `@nzip/lofi` package alongside the published9-nzip packages. Publication credentials remain a release-time secret, not repository configuration.10-11-## Decision12-13-Use `@nzip/lofi` as lofi's only JSR package. Public framework boundaries remain explicit subpath14-exports such as `@nzip/lofi/core`, `@nzip/lofi/sync`, `@nzip/lofi/auth`, `@nzip/lofi/ui`, and15-`@nzip/lofi/pwa`. Public tooling graduates under the same package, including the M2 creation command16-at `jsr:@nzip/lofi/create` and testing helpers at `@nzip/lofi/testing`.17-18-Do not publish lockstep `@lofi-cat/*` packages. Internal module boundaries and dependency direction19-remain enforceable even though those modules share one package version.20-21-## Why22-23-The prototype's modules evolve together around a fast-moving pinned Jazz alpha. One JSR package24-provides one version, one publish operation, and direct subpath imports without creating independent25-release promises before the seams have been proven by a second application.26-27-## Consequences28-29-- The M2 public create command is `deno run -A jsr:@nzip/lofi/create <name>`.30-- Consumers import framework APIs through named subpaths, not the package root.31-- Package extraction validates export boundaries, but does not create independently versioned32- artifacts.33-- A future split requires evidence that a module needs an independent compatibility or release34- lifecycle.35-36-## Registry evidence37-38-- [JSR `@nzip` scope](https://jsr.io/@nzip), including the reserved `@nzip/lofi` package
D docs/decisions/0006-bound-layer3-inspection-and-testing.md +0 -80
@@ -1,80 +0,0 @@
1-# 0006: Bound Layer 3 inspection and testing to truthful observable seams2-3-Status: accepted for M2 implementation\4-Date: 2026-07-15\5-Issues: #10, #126-7-## Decision8-9-Layer 3 graduates two developer surfaces:10-11-- a visible development-only inspector backed by a provisional internal snapshot/action adapter;12-- readiness-first Playwright helpers exported from the single package at `@nzip/lofi/testing`.13-14-The inspector is generated runtime machinery, not a public framework facade. `./testing` is the only15-new public package export in this layer. Broader `core`, `ui`, `sync`, `auth`, and `pwa` extraction16-still requires the M4 evidence described by ADR 0005.17-18-The inspector may report only signals lofi can observe:19-20-- device-local identity and the blocked alpha passkey-backup state;21-- requested/open/failed persistent storage plus browser persistence permission;22-- local-only or managed-configured mode;23-- lofi-wrapped per-write local/global durability and mutation failures; and24-- active client, consumer, vendor-subscription, and mutation-listener counts.25-26-The Jazz alpha pin exposes no supported live connection state, vendor queue depth, or multi-tab27-leader/follower role. Those fields remain visibly unavailable. Configuration is never presented as28-connectivity, and checklist writes are not mislabeled as the vendor's complete pending queue.29-30-Inspector transport pause/resume calls Jazz `Db.disconnect()`/`reconnect()` only when managed sync31-is configured and labels the action as a cloud-transport test seam. Real browser offline control is32-owned by `@nzip/lofi/testing` through Playwright `BrowserContext.setOffline()`. Client restart uses33-a full document reload: Jazz alpha.53 does not reliably reopen the same browser-broker namespace34-after an in-document `Db.shutdown()`/`createDb()` cycle, while a document lifecycle restart retains35-the locally durable replica. Replica clear uses `Db.deleteClientStorage()` behind a destructive36-confirmation, then reloads the document; it clears the local OPFS namespace while preserving the37-localStorage identity and warns that unsynced data may be lost.38-39-## Two-client identity rule40-41-The current permissions are creator-only. Two distinct user identities therefore cannot both read42-and edit one row, so claiming distinct-identity convergence would be false. The convergence fixture43-uses two isolated browser contexts and separate OPFS replicas with the same restored identity. The44-first context's Playwright storage state is passed directly to the second context in memory. It is45-never written to reports, traces, snapshots, logs, or screenshots because it contains the bearer46-identity secret.47-48-A truly distinct-user fixture belongs with sharing/invitation and permission-model work, not this49-testing layer.50-51-## Verification boundary52-53-Local acceptance proves readiness predicates, offline restoration in `finally`, restart/reload,54-artifact redaction, inspector actions, and production exclusion. Closing the convergence contract55-also requires a cloud-configured generated-project journey:56-57-1. seed a row and wait for global durability;58-2. boot the second isolated replica with the in-memory restored identity;59-3. take both browser contexts offline;60-4. make orthogonal edits, then reload/recreate while work remains local;61-5. restore network control in `finally` and wait for both visible snapshots to converge; and62-6. remove fixture rows and wait for global durability.63-64-Only the public `JAZZ_APP_ID`/`JAZZ_SERVER_URL` pair reaches the child application. Server secrets65-remain blank, and no configured value is retained in evidence.66-67-Production builds must contain no lofi inspector marker, global bridge, route, or chunk. Jazz's raw68-vendor inspector remains disabled.69-70-## Deferred physical-device evidence71-72-Playwright does not graduate installed-PWA lifecycle, storage eviction, airplane-mode cold launch,73-real passkey custody, or mobile background/foreground recovery. Those remain explicit M3 physical-74-device gates.75-76-## Why77-78-This boundary gives developers useful controls and deterministic tests without inventing vendor79-precision, leaking identity material, weakening creator-only permissions, or prematurely turning the80-M1 runtime into a general framework API.
D docs/decisions/README.md +0 -20
D docs/m2-abstraction-leaks.md +0 -24
@@ -1,24 +0,0 @@
1-# M2 abstraction-leak ledger2-3-Status: active during M2\4-Last reviewed: 2026-07-155-6-This ledger keeps the Layer 1 reference application honest. A listed leak is not a supported lofi7-API; it is a concrete input to the layer that owns removing or productizing it.8-9-| Leak retained in Layer 1 | Why it remains | Owning issue | Graduation evidence |10-| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- |11-| Repository-root wrappers still own the checkout journey; generated commands now live in `@nzip/lofi`. | The generated path is implemented without repository-relative paths, but this leak remains listed until exact-head generated golden evidence is retained. | #13, #14 | A generated directory runs its own documented tasks without repository-relative paths. |12-| `schema.ts` and `permissions.ts` import the pinned Jazz schema DSL directly. | M1 rejected inventing a second schema language without a proven ergonomic gain. | Later API extraction after M2 | A second real application demonstrates a smaller stable facade, or the direct DSL is accepted explicitly. |13-| `app.ts` uses a provisional plain configuration object and the Jazz schema value. | Layer 1 needs configuration-as-data but does not yet have two consumers that justify a public factory or exported type. | #13 | The generator emits the approved configuration without raw client, transport, or environment plumbing. |14-| Live socket state, vendor queue depth, and multi-tab role remain unavailable. | Jazz alpha.53 exposes mutation durability but no supported signal for these details; ADR 0006 accepts explicit unavailability instead of fabricated precision. | Jazz baseline review | A later Jazz pin exposes supported signals, or the unavailable boundary remains an intentional product contract. |15-16-## Graduated in Layer 317-18-| Former leak | Graduated surface | Evidence |19-| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |20-| Runtime cardinality and lifecycle evidence used a development-only probe. | The generated dev-only inspector owns redacted diagnostics and safe actions; production builds contain no inspector marker, bridge, route, or chunk. | [ADR 0006](decisions/0006-bound-layer3-inspection-and-testing.md), inspector unit coverage, and generated golden restart/clear/production-exclusion assertions in `tools/golden_path.ts`. |21-| Browser orchestration existed only in the repository checkout journey. | `@nzip/lofi/testing` exports readiness, offline restoration, two-client identity isolation, convergence coordination, and sanitized failure artifacts. | [ADR 0006](decisions/0006-bound-layer3-inspection-and-testing.md), generated subpath-resolution coverage, real Chromium integration, and the cloud two-replica convergence gate. |22-23-Deleting an entry requires retained evidence in the owning issue or a decision record accepting the24-behavior as an intentional public boundary.
R init.md → docs/seed.md +0 -0

No content changes.

R spikes/astro-deno/evidence/2026-07-15.md → docs/spikes/astro-deno/evidence/2026-07-15.md +0 -0

No content changes.

R spikes/identity/evidence/2026-07-15.md → docs/spikes/identity/evidence/2026-07-15.md +0 -0

No content changes.

R spikes/jazz2-baseline/README.md → docs/spikes/jazz2-baseline/README.md +0 -0

No content changes.

R spikes/jazz2-baseline/evidence/2026-07-15.md → docs/spikes/jazz2-baseline/evidence/2026-07-15.md +0 -0

No content changes.

R spikes/jazz2-baseline/index.html → docs/spikes/jazz2-baseline/index.html +0 -0

No content changes.

R spikes/jazz2-baseline/permissions.ts → docs/spikes/jazz2-baseline/permissions.ts +0 -0

No content changes.

R spikes/jazz2-baseline/schema.ts → docs/spikes/jazz2-baseline/schema.ts +0 -0

No content changes.

R spikes/jazz2-baseline/src/import-meta.d.ts → docs/spikes/jazz2-baseline/src/import-meta.d.ts +0 -0

No content changes.

R spikes/jazz2-baseline/src/main.ts → docs/spikes/jazz2-baseline/src/main.ts +0 -0

No content changes.

R spikes/jazz2-baseline/src/style.css → docs/spikes/jazz2-baseline/src/style.css +0 -0

No content changes.

R spikes/jazz2-baseline/vite.config.ts → docs/spikes/jazz2-baseline/vite.config.ts +0 -0

No content changes.

R spikes/opfs-device/device-checklist.md → docs/spikes/opfs-device/device-checklist.md +0 -0

No content changes.

R spikes/opfs-device/evidence/2026-07-15.md → docs/spikes/opfs-device/evidence/2026-07-15.md +0 -0

No content changes.

R spikes/preact-integration/compat-control/index.html → docs/spikes/preact-integration/compat-control/index.html +0 -0

No content changes.

R spikes/preact-integration/compat-control/src.tsx → docs/spikes/preact-integration/compat-control/src.tsx +0 -0

No content changes.

R spikes/preact-integration/compat-control/vite.config.ts → docs/spikes/preact-integration/compat-control/vite.config.ts +0 -0

No content changes.

R spikes/preact-integration/evidence/2026-07-15.md → docs/spikes/preact-integration/evidence/2026-07-15.md +0 -0

No content changes.

D jsr.json +0 -33
D output/playwright/jazz2-alpha53-cloud-second-client.png +0 -0

Binary file.

D output/playwright/jazz2-alpha53-local-offline-multitab.png +0 -0

Binary file.

D package/commands/check.ts +0 -47
@@ -1,47 +0,0 @@
1-#!/usr/bin/env -S deno run -A2-3-import {4- childEnvironment,5- loadEnvironment,6- serverEnvironmentNames,7-} from "../tooling/environment.ts";8-import { doctorReport, printDoctorReport } from "../tooling/diagnostics.ts";9-import { scanSecrets, walkFiles } from "../tooling/project.ts";10-import { runDeno } from "../tooling/process.ts";11-import { exitOnFailure } from "./shared.ts";12-13-const report = await doctorReport();14-if (report.blocked || !report.validation.ok) {15- printDoctorReport(report);16- console.error("error: check stopped at lofi preflight; rerun `deno task check` after the action");17- Deno.exit(1);18-}19-const environment = childEnvironment(report.validation);20-environment.LOFI_SKIP_JAZZ_MANAGED = "1";21-const typedFiles = await walkFiles(Deno.cwd(), {22- extensions: new Set([".ts", ".tsx"]),23-});24-25-for (26- const [name, args] of [27- ["format", ["fmt", "--check"]],28- ["lint", ["lint"]],29- ["type", ["check", ...typedFiles]],30- ["Astro", ["run", "-A", "npm:astro@7.0.9", "check"]],31- ] as const32-) {33- exitOnFailure(await runDeno(args, environment), `${name} check`);34-}35-36-const loadedEnvironment = await loadEnvironment();37-const secrets = await scanSecrets(38- Object.fromEntries(serverEnvironmentNames.map((name) => [name, loadedEnvironment[name] ?? ""])),39-);40-if (secrets.leaks.length > 0) {41- for (const leak of secrets.leaks) {42- console.error(`error: ${leak.name} value found in ${leak.path}`);43- }44- console.error("error: secret scan failed; remove the value and rerun `deno task check`");45- Deno.exit(1);46-}47-console.log(`lofi check passed (4 checks, ${secrets.scanned} files secret-scanned)`);
M package/create_core.ts +43 -57
@@ -53,62 +53,51 @@ The default project runs local-only with durable browser storage. To enable mana
5353 \`.env.example\` to \`.env\` and set both public Jazz values. Run \`deno task doctor\` before boot when5454 you want configuration diagnostics without starting the application.5555 56-Public tasks: \`dev\`, \`doctor\`, \`check\`, \`test\`, \`build\`, and \`preview\`.56+Public tasks: \`dev\`, \`doctor\`, \`test\`, \`build\`, and \`preview\`. Schema and sync tasks:57+\`schema:validate\`, \`schema:deploy\`, \`migrations:create\`, and \`migrations:push\`.58+59+## Hosting60+61+\`deno task build\` emits a static PWA in \`dist/\`. The deploy tasks host it on Deno Deploy as a62+static site — they push the built \`dist/\` as the deploy root, which serves it as plain assets:63+64+- \`deno task deploy:create --org <org> --app <app>\` — one-time: create the app from \`dist/\`.65+- \`deno task deploy\` — thereafter: build and push \`dist/\`.66+67+Point them at any other static host by editing those two tasks.5768 `;5869 }5970 60-function generatedDenoConfig(packagePrefix: string): string {61- const packageCommand = (subpath: string, localPath: string) =>62- packagePrefix.startsWith("file:")63- ? `${packagePrefix}${localPath}`64- : `${packagePrefix}${subpath}`;65- const config = {66- imports: {67- "@astrojs/check": "npm:@astrojs/check@0.9.9",68- "@astrojs/preact": "npm:@astrojs/preact@6.0.1",69- "@nzip/lofi/": packagePrefix,70- "@nzip/lofi/build": packageCommand("build", "commands/build.ts"),71- "@nzip/lofi/check": packageCommand("check", "commands/check.ts"),72- "@nzip/lofi/dev": packageCommand("dev", "commands/dev.ts"),73- "@nzip/lofi/doctor": packageCommand("doctor", "commands/doctor.ts"),74- "@nzip/lofi/preview": packageCommand("preview", "commands/preview.ts"),75- "@nzip/lofi/testing": packageCommand("testing", "testing/mod.ts"),76- "@nzip/lofi/test": packageCommand("test", "commands/run_tests.ts"),77- "astro": "npm:astro@7.0.9",78- "astro/config": "npm:astro@7.0.9/config",79- "jazz-tools": "npm:jazz-tools@2.0.0-alpha.53",80- "jazz-tools/dev/vite": "npm:jazz-tools@2.0.0-alpha.53/dev/vite",81- "preact": "npm:preact@10.29.7",82- "preact/hooks": "npm:preact@10.29.7/hooks",83- "preact/jsx-dev-runtime": "npm:preact@10.29.7/jsx-dev-runtime",84- "preact/jsx-runtime": "npm:preact@10.29.7/jsx-runtime",85- "typescript": "npm:typescript@6.0.3",86- "vite": "npm:vite@8.0.1",87- },88- nodeModulesDir: "auto",89- compilerOptions: {90- lib: ["deno.ns", "dom", "dom.iterable", "esnext"],91- jsx: "react-jsx",92- jsxImportSource: "preact",93- },94- tasks: {95- dev: "deno run -A @nzip/lofi/dev",96- doctor: "deno run -A @nzip/lofi/doctor",97- check: "deno run -A @nzip/lofi/check",98- test: "deno run -A @nzip/lofi/test",99- build: "deno run -A @nzip/lofi/build",100- preview: "deno run -A @nzip/lofi/preview",101- },102- fmt: {103- lineWidth: 100,104- semiColons: true,105- singleQuote: false,106- },107- lint: {108- rules: { tags: ["recommended"] },109- },110- };111- return `${JSON.stringify(config, null, 2)}\n`;71+// The `@nzip/lofi/*` import keys the template carries as local repo paths; a72+// generated project resolves the same keys through the published package (or a73+// file: override in clean-room tests). Everything else in the template deno.json74+// — npm imports, tasks (including schema/migration/deploy), fmt, lint — is copied75+// verbatim, so the template is the single source of truth for project config.76+const lofiImportTargets: Record<string, { subpath: string; localPath: string }> = {77+ "@nzip/lofi/build": { subpath: "build", localPath: "commands/build.ts" },78+ "@nzip/lofi/dev": { subpath: "dev", localPath: "commands/dev.ts" },79+ "@nzip/lofi/doctor": { subpath: "doctor", localPath: "commands/doctor.ts" },80+ "@nzip/lofi/preview": { subpath: "preview", localPath: "commands/preview.ts" },81+ "@nzip/lofi/test": { subpath: "test", localPath: "commands/run_tests.ts" },82+ "@nzip/lofi/testing": { subpath: "testing", localPath: "testing/mod.ts" },83+};84+85+async function rewritePortableDenoConfig(root: string, packagePrefix: string): Promise<void> {86+ const path = join(root, "deno.json");87+ const config = JSON.parse(await Deno.readTextFile(path));88+ const imports = config.imports as Record<string, string> | undefined;89+ if (!imports || typeof imports["@nzip/lofi/"] !== "string") {90+ throw new Error("starter deno.json is missing the @nzip/lofi/ import marker");91+ }92+ const isFileOverride = packagePrefix.startsWith("file:");93+ imports["@nzip/lofi/"] = packagePrefix;94+ for (const [key, { subpath, localPath }] of Object.entries(lofiImportTargets)) {95+ if (typeof imports[key] !== "string") {96+ throw new Error(`starter deno.json is missing the ${key} import`);97+ }98+ imports[key] = isFileOverride ? `${packagePrefix}${localPath}` : `${packagePrefix}${subpath}`;99+ }100+ await Deno.writeTextFile(path, `${JSON.stringify(config, null, 2)}\n`);112101 }113102 114103 function validateName(name: string): string[] {
@@ -210,13 +199,10 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
210199 try {211200 await writeTemplate(staging);212201 await rewritePortableAstroConfig(staging);202+ await rewritePortableDenoConfig(staging, options.packagePrefix ?? LOFI_PACKAGE_PREFIX);213203 await Deno.writeTextFile(join(staging, ".gitignore"), generatedGitignore);214204 await Deno.writeTextFile(join(staging, ".env.example"), generatedEnvironment);215205 await Deno.writeTextFile(join(staging, "README.md"), generatedReadme(basename(destination)));216- await Deno.writeTextFile(217- join(staging, "deno.json"),218- generatedDenoConfig(options.packagePrefix ?? LOFI_PACKAGE_PREFIX),219- );220206 221207 await Deno.remove(destination).catch((error) => {222208 if (!(error instanceof Deno.errors.NotFound)) throw error;
M package/create_core_test.ts +3 -3
M package/starter_template.ts +19 -27
@@ -1,15 +1,17 @@
1+import denoConfig from "../apps/reference/deno.json" with { type: "text" };12 import astroConfig from "../apps/reference/astro.config.ts" with { type: "text" };23 import favicon from "../apps/reference/public/favicon.svg" with { type: "text" };34 import manifest from "../apps/reference/public/manifest.webmanifest" with { type: "text" };45 import serviceWorker from "../apps/reference/public/sw.js" with { type: "text" };56 import deviceStatus from "../apps/reference/src/_lofi/DeviceStatus.tsx" with { type: "text" };6-import referenceShell from "../apps/reference/src/_lofi/ReferenceShell.astro" with { type: "text" };7+import shell from "../apps/reference/src/_lofi/Shell.astro" with { type: "text" };78 import boot from "../apps/reference/src/_lofi/boot.ts" with { type: "text" };8-import checklistStore from "../apps/reference/src/_lofi/checklist-store.ts" with { type: "text" };9-import checklistStoreTest from "../apps/reference/src/_lofi/checklist-store_test.ts" with {9+import config from "../apps/reference/src/_lofi/config.ts" with { type: "text" };10+import diagnostics from "../apps/reference/src/_lofi/diagnostics.ts" with { type: "text" };11+import tableStore from "../apps/reference/src/_lofi/table-store.ts" with { type: "text" };12+import tableStoreTest from "../apps/reference/src/_lofi/table-store_test.ts" with {1013 type: "text",1114 };12-import config from "../apps/reference/src/_lofi/config.ts" with { type: "text" };1315 import deviceCapabilities from "../apps/reference/src/_lofi/device-capabilities.ts" with {1416 type: "text",1517 };
@@ -33,49 +35,40 @@ import uiMutation from "../apps/reference/src/_lofi/ui-mutation.ts" with { type:
3335 import uiMutationTest from "../apps/reference/src/_lofi/ui-mutation_test.ts" with {3436 type: "text",3537 };36-import useChecklist from "../apps/reference/src/_lofi/use-checklist.ts" with { type: "text" };3738 import useDeviceCapabilities from "../apps/reference/src/_lofi/use-device-capabilities.ts" with {3839 type: "text",3940 };41+import useTasks from "../apps/reference/src/islands/use-tasks.ts" with { type: "text" };4042 import app from "../apps/reference/src/app.ts" with { type: "text" };4143 import environmentTypes from "../apps/reference/src/env.d.ts" with { type: "text" };42-import checklistIsland from "../apps/reference/src/islands/ChecklistIsland.tsx" with {43- type: "text",44-};45-import migration from "../apps/reference/src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts" with {46- type: "text",47-};48-import oldSchemaSnapshot from "../apps/reference/src/migrations/snapshots/20260715T194819-6c62fec42c35.json" with {49- type: "text",50-};51-import currentSchemaSnapshot from "../apps/reference/src/migrations/snapshots/20260715T194947-ff85ac1d97ee.json" with {52- type: "text",53-};44+import taskList from "../apps/reference/src/islands/TaskList.tsx" with { type: "text" };5445 import indexPage from "../apps/reference/src/pages/index.astro" with { type: "text" };5546 import permissions from "../apps/reference/src/permissions.ts" with { type: "text" };5647 import schema from "../apps/reference/src/schema.ts" with { type: "text" };5748 import globalStyles from "../apps/reference/src/styles/global.css" with { type: "text" };58-import uiContract from "../apps/reference/src/ui-contract.ts" with { type: "text" };5949 import authorBoundaryTest from "../apps/reference/tests/author-boundary_test.ts" with {6050 type: "text",6151 };6252 import testingContractTest from "../apps/reference/tests/testing-contract_test.ts" with {6353 type: "text",6454 };55+import convergenceExample from "../apps/reference/tests/convergence_e2e_test.ts" with {56+ type: "text",57+};6558 import tsconfig from "../apps/reference/tsconfig.json" with { type: "text" };6659 6760 /** Every source-controlled file copied from the validated reference app into a new project. */6861 export const STARTER_TEMPLATE: Readonly<Record<string, string>> = {62+ "deno.json": denoConfig,6963 "astro.config.ts": astroConfig,7064 "public/favicon.svg": favicon,7165 "public/manifest.webmanifest": manifest,7266 "public/sw.js": serviceWorker,7367 "src/_lofi/DeviceStatus.tsx": deviceStatus,74- "src/_lofi/ReferenceShell.astro": referenceShell,68+ "src/_lofi/Shell.astro": shell,7569 "src/_lofi/boot.ts": boot,76- "src/_lofi/checklist-store.ts": checklistStore,77- "src/_lofi/checklist-store_test.ts": checklistStoreTest,7870 "src/_lofi/config.ts": config,71+ "src/_lofi/diagnostics.ts": diagnostics,7972 "src/_lofi/device-capabilities.ts": deviceCapabilities,8073 "src/_lofi/device-capabilities_test.ts": deviceCapabilitiesTest,8174 "src/_lofi/inspector.ts": inspector,
@@ -86,23 +79,22 @@ export const STARTER_TEMPLATE: Readonly<Record<string, string>> = {
8679 "src/_lofi/resource-lifecycle.ts": resourceLifecycle,8780 "src/_lofi/resource-lifecycle_test.ts": resourceLifecycleTest,8881 "src/_lofi/runtime.ts": runtime,82+ "src/_lofi/table-store.ts": tableStore,83+ "src/_lofi/table-store_test.ts": tableStoreTest,8984 "src/_lofi/test-assert.ts": testAssert,9085 "src/_lofi/ui-mutation.ts": uiMutation,9186 "src/_lofi/ui-mutation_test.ts": uiMutationTest,92- "src/_lofi/use-checklist.ts": useChecklist,9387 "src/_lofi/use-device-capabilities.ts": useDeviceCapabilities,9488 "src/app.ts": app,9589 "src/env.d.ts": environmentTypes,96- "src/islands/ChecklistIsland.tsx": checklistIsland,97- "src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts": migration,98- "src/migrations/snapshots/20260715T194819-6c62fec42c35.json": oldSchemaSnapshot,99- "src/migrations/snapshots/20260715T194947-ff85ac1d97ee.json": currentSchemaSnapshot,90+ "src/islands/TaskList.tsx": taskList,91+ "src/islands/use-tasks.ts": useTasks,10092 "src/pages/index.astro": indexPage,10193 "src/permissions.ts": permissions,10294 "src/schema.ts": schema,10395 "src/styles/global.css": globalStyles,104- "src/ui-contract.ts": uiContract,10596 "tests/author-boundary_test.ts": authorBoundaryTest,97+ "tests/convergence_e2e_test.ts": convergenceExample,10698 "tests/testing-contract_test.ts": testingContractTest,10799 "tsconfig.json": tsconfig,108100 };
M package/testdata/starter.snapshot.json +17 -19
@@ -2,44 +2,42 @@
22 ".env.example": "c22aed73c7089168ac777fd4f68ad504f9b826ea7185b705514a4ac5505918b1",33 ".gitignore": "9efb15c6a9bfc20f296ed712e74273b6015a0dd9a40f7e861b8711dcf61825f1",44 "astro.config.ts": "8a19cae348af7fcbd9db119d2423dd2e464f0e5ace6e5723d06cd3a1cc9a0d4b",5- "deno.json": "1285b00d154c19fe9104d7b13eff503cd95d628574d409177cdfbf7d652a98ac",5+ "deno.json": "679b5f2a8da16e060c2423ae159af5fba9a60d4435b5a3696425978010cbd2b7",66 "public/favicon.svg": "23efdb888dae688715faafe3ef94f7b5ad1976afcc715c0a742218b54732c6ad",7- "public/manifest.webmanifest": "d23457fe8df68a16181fde1d4ecca4b69d3b050b5fa3bf8f4051cb05bde1d3d6",7+ "public/manifest.webmanifest": "7d492285fd982e6e68fa04f12d78cd4f0bef4343f0408e314f1582029f3ea407",88 "public/sw.js": "d816161fd5a35f2c477ca72eaa5ba58eb8d94795a4399d29a19838e886dafa31",9- "README.md": "26fb40f86d03a403519bbce0f263b2305971b98c310a19cec37ab0079130fb0c",9+ "README.md": "6a116909a8e9a92a4d48932d2d9672882171cfe1eb1d9d7caa8d36a6e4af8348",1010 "src/_lofi/boot.ts": "dd66bd1e5ddb88599a0cbadb2c2cf932993734843c7e5cf41d28b389560a32c7",11- "src/_lofi/checklist-store_test.ts": "0c0ebc75afa8702ad13fec9eaace14763a6d3ef52c3afa283ebfae33f90929d9",12- "src/_lofi/checklist-store.ts": "3a221882b72be6652b3ccfd5d1b058703ad84ae955c12515a301cec0f8708cd7",1311 "src/_lofi/config.ts": "3ae7e31b3915e12eb595eeea158c0dbd026f4f0f8bf7b0f4809117bec9752f1a",1412 "src/_lofi/device-capabilities_test.ts": "0eece375a0645e915294c7647cba4666e992a8a471cb636cf889bcd323a65ee5",1513 "src/_lofi/device-capabilities.ts": "91b03f9bed813d3770061416d40066ed6f21829877293e5395eff8f0f98fc11e",1614 "src/_lofi/DeviceStatus.tsx": "1ba2e2c2bee7ac15bc2830e879904deddf95bba1b55359f0376cf7cb1c9aafeb",15+ "src/_lofi/diagnostics.ts": "abb2a5f8e4d6b8ab1a86d475db6c374aecf4580b534ba9d7d850e1dbb29bb7f8",1716 "src/_lofi/inspector_test.ts": "05de6636a3ff5ff7f918f989ac919cde653fafd81cbd58c8f0c371badb554a07",1817 "src/_lofi/inspector.ts": "19fbe4f2d300ca4886ad90f16f6539cc0ad04ba1f38ac28bd9dec269c3f872bd",1918 "src/_lofi/probe.ts": "9bb284f4543e631acbfb22bb661b5cfc0798d561b0e95ee09796b36ebb5865b0",2019 "src/_lofi/pwa_test.ts": "092d9ff442d82086a03cf45c6ed0256ab0f1ce8db42fe7e636d4b93d6ebae63e",2120 "src/_lofi/pwa.ts": "185a0668528b49eae2dd0aa905a5a2e491b3787da335d491ffecaf8bfadec430",22- "src/_lofi/ReferenceShell.astro": "a2817146d1fe62cfdc399669709996b468823a8828257abf63b445c4c8eac912",2321 "src/_lofi/resource-lifecycle_test.ts": "9a43053351b8b90f3b67a2953c3ff159e0337ab8009f1d061e9e2bf7382abf43",2422 "src/_lofi/resource-lifecycle.ts": "4e017f4391f18854486044709041f163308fa3fc84e08d5ec7f45c39e3ae3cb5",25- "src/_lofi/runtime.ts": "4fa51fae73fa69aec95e6f9a3d750844bb841a9ae8b787e03a16b8d3a3ba3a22",23+ "src/_lofi/runtime.ts": "db204517acc708f5145f48ed5cbd1ab95c01e35ddedb09dc0ba9617ea8bc1f79",24+ "src/_lofi/Shell.astro": "a2817146d1fe62cfdc399669709996b468823a8828257abf63b445c4c8eac912",25+ "src/_lofi/table-store_test.ts": "1b8cfd06192b9c0daacc8a8c7811b691338f4ef459b209b3830fb87a0a039955",26+ "src/_lofi/table-store.ts": "7ad445cc34c11e0cab3afcf1cde097345f1a53f2583da6c7fd00c7cb3e082df8",2627 "src/_lofi/test-assert.ts": "38549889964a4e92a0d63ee514c746cae5a43e6160cea4f2075a9e61543d3744",2728 "src/_lofi/ui-mutation_test.ts": "16153da95e080570af254eb0c56433f2db8abacec542984f59f6afd4ebf1c501",2829 "src/_lofi/ui-mutation.ts": "3273053a796160556045d06d672f4c79d9597e1f822928f1ee71a7d31865dc32",29- "src/_lofi/use-checklist.ts": "a6d2818d390d228ad2a3db554b7cb043b60f7e9a2e48636ba19247c666343eaf",3030 "src/_lofi/use-device-capabilities.ts": "f7c7b2321b400d8076a5347e0f1ff2924623535979d48a2d94a69f825b93841e",31- "src/app.ts": "3fd3646054f11ef7a1c080445d089eba45d58df7934aeaa58edab7c965c65523",32- "src/env.d.ts": "b44daed05ec5cdfacfd8d8acf7866974b5f6b8db923ab53bd244419093c719da",33- "src/islands/ChecklistIsland.tsx": "77c8c085327b7832d0d9daa0f39a61d3ecf1dc6f7e50c8146499dd6d81aecbe3",34- "src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts": "387201d32018cf9bbc0da7041110638baf27bb9eb55a5e03f59b124bcfc336d5",35- "src/migrations/snapshots/20260715T194819-6c62fec42c35.json": "799e32dee2ca64b7ea69ae48869f5a6dc29adfdb97dd79767a4c8697495aa582",36- "src/migrations/snapshots/20260715T194947-ff85ac1d97ee.json": "39bb03925d68138aa5effc6fc9799de90ad4f3b6b65df84b638afc7b2d67c16b",37- "src/pages/index.astro": "1930f00137df528f15836eb68230b06b248f8abec53f1a051a904557a1287346",38- "src/permissions.ts": "b4580cc5f32935ac568a9aff6109c4aa7e4b3ee8cea8b28c3f306db68a55dcc2",31+ "src/app.ts": "c03faa5219c79940e86f19beaaa94e6b917ec30311a51566b8f16d15886219cb",32+ "src/env.d.ts": "01e5f288625c699524d6b6385a3a43907307fabcdbff802a32b82b254ef0876f",33+ "src/islands/TaskList.tsx": "2d6f4c7ed2475f1ce561e4b2c3a4e21210f4b55f0ec3eee6c4a6047f8622e189",34+ "src/islands/use-tasks.ts": "d2a9afa80590d4f38db7cfe0da37e6b7b17c00c1a73d82e06b800f97b5d609af",35+ "src/pages/index.astro": "3746bbd23cca65f5561c23fd4690368ee3f1cebb38d16f8bc7552ddff1f3f7fa",36+ "src/permissions.ts": "dcb00b7f0576d04ad527b8892b8096573b107c3130ed6d835243251c406a38b7",3937 "src/schema.ts": "f2c555b088ded8eea2653f5d955fc9aae69dfd588e891adf509e99052f1e9949",40- "src/styles/global.css": "7cbe243842f3bca32038d99a4872afe30c346cf7137387ce41861c9333a1f5c0",41- "src/ui-contract.ts": "fc40d20dff6ba870c0de038839e66cb61d4349031e4a7748d963ca182e8bbec0",42- "tests/author-boundary_test.ts": "7ea79031ed4ae7d7966bef2e456e02efe7d93d82c8f0bee219d885d300260ed2",38+ "src/styles/global.css": "0e66a21e9b83cc115f01567ab8a87f949ce7fff8e42a3c3dc2efdd70cfffb706",39+ "tests/author-boundary_test.ts": "529bbd81977294398f4c48a3616d10cdcf0fe5f7c83b705365ad80124ab1a0f1",40+ "tests/convergence_e2e_test.ts": "71ec0ac935c25ff0722905e5b195c730f32a3b886dd4172e11d9e0e80f19cb38",4341 "tests/testing-contract_test.ts": "4257306060d42566b879d92b3a6c395805b20f53717bee55d670c0ef7a117eec",4442 "tsconfig.json": "fe2e5acc66101ed42d893d7e7063d07d298927621b351adcfb1ebde6c3a0a2ac"4543 }
D package/tooling/environment_test.ts +0 -22
M package/tooling/project.ts +5 -1
D tools/check_env.ts +0 -21
D tools/check_migrations.ts +0 -161
@@ -1,161 +0,0 @@
1-import { schema as s } from "jazz-tools";2-import { referenceApp } from "../apps/reference/src/app.ts";3-import migration from "../apps/reference/src/migrations/20260715T194947-notes-to-tasks-6c62fec42c35-ff85ac1d97ee.ts";4-5-const SCHEMA_DIR = "apps/reference/src";6-const MIGRATIONS_DIR = `${SCHEMA_DIR}/migrations`;7-const SNAPSHOTS_DIR = `${MIGRATIONS_DIR}/snapshots`;8-const JAZZ_TOOLS = "npm:jazz-tools@2.0.0-alpha.53";9-10-function fail(message: string): never {11- throw new Error(`migration contract: ${message}`);12-}13-14-async function jazz(args: string[]): Promise<string> {15- const output = await new Deno.Command(Deno.execPath(), {16- args: ["run", "-A", JAZZ_TOOLS, ...args, "--schema-dir", SCHEMA_DIR],17- stdout: "piped",18- stderr: "piped",19- }).output();20- if (!output.success) {21- const error = new TextDecoder().decode(output.stderr).trim();22- fail(`Jazz CLI failed: ${error || `exit ${output.code}`}`);23- }24- return new TextDecoder().decode(output.stdout).trim();25-}26-27-async function jazzSnapshot(hash: string): Promise<unknown> {28- const isolatedEnvironment: Record<string, string> = {};29- for (30- const name of [31- "JAZZ_APP_ID",32- "JAZZ_SERVER_URL",33- "JAZZ_ADMIN_SECRET",34- "BACKEND_SECRET",35- "VITE_JAZZ_APP_ID",36- "VITE_JAZZ_SERVER_URL",37- "PUBLIC_JAZZ_APP_ID",38- "PUBLIC_JAZZ_SERVER_URL",39- "NEXT_PUBLIC_JAZZ_APP_ID",40- "NEXT_PUBLIC_JAZZ_SERVER_URL",41- "EXPO_PUBLIC_JAZZ_APP_ID",42- "EXPO_PUBLIC_JAZZ_SERVER_URL",43- ]44- ) isolatedEnvironment[name] = "";45- const output = await new Deno.Command(Deno.execPath(), {46- args: [47- "run",48- "-A",49- JAZZ_TOOLS,50- "schema",51- "export",52- "--schema-hash",53- hash,54- "--migrations-dir",55- MIGRATIONS_DIR,56- ],57- env: isolatedEnvironment,58- stdout: "piped",59- stderr: "piped",60- }).output();61- if (!output.success) {62- const error = new TextDecoder().decode(output.stderr).trim();63- fail(`snapshot ${hash} does not hash to its filename: ${error || `exit ${output.code}`}`);64- }65- return JSON.parse(new TextDecoder().decode(output.stdout));66-}67-68-function hashField(source: string, field: "fromHash" | "toHash"): string {69- const match = source.match(new RegExp(`${field}:\\s*["']([0-9a-f]{12})["']`));70- if (!match) fail(`reviewed migration is missing a 12-character ${field}`);71- return match[1];72-}73-74-const hashOutput = await jazz(["schema", "hash"]);75-const currentHash = hashOutput.match(/Current schema hash:\s*([0-9a-f]{12})/)?.[1];76-if (!currentHash) fail(`could not read the current hash from Jazz CLI output: ${hashOutput}`);77-78-const migrationNames: string[] = [];79-for await (const entry of Deno.readDir(MIGRATIONS_DIR)) {80- if (entry.isFile && entry.name.endsWith(".ts")) migrationNames.push(entry.name);81-}82-if (migrationNames.length === 0) fail(`no reviewed migrations found in ${MIGRATIONS_DIR}`);83-84-let currentEdgeFound = false;85-for (const name of migrationNames.sort()) {86- const source = await Deno.readTextFile(`${MIGRATIONS_DIR}/${name}`);87- const fromHash = hashField(source, "fromHash");88- const toHash = hashField(source, "toHash");89- if (!name.endsWith(`-${fromHash}-${toHash}.ts`)) {90- fail(`${name} does not encode its declared ${fromHash} -> ${toHash} edge`);91- }92- for (const hash of [fromHash, toHash]) {93- const snapshotNames = [];94- for await (const entry of Deno.readDir(SNAPSHOTS_DIR)) {95- if (entry.isFile && entry.name.endsWith(`-${hash}.json`)) snapshotNames.push(entry.name);96- }97- if (snapshotNames.length !== 1) {98- fail(`${name} requires exactly one ${hash} snapshot; found ${snapshotNames.length}`);99- }100- const snapshot = JSON.parse(101- await Deno.readTextFile(`${SNAPSHOTS_DIR}/${snapshotNames[0]}`),102- );103- if (JSON.stringify(await jazzSnapshot(hash)) !== JSON.stringify(snapshot)) {104- fail(`${snapshotNames[0]} does not round-trip through Jazz's hash loader`);105- }106- }107- if (toHash === currentHash) currentEdgeFound = true;108-}109-if (!currentEdgeFound) {110- fail(`current schema ${currentHash} has no reviewed incoming migration edge`);111-}112-113-const currentSnapshots: string[] = [];114-for await (const entry of Deno.readDir(SNAPSHOTS_DIR)) {115- if (entry.isFile && entry.name.endsWith(`-${currentHash}.json`)) {116- currentSnapshots.push(entry.name);117- }118-}119-if (currentSnapshots.length !== 1) {120- fail(`current schema ${currentHash} must have exactly one snapshot`);121-}122-123-const currentSnapshot = JSON.parse(124- await Deno.readTextFile(`${SNAPSHOTS_DIR}/${currentSnapshots[0]}`),125-);126-if (JSON.stringify(referenceApp.schema.wasmSchema) !== JSON.stringify(currentSnapshot)) {127- fail(`current snapshot ${currentSnapshots[0]} does not match schema.ts`);128-}129-130-const previousSnapshotName = [];131-for await (const entry of Deno.readDir(SNAPSHOTS_DIR)) {132- if (entry.isFile && entry.name.endsWith("-6c62fec42c35.json")) {133- previousSnapshotName.push(entry.name);134- }135-}136-if (previousSnapshotName.length !== 1) fail("the M1 source snapshot is missing or ambiguous");137-const previousSnapshot = JSON.parse(138- await Deno.readTextFile(`${SNAPSHOTS_DIR}/${previousSnapshotName[0]}`),139-);140-if (JSON.stringify(s.defineApp(migration.from).wasmSchema) !== JSON.stringify(previousSnapshot)) {141- fail("the reviewed lens source does not match the M1 snapshot");142-}143-if (JSON.stringify(s.defineApp(migration.to).wasmSchema) !== JSON.stringify(currentSnapshot)) {144- fail("the reviewed lens target does not match the current snapshot");145-}146-147-const expectedForward = [{148- table: "tasks",149- renamedFrom: "notes",150- operations: [151- { type: "rename", column: "body", value: "text" },152- { type: "introduce", column: "completed", sqlType: "BOOLEAN", value: false },153- ],154-}];155-if (JSON.stringify(migration.forward) !== JSON.stringify(expectedForward)) {156- fail("the reviewed lens must rename notes/body and add completed=false");157-}158-159-console.log(160- `migration contract: ${migrationNames.length} reviewed edge(s), current schema ${currentHash}`,161-);
D tools/check_secret_leaks.ts +0 -40
@@ -1,40 +0,0 @@
1-import { collectBuildArtifactFiles } from "./artifact_files.ts";2-import { serverEnvironmentNames } from "./env_contract.ts";3-import { loadNamedEnvironment } from "./load_env.ts";4-import { findSecretLeaks } from "./secret_scan.ts";5-6-async function sourceFiles(): Promise<string[]> {7- const output = await new Deno.Command("git", {8- args: ["ls-files", "-z", "--cached", "--others", "--exclude-standard"],9- stdout: "piped",10- }).output();11- if (!output.success) throw new Error("Unable to enumerate source files.");12- return new TextDecoder().decode(output.stdout).split("\0").filter(Boolean);13-}14-15-const environment = await loadNamedEnvironment(serverEnvironmentNames);16-const secretValues = serverEnvironmentNames17- .map((name) => ({ name, value: environment[name]?.trim() ?? "" }))18- .filter(({ value }) => value.length > 0);19-const buildArtifacts = await collectBuildArtifactFiles();20-const candidates = [...new Set([...await sourceFiles(), ...buildArtifacts])];21-const files: Array<{ path: string; content: Uint8Array }> = [];22-23-for (const path of candidates) {24- try {25- files.push({ path, content: await Deno.readFile(path) });26- } catch (error) {27- if (error instanceof Deno.errors.NotFound) continue;28- throw error;29- }30-}31-32-const leaks = findSecretLeaks(files, secretValues);33-if (leaks.length > 0) {34- for (const leak of leaks) console.error(`error: ${leak.name} value found in ${leak.path}`);35- Deno.exit(1);36-}37-38-console.log(39- `secret leak check passed (${candidates.length} files including ${buildArtifacts.length} build artifacts, ${secretValues.length} available server secrets)`,40-);
D tools/golden_path.ts +0 -1220
@@ -1,1220 +0,0 @@
1-import { join, resolve } from "node:path";2-import {3- type BrowserTestClient,4- createTwoClientFixture,5- runConcurrentOfflineConvergence,6-} from "@nzip/lofi/testing";7-import { type Browser, type BrowserContext, chromium, type Page } from "playwright";8-import {9- clientEnvironmentNames,10- environmentNames,11- serverEnvironmentNames,12- validateEnvironment,13-} from "./env_contract.ts";14-import {15- artifactPaths,16- type CapturedProcess,17- type CommandRecord,18- initializeFixtureGit,19- installNodeSentinel,20- type JourneyAssertion,21- type JourneyReport,22- type JourneySource,23- materializeCleanProject,24- probeHttpReady,25- reserveLocalPort,26- runCapturedCommand,27- safeChildEnvironment,28- scanAuthorBoundary,29- startReadyProcess,30- writeJourneyReport,31-} from "./golden_path_core.ts";32-import { loadEnvironment } from "./load_env.ts";33-import { checklistUi } from "../apps/reference/src/ui-contract.ts";34-import { redactDiagnosticText } from "../package/testing/safety.ts";35-import { readTraceArchive, sanitizeTraceArchive } from "../package/testing/trace.ts";36-import { assert } from "./assert.ts";37-38-export type GoldenPathCommands = {39- doctor?: string;40- dev: string;41- check: string;42- test: string;43- build: string;44- preview: string;45-};46-47-export type GoldenPathOptions = {48- source: JourneySource;49- /** Repository working tree for checkout mode, or the already-created project for create mode. */50- projectRoot?: string;51- artifactRoot?: string;52- authorPaths?: string[];53- commands?: Partial<GoldenPathCommands>;54- cacheMode?: "existing" | "cold";55- environmentMode?: "isolated-local" | "cloud-from-root";56- timeoutMs?: number;57- islandLabels?: [string, string];58- hmrPath?: string;59- initialCommands?: CommandRecord[];60- sourceRevisionRoot?: string;61- resetArtifactRoot?: boolean;62- journeyStartedAt?: Date;63- journeyStartedPerformanceMs?: number;64- createDurationMs?: number;65- developerCommandCount?: number;66-};67-68-const defaultCommands: GoldenPathCommands = {69- dev: "dev",70- check: "check",71- test: "test",72- build: "build",73- preview: "preview",74-};75-76-const defaultAuthorPaths = [77- "apps/reference/src/app.ts",78- "apps/reference/src/islands",79- "apps/reference/src/pages",80- "apps/reference/src/permissions.ts",81- "apps/reference/src/schema.ts",82- "apps/reference/src/styles",83-];84-85-const retainedBody = "Golden path retained item";86-const updatedBody = "Golden path retained item updated";87-const disposableBody = "Golden path disposable item";88-const offlineDevelopmentBody = "Golden path development offline item";89-const offlineProductionBody = "Golden path production offline item";90-const offlineProductionSyncedBody = "Golden path production offline item synced";91-const replicaClearBody = "Golden path replica-clear disposable item";92-const convergenceTextSeedBody = "Golden path two-client text item";93-const convergenceEditedBody = "Golden path two-client text item edited";94-const convergenceCompletionBody = "Golden path two-client completion item";95-96-function taskArgs(task: string, extra: string[] = []): string[] {97- return ["task", task, ...(extra.length > 0 ? ["--", ...extra] : [])];98-}99-100-function escaped(value: string): string {101- return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");102-}103-104-async function waitForItem(105- page: Page,106- islandLabels: readonly string[],107- body: string,108-): Promise<void> {109- for (const [index, label] of islandLabels.entries()) {110- const island = page.locator("[data-island]").filter({ hasText: label });111- const item = island.getByRole("listitem").filter({ hasText: body });112- if (index === 0) {113- const failure = island.getByRole("status").filter({ hasText: checklistUi.writeFailed });114- await item.or(failure).waitFor({ state: "visible" });115- if (await failure.isVisible()) {116- throw new Error((await failure.textContent()) ?? "Write failed");117- }118- } else {119- await item.waitFor({ state: "visible" });120- }121- }122-}123-124-async function waitForItemAbsent(125- page: Page,126- islandLabels: readonly string[],127- body: string,128-): Promise<void> {129- for (const label of islandLabels) {130- const island = page.locator("[data-island]").filter({ hasText: label });131- await island.getByRole("listitem").filter({ hasText: body }).waitFor({ state: "detached" });132- }133-}134-135-async function addItem(page: Page, island: string, body: string): Promise<void> {136- const section = page.locator("[data-island]").filter({ hasText: island });137- const textbox = section.getByRole("textbox", { name: checklistUi.newItem });138- try {139- await textbox.waitFor({ state: "visible" });140- } catch (error) {141- throw new Error(142- `reference UI is missing accessible textbox "${checklistUi.newItem}" in ${island}; #9 must expose CRUD controls`,143- { cause: error },144- );145- }146- const add = section.getByRole("button", { name: checklistUi.addFrom(island) });147- try {148- await add.waitFor({ state: "visible" });149- } catch (error) {150- throw new Error(151- `reference UI is missing accessible button "${152- checklistUi.addFrom(island)153- }"; #9 must expose CRUD controls`,154- { cause: error },155- );156- }157- await textbox.fill(body);158- await add.click();159-}160-161-async function waitForLocalDurability(page: Page): Promise<void> {162- await page.getByRole("status").filter({163- hasText: new RegExp(164- `(?:${escaped(checklistUi.lastWrite("local"))}|${escaped(checklistUi.lastWrite("global"))})`,165- ),166- }).first().waitFor({ state: "visible" });167-}168-169-async function assertRuntimeCardinality(170- page: Page,171- islandLabels: readonly string[],172-): Promise<void> {173- assert(islandLabels.length === 2, "golden path cardinality requires two mounted islands");174- await page.waitForFunction(async () => {175- const inspector = (globalThis as typeof globalThis & {176- __LOFI_INSPECTOR__?: {177- readSnapshot(): Promise<{178- storage: { driver: string };179- runtime: {180- clients: number;181- consumers: number;182- vendorSubscriptions: number;183- mutationListeners: number;184- };185- }>;186- };187- }).__LOFI_INSPECTOR__;188- const snapshot = await inspector?.readSnapshot();189- return snapshot?.storage.driver === "persistent open" &&190- snapshot.runtime.clients === 1 &&191- snapshot.runtime.consumers === 2 &&192- snapshot.runtime.vendorSubscriptions === 1 &&193- snapshot.runtime.mutationListeners === 1;194- });195-}196-197-async function restartClientThroughInspector(198- page: Page,199- islandLabels: readonly string[],200- retainedItem: string,201- timeoutMs: number,202-): Promise<void> {203- const identity = await armIdentityComparison(page);204- const before = await page.evaluate(() => ({205- timeOrigin: performance.timeOrigin,206- url: location.href,207- }));208- const navigated = page.waitForEvent("domcontentloaded", { timeout: timeoutMs });209- await page.getByRole("button", { name: "Restart client" }).click();210- await navigated;211- const after = await page.evaluate(() => ({212- timeOrigin: performance.timeOrigin,213- url: location.href,214- }));215- assert(after.timeOrigin !== before.timeOrigin, "inspector restart did not replace the document");216- assert(after.url === before.url, "inspector restart changed the application URL");217- assert(218- await identityComparisonMatches(page, identity.token),219- "inspector restart changed the device identity",220- );221- await waitForItem(page, islandLabels, retainedItem);222- for (const label of islandLabels) {223- const island = page.locator("[data-island]").filter({ hasText: label });224- await island.getByRole("status").filter({ hasText: "1 item(s)" }).waitFor({225- state: "visible",226- timeout: timeoutMs,227- });228- }229- await assertRuntimeCardinality(page, islandLabels);230-}231-232-async function armIdentityComparison(page: Page): Promise<{ token: string; present: boolean }> {233- const token = crypto.randomUUID();234- const present = await page.evaluate(async (comparisonToken) => {235- const identity = JSON.stringify(236- Object.entries(localStorage).sort(([left], [right]) => left.localeCompare(right)),237- );238- const digest = new Uint8Array(239- await crypto.subtle.digest("SHA-256", new TextEncoder().encode(identity)),240- );241- const hex = Array.from(digest).map((byte) => byte.toString(16).padStart(2, "0")).join("");242- (globalThis as typeof globalThis & { name: string }).name =243- `lofi-golden:${comparisonToken}:${hex}`;244- return identity !== "[]";245- }, token);246- return { token, present };247-}248-249-async function identityComparisonMatches(page: Page, token: string): Promise<boolean> {250- return await page.evaluate(async (comparisonToken) => {251- const browserGlobal = globalThis as typeof globalThis & { name: string };252- const expected = browserGlobal.name;253- browserGlobal.name = "";254- const identity = JSON.stringify(255- Object.entries(localStorage).sort(([left], [right]) => left.localeCompare(right)),256- );257- const digest = new Uint8Array(258- await crypto.subtle.digest("SHA-256", new TextEncoder().encode(identity)),259- );260- const hex = Array.from(digest).map((byte) => byte.toString(16).padStart(2, "0")).join("");261- return expected === `lofi-golden:${comparisonToken}:${hex}`;262- }, token);263-}264-265-async function exerciseHmr(266- page: Page,267- projectRoot: string,268- hmrPath: string,269- islandLabels: readonly string[],270- retainedItem: string,271- timeoutMs: number,272-): Promise<{ samples: number[]; restore: () => Promise<void> }> {273- const path = resolve(projectRoot, hmrPath);274- const original = await Deno.readTextFile(path);275- const samples: number[] = [];276- for (let cycle = 1; cycle <= 5; cycle++) {277- const started = performance.now();278- await Deno.writeTextFile(279- path,280- `${original}\n:root {\n --lofi-golden-hmr-cycle: ${cycle};\n}\n`,281- );282- await page.waitForFunction(283- (expected) =>284- getComputedStyle(document.documentElement).getPropertyValue("--lofi-golden-hmr-cycle")285- .trim() === expected,286- String(cycle),287- { timeout: timeoutMs },288- );289- samples.push(Math.round(performance.now() - started));290- await waitForItem(page, islandLabels, retainedItem);291- await assertRuntimeCardinality(page, islandLabels);292- }293- return {294- samples,295- restore: async () => await Deno.writeTextFile(path, original),296- };297-}298-299-async function setReferenceConnection(page: Page, connected: boolean): Promise<void> {300- await page.evaluate(async (shouldConnect) => {301- const inspector = (globalThis as typeof globalThis & {302- __LOFI_INSPECTOR__?: { setTransportPaused(paused: boolean): Promise<void> };303- }).__LOFI_INSPECTOR__;304- if (!inspector) throw new Error("development inspector is unavailable");305- await inspector.setTransportPaused(!shouldConnect);306- }, connected);307-}308-309-async function exerciseReplicaClear(310- browser: Browser,311- url: string,312- islandLabels: readonly string[],313- timeoutMs: number,314-): Promise<void> {315- const context = await browser.newContext();316- try {317- const page = await context.newPage();318- await page.goto(url, { waitUntil: "domcontentloaded", timeout: timeoutMs });319- await page.getByRole("textbox", { name: checklistUi.newItem }).first().waitFor({320- state: "visible",321- });322- await assertRuntimeCardinality(page, islandLabels);323- await addItem(page, islandLabels[0], replicaClearBody);324- await waitForItem(page, islandLabels, replicaClearBody);325- await waitForLocalDurability(page);326- const identity = await armIdentityComparison(page);327- assert(identity.present, "replica-clear fixture did not create an identity state");328- const navigated = page.waitForEvent("domcontentloaded", { timeout: timeoutMs });329- page.once("dialog", (dialog) => dialog.accept());330- await page.getByRole("button", { name: "Clear local replica" }).click();331- await navigated;332- await waitForItemAbsent(page, islandLabels, replicaClearBody);333- assert(334- await identityComparisonMatches(page, identity.token),335- "replica clear changed the device-local identity",336- );337- } finally {338- await context.close();339- }340-}341-342-async function inspectorMarkerFiles(root: string): Promise<string[]> {343- const matches: string[] = [];344- async function visit(path: string): Promise<void> {345- for await (const entry of Deno.readDir(path)) {346- const child = join(path, entry.name);347- if (entry.isDirectory) await visit(child);348- else if (entry.isFile) {349- const content = await Deno.readTextFile(child).catch(() => "");350- if (content.includes("lofi-development-inspector")) matches.push(child);351- }352- }353- }354- await visit(root);355- return matches.sort();356-}357-358-async function observeReconnectSettlement(359- page: Page,360- timeoutMs: number,361- required: boolean,362-): Promise<JourneyAssertion> {363- if (!required) {364- return {365- name: "development reconnect settlement",366- status: "blocked",367- detail:368- "Local-only mode has no global durability endpoint; offline retention passed, but this run makes no transport convergence claim.",369- };370- }371- try {372- const global = page.getByRole("status").filter({373- hasText: checklistUi.lastWrite("global"),374- }).first();375- const failure = page.getByRole("status").filter({ hasText: checklistUi.writeFailed }).first();376- await global.or(failure).waitFor({377- state: "visible",378- timeout: timeoutMs,379- });380- if (await failure.isVisible()) {381- throw new Error((await failure.textContent()) ?? "Write failed");382- }383- return {384- name: "development reconnect settlement",385- status: "passed",386- detail: "The configured server exposed global settlement after reconnection.",387- };388- } catch {389- throw new Error(390- "cloud evidence failed: reconnect did not expose global settlement before the readiness deadline",391- );392- }393-}394-395-async function journeyEnvironment(396- sourceRoot: string,397- mode: "isolated-local" | "cloud-from-root",398- artifactRoot: string,399-): Promise<Record<string, string>> {400- const isolated = safeChildEnvironment();401- if (mode === "isolated-local") return await installNodeSentinel(isolated, artifactRoot);402-403- const configured = await loadEnvironment(join(sourceRoot, ".env"));404- const validation = validateEnvironment(configured);405- if (!validation.ok) throw new Error(validation.errors.join(" "));406- if (validation.mode !== "cloud-configured") {407- throw new Error(408- "cloud evidence requires the complete JAZZ_APP_ID/JAZZ_SERVER_URL pair in the root .env or process environment",409- );410- }411- const allowlisted = { ...isolated };412- for (const name of clientEnvironmentNames) {413- allowlisted[name] = configured[name]?.trim() ?? "";414- }415- for (const name of serverEnvironmentNames) allowlisted[name] = "";416- return await installNodeSentinel(allowlisted, artifactRoot);417-}418-419-async function updateItem(page: Page, body: string, nextBody: string): Promise<void> {420- const edit = page.getByRole("button", { name: checklistUi.edit(body), exact: true }).first();421- try {422- await edit.click();423- } catch (error) {424- throw new Error(`reference UI is missing accessible button "${checklistUi.edit(body)}"`, {425- cause: error,426- });427- }428- const textbox = page.getByRole("textbox", { name: checklistUi.edit(body), exact: true }).first();429- try {430- await textbox.fill(nextBody);431- } catch (error) {432- throw new Error(`reference UI is missing accessible textbox "${checklistUi.edit(body)}"`, {433- cause: error,434- });435- }436- const save = page.getByRole("button", { name: checklistUi.save(body), exact: true }).first();437- try {438- await save.click();439- } catch (error) {440- throw new Error(`reference UI is missing accessible button "${checklistUi.save(body)}"`, {441- cause: error,442- });443- }444-}445-446-async function completeItem(page: Page, body: string): Promise<void> {447- const name = checklistUi.complete(body);448- const checkboxes = page.getByRole("checkbox", { name });449- try {450- await checkboxes.first().waitFor({ state: "visible" });451- } catch (error) {452- throw new Error(453- `reference UI needs checkbox "${checklistUi.complete(body)}"`,454- { cause: error },455- );456- }457- await checkboxes.first().click();458- await page.waitForFunction((accessibleName) => {459- const matches = [...document.querySelectorAll<HTMLInputElement>('input[type="checkbox"]')]460- .filter((element) => element.getAttribute("aria-label") === accessibleName);461- return matches.length === 2 && matches.every((element) => element.checked);462- }, checklistUi.complete(body));463-}464-465-async function assertCompleted(page: Page, body: string): Promise<void> {466- const name = checklistUi.complete(body);467- const checkboxes = page.getByRole("checkbox", { name });468- await checkboxes.first().waitFor({ state: "visible" });469- await page.waitForFunction((accessibleName) => {470- const matches = [...document.querySelectorAll<HTMLInputElement>('input[type="checkbox"]')]471- .filter((element) => element.getAttribute("aria-label") === accessibleName);472- return matches.length === 2 && matches.every((element) => element.checked);473- }, name);474- assert(await checkboxes.count() === 2, `expected two completion controls for ${body}`);475- assert(476- await checkboxes.evaluateAll((elements) =>477- elements.every((element) => (element as HTMLInputElement).checked)478- ),479- `completion for ${body} did not survive reload in both islands`,480- );481-}482-483-async function deleteItem(page: Page, body: string): Promise<void> {484- const button = page.getByRole("button", { name: checklistUi.delete(body), exact: true }).first();485- try {486- await button.click();487- } catch (error) {488- throw new Error(`reference UI is missing accessible button "${checklistUi.delete(body)}"`, {489- cause: error,490- });491- }492-}493-494-async function waitForProductionPwa(page: Page, timeoutMs: number): Promise<void> {495- await page.waitForFunction(496- () => {497- return (globalThis as typeof globalThis & { __LOFI_PWA_STATE__?: string })498- .__LOFI_PWA_STATE__ === "ready";499- },500- undefined,501- { timeout: timeoutMs },502- );503- await page.waitForFunction(() => navigator.serviceWorker.controller !== null, undefined, {504- timeout: timeoutMs,505- });506-}507-508-async function waitForChecklistReady(page: Page, timeoutMs: number): Promise<void> {509- await page.getByRole("textbox", { name: checklistUi.newItem }).first().waitFor({510- state: "visible",511- timeout: timeoutMs,512- });513- await page.getByRole("status").filter({ hasText: /\d+ item\(s\)/ }).first().waitFor({514- state: "visible",515- timeout: timeoutMs,516- });517-}518-519-async function valueFreeClientState(client: BrowserTestClient) {520- const renderedRows = await client.page.locator("[data-task-id]").count();521- const completedControls = await client.page.locator('input[type="checkbox"]:checked').count();522- return { offline: client.offline, renderedRows, completedControls };523-}524-525-async function exerciseTwoClientCloudConvergence(526- browser: Browser,527- url: string,528- islandLabels: readonly string[],529- timeoutMs: number,530- artifactRoot: string,531- redactValues: readonly string[],532-): Promise<void> {533- const fixture = await createTwoClientFixture({534- baseURL: url,535- browser,536- identity: {537- mode: "shared",538- async preparePrimary(client) {539- await waitForProductionPwa(client.page, timeoutMs);540- await waitForChecklistReady(client.page, timeoutMs);541- },542- },543- artifacts: {544- directory: join(artifactRoot, "two-client-convergence"),545- secretValues: redactValues,546- },547- });548- try {549- await Promise.all(fixture.clients.map(async (client) => {550- await waitForProductionPwa(client.page, timeoutMs);551- await waitForChecklistReady(client.page, timeoutMs);552- }));553- await addItem(fixture.first.page, islandLabels[0], convergenceTextSeedBody);554- await waitForItem(fixture.first.page, islandLabels, convergenceTextSeedBody);555- await addItem(fixture.first.page, islandLabels[0], convergenceCompletionBody);556- await waitForItem(fixture.first.page, islandLabels, convergenceCompletionBody);557- await observeReconnectSettlement(fixture.first.page, timeoutMs, true);558- await waitForItem(fixture.second.page, islandLabels, convergenceTextSeedBody);559- await waitForItem(fixture.second.page, islandLabels, convergenceCompletionBody);560-561- type ConvergenceEdit = { kind: "text" } | { kind: "completion" };562- await runConcurrentOfflineConvergence<ConvergenceEdit, BrowserTestClient>(fixture, {563- edits: [{ kind: "text" }, { kind: "completion" }],564- async ready(client) {565- await waitForProductionPwa(client.page, timeoutMs);566- await waitForItem(client.page, islandLabels, convergenceTextSeedBody);567- await waitForItem(client.page, islandLabels, convergenceCompletionBody);568- },569- async apply(client, edit) {570- if (edit.kind === "text") {571- await updateItem(client.page, convergenceTextSeedBody, convergenceEditedBody);572- } else {573- await completeItem(client.page, convergenceCompletionBody);574- }575- },576- async locallyApplied(client, edit) {577- if (edit.kind === "text") {578- await waitForItem(client.page, islandLabels, convergenceEditedBody);579- } else {580- await assertCompleted(client.page, convergenceCompletionBody);581- }582- await waitForLocalDurability(client.page);583- },584- async whilePending(current) {585- await current.first.reloadPage();586- await waitForProductionPwa(current.first.page, timeoutMs);587- await waitForItem(current.first.page, islandLabels, convergenceEditedBody);588-589- await current.second.restartPage();590- await waitForProductionPwa(current.second.page, timeoutMs);591- await waitForItem(current.second.page, islandLabels, convergenceCompletionBody);592- await assertCompleted(current.second.page, convergenceCompletionBody);593- },594- async converged(current) {595- for (const client of current.clients) {596- await waitForItem(client.page, islandLabels, convergenceEditedBody);597- await assertCompleted(client.page, convergenceCompletionBody);598- }599- },600- snapshot: valueFreeClientState,601- failureLabel: "cloud-two-client-convergence",602- });603-604- for (const body of [convergenceEditedBody, convergenceCompletionBody]) {605- await deleteItem(fixture.first.page, body);606- await waitForItemAbsent(fixture.first.page, islandLabels, body);607- await observeReconnectSettlement(fixture.first.page, timeoutMs, true);608- await waitForItemAbsent(fixture.second.page, islandLabels, body);609- }610- } catch (error) {611- await fixture.captureFailure("cloud-two-client-cleanup", valueFreeClientState).catch(() => {612- // The original convergence or cleanup failure remains authoritative.613- });614- throw error;615- } finally {616- await fixture.close();617- }618-}619-620-async function screenshotFailure(page: Page | null, path: string): Promise<void> {621- if (!page || page.isClosed()) return;622- try {623- await page.screenshot({ path, fullPage: true });624- } catch {625- // Process logs and the trace remain authoritative when the page itself is unavailable.626- }627-}628-629-function byteSequencePresent(haystack: Uint8Array, needle: Uint8Array): boolean {630- if (needle.length === 0 || haystack.length < needle.length) return false;631- outer:632- for (let offset = 0; offset <= haystack.length - needle.length; offset++) {633- for (let index = 0; index < needle.length; index++) {634- if (haystack[offset + index] !== needle[index]) continue outer;635- }636- return true;637- }638- return false;639-}640-641-async function sanitizeRetainedTrace(642- path: string,643- configuredValues: readonly string[],644-): Promise<void> {645- await sanitizeTraceArchive(646- path,647- (value) => redactDiagnosticText(value, configuredValues),648- );649- const entries = await readTraceArchive(path);650- assert(651- Object.keys(entries).every((name) => !name.startsWith("resources/")),652- "sanitized trace retained a response/source resource",653- );654- const encoder = new TextEncoder();655- for (const configured of configuredValues.filter(Boolean)) {656- const needle = encoder.encode(configured);657- assert(658- Object.values(entries).every((bytes) => !byteSequencePresent(bytes, needle)),659- "sanitized trace retained a configured environment value",660- );661- }662- const traceText = Object.entries(entries)663- .filter(([name]) => name.endsWith(".trace"))664- .map(([, bytes]) => new TextDecoder().decode(bytes))665- .join("\n");666- assert(667- !/"identity"\s*:\s*"[^"\n]+"/.test(traceText),668- "sanitized trace retained an identity-valued Playwright result",669- );670-}671-672-function commandFailure(record: CommandRecord): Error {673- return new Error(674- `${record.name} failed with exit ${record.exitCode}; rerun ${Deno.execPath()} ${675- record.args.join(" ")676- } and inspect ${record.stderrPath}`,677- );678-}679-680-async function sourceRevision(681- sourceRoot: string,682- environment: Record<string, string>,683-): Promise<string> {684- const output = await new Deno.Command("git", {685- args: ["rev-parse", "HEAD"],686- cwd: sourceRoot,687- clearEnv: true,688- env: environment,689- stdout: "piped",690- stderr: "null",691- }).output();692- return output.success ? new TextDecoder().decode(output.stdout).trim() : "unavailable";693-}694-695-export async function runJourney(options: GoldenPathOptions): Promise<JourneyReport> {696- const sourceRoot = resolve(options.projectRoot ?? Deno.cwd());697- const revisionRoot = resolve(options.sourceRevisionRoot ?? sourceRoot);698- const environmentMode = options.environmentMode ?? "isolated-local";699- const artifacts = artifactPaths(700- resolve(701- options.artifactRoot ??702- join(703- sourceRoot,704- environmentMode === "cloud-from-root"705- ? "test-results/golden-path-cloud"706- : "test-results/golden-path",707- ),708- ),709- );710- if (options.resetArtifactRoot !== false) {711- await Deno.remove(artifacts.root, { recursive: true }).catch((error) => {712- if (!(error instanceof Deno.errors.NotFound)) throw error;713- });714- }715- await Deno.mkdir(artifacts.root, { recursive: true });716-717- const startedAt = options.journeyStartedAt ?? new Date();718- const timeoutMs = options.timeoutMs ?? 60_000;719- const commands = { ...defaultCommands, ...options.commands };720- const islandLabels = options.islandLabels ?? ["North island", "South island"];721- const environment = await journeyEnvironment(sourceRoot, environmentMode, artifacts.root);722- const configuredEnvironment = await loadEnvironment(join(sourceRoot, ".env"));723- const redactValues = [724- ...new Set(725- environmentNames.flatMap((name) => [configuredEnvironment[name], environment[name]]).filter(726- Boolean,727- ),728- ),729- ];730- const commit = await sourceRevision(revisionRoot, environment);731- const commandRecords: CommandRecord[] = [...options.initialCommands ?? []];732- const assertions: JourneyAssertion[] = [];733- let projectRoot = sourceRoot;734- let browser: Browser | null = null;735- let context: BrowserContext | null = null;736- let page: Page | null = null;737- let dev: CapturedProcess | null = null;738- let preview: CapturedProcess | null = null;739- let browserVersion = "not launched";740- let devReadyMs: number | undefined;741- let firstRetainedWriteMs: number | undefined;742- let createToFirstRetainedWriteMs: number | undefined;743- let hmrMs: number[] | undefined;744- let restoreHmr: (() => Promise<void>) | null = null;745- let failure: unknown;746-747- const report: JourneyReport = {748- schemaVersion: 1,749- source: options.source,750- environmentMode: environmentMode === "cloud-from-root" ? "cloud-allowlisted" : "isolated-local",751- status: "failed",752- startedAt: startedAt.toISOString(),753- completedAt: startedAt.toISOString(),754- runtime: {755- deno: Deno.version.deno,756- typescript: Deno.version.typescript,757- v8: Deno.version.v8,758- os: Deno.build.os,759- arch: Deno.build.arch,760- browser: browserVersion,761- commit,762- },763- cacheMode: options.cacheMode ?? "existing",764- measurements: {765- developerCommandCount: options.developerCommandCount ?? (options.source === "create" ? 3 : 1),766- createMs: options.createDurationMs,767- },768- commands: commandRecords,769- assertions,770- authorBoundaryViolations: [],771- artifacts,772- };773-774- try {775- if (options.source === "checkout") {776- projectRoot = await materializeCleanProject(sourceRoot);777- commandRecords.push(778- ...await initializeFixtureGit(projectRoot, environment, artifacts.root, redactValues),779- );780- }781-782- report.authorBoundaryViolations = await scanAuthorBoundary(783- projectRoot,784- options.authorPaths ?? defaultAuthorPaths,785- );786- assert(787- report.authorBoundaryViolations.length === 0,788- `author boundary leaked framework plumbing: ${789- report.authorBoundaryViolations.map((item) => `${item.path}:${item.line} ${item.rule}`)790- .join(791- ", ",792- )793- }`,794- );795- assertions.push({796- name: "author boundary",797- status: "passed",798- detail: "No forbidden runtime, worker, transport, Workbox, or capability plumbing found.",799- });800- if (environmentMode === "cloud-from-root") {801- assert(802- clientEnvironmentNames.every((name) => Boolean(environment[name])) &&803- serverEnvironmentNames.every((name) => environment[name] === ""),804- "cloud child environment did not isolate server credentials",805- );806- assertions.push({807- name: "cloud credential isolation",808- status: "passed",809- detail:810- "The application child received only the public Jazz pair; server credentials were explicitly blank.",811- });812- }813-814- if (commands.doctor) {815- const doctor = await runCapturedCommand({816- cwd: projectRoot,817- args: taskArgs(commands.doctor),818- environment,819- artifactRoot: artifacts.root,820- name: "doctor",821- redactValues,822- });823- commandRecords.push(doctor);824- if (doctor.exitCode !== 0) throw commandFailure(doctor);825- assertions.push({826- name: "doctor preflight",827- status: "passed",828- detail: "Generated diagnostics completed without starting the application.",829- });830- }831-832- try {833- browser = await chromium.launch({ headless: true });834- } catch (error) {835- throw new Error(836- "Chromium is unavailable; install the pinned browser through the repository's explicit Deno browser-install task.",837- { cause: error },838- );839- }840- browserVersion = browser.version();841- report.runtime.browser = browserVersion;842- context = await browser.newContext();843- await context.tracing.start({ screenshots: false, snapshots: false, sources: false });844- page = await context.newPage();845-846- const port = reserveLocalPort();847- const devStarted = performance.now();848- dev = startReadyProcess({849- cwd: projectRoot,850- args: taskArgs(commands.dev, ["--host", "127.0.0.1", "--port", String(port)]),851- environment,852- artifactRoot: artifacts.root,853- name: "dev",854- readyPattern: /(http:\/\/(?:127\.0\.0\.1|localhost):\d+\/?)/,855- readyCheck: probeHttpReady,856- timeoutMs,857- redactValues,858- });859- const devUrl = await dev.ready;860- devReadyMs = Math.round(performance.now() - devStarted);861- await page.goto(devUrl, { waitUntil: "domcontentloaded", timeout: timeoutMs });862- await page.getByRole("textbox", { name: checklistUi.newItem }).first().waitFor({863- state: "visible",864- });865- await assertRuntimeCardinality(page, islandLabels);866- await page.getByRole("status").filter({ hasText: /\d+ item\(s\)/ }).first().waitFor({867- state: "visible",868- });869- const inspector = page.locator('[data-lofi-inspector="lofi-development-inspector"]');870- await inspector.waitFor({ state: "attached" });871- const inspectorSnapshot = await page.evaluate(async () => {872- const bridge = (globalThis as typeof globalThis & {873- __LOFI_INSPECTOR__?: { readSnapshot(): Promise<unknown> };874- }).__LOFI_INSPECTOR__;875- if (!bridge) throw new Error("development inspector bridge is unavailable");876- return await bridge.readSnapshot();877- });878- const serializedInspector = JSON.stringify(inspectorSnapshot);879- assert(880- serializedInspector.includes("live detail unavailable") ||881- serializedInspector.includes("not configured"),882- "inspector must name unavailable transport precision",883- );884- assert(885- !/secret|token|password/i.test(serializedInspector),886- "inspector snapshot exposed secrets",887- );888- if (environmentMode === "isolated-local") {889- assert(890- await page.getByRole("button", { name: "Transport pause unavailable in local-only" })891- .isDisabled(),892- "local-only inspector must disable cloud transport controls",893- );894- }895- assertions.push({896- name: "development inspector",897- status: "passed",898- detail:899- "The development-only surface exposed value-free storage, durability, runtime, and explicitly unavailable vendor signals.",900- });901- devReadyMs = Math.round(performance.now() - devStarted);902- assertions.push({903- name: "development readiness",904- status: "passed",905- detail: `Hydrated author UI and the persistent runtime were usable in ${devReadyMs}ms.`,906- });907-908- await addItem(page, islandLabels[0], retainedBody);909- await waitForItem(page, islandLabels, retainedBody);910- await waitForLocalDurability(page);911- firstRetainedWriteMs = Math.round(performance.now() - devStarted);912- if (options.journeyStartedPerformanceMs !== undefined) {913- createToFirstRetainedWriteMs = Math.round(914- performance.now() - options.journeyStartedPerformanceMs,915- );916- }917- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });918- await waitForItem(page, islandLabels, retainedBody);919- await assertRuntimeCardinality(page, islandLabels);920- assertions.push({921- name: "retained development write",922- status: "passed",923- detail:924- "The local write survived reload and both islands kept one shared runtime subscription.",925- });926-927- await restartClientThroughInspector(page, islandLabels, retainedBody, timeoutMs);928- assertions.push({929- name: "inspector client restart",930- status: "passed",931- detail: "The development-only client restart retained data and restored runtime cardinality.",932- });933-934- const hmr = await exerciseHmr(935- page,936- projectRoot,937- options.hmrPath ??938- (options.source === "create"939- ? "src/styles/global.css"940- : "apps/reference/src/styles/global.css"),941- islandLabels,942- retainedBody,943- timeoutMs,944- );945- hmrMs = hmr.samples;946- restoreHmr = hmr.restore;947- assertions.push({948- name: "HMR state and cardinality",949- status: "passed",950- detail:951- `Five observable style edits retained data with one client, two consumers, and one vendor subscription (${952- hmrMs.join(", ")953- }ms).`,954- });955-956- await updateItem(page, retainedBody, updatedBody);957- await waitForItem(page, islandLabels, updatedBody);958- await completeItem(page, updatedBody);959- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });960- await waitForItem(page, islandLabels, updatedBody);961- await assertCompleted(page, updatedBody);962-963- await addItem(page, islandLabels[0], disposableBody);964- await waitForItem(page, islandLabels, disposableBody);965- if (environmentMode === "cloud-from-root") {966- await observeReconnectSettlement(page, timeoutMs, true);967- }968- await deleteItem(page, disposableBody);969- await waitForItemAbsent(page, islandLabels, disposableBody);970- if (environmentMode === "cloud-from-root") {971- const online = await observeReconnectSettlement(page, timeoutMs, true);972- assertions.push({973- ...online,974- name: "development online settlement",975- detail:976- "The online insert and delete reached global durability before the inspector paused transport.",977- });978- }979- assertions.push({980- name: "accessible CRUD",981- status: "passed",982- detail: "Create, update, complete, and delete worked through named author-facing controls.",983- });984-985- if (environmentMode === "cloud-from-root") {986- await setReferenceConnection(page, false);987- } else {988- await context.setOffline(true);989- }990- await addItem(page, islandLabels[1], offlineDevelopmentBody);991- await waitForItem(page, islandLabels, offlineDevelopmentBody);992- await waitForLocalDurability(page);993- if (environmentMode === "cloud-from-root") await setReferenceConnection(page, true);994- else await context.setOffline(false);995- assertions.push(996- await observeReconnectSettlement(page, timeoutMs, environmentMode === "cloud-from-root"),997- );998- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });999- await waitForItem(page, islandLabels, offlineDevelopmentBody);1000- assertions.push({1001- name: "development offline write",1002- status: "passed",1003- detail: environmentMode === "cloud-from-root"1004- ? "A loaded page accepted a local write while Jazz transport was paused and retained it after transport resumed."1005- : "A loaded page accepted a local write offline and retained it after network return.",1006- });1007-1008- if (environmentMode === "isolated-local") {1009- await exerciseReplicaClear(browser, devUrl, islandLabels, timeoutMs);1010- assertions.push({1011- name: "inspector replica clear",1012- status: "passed",1013- detail:1014- "A confirmation-gated clear removed an isolated OPFS replica while preserving its in-memory-compared identity state.",1015- });1016- }1017-1018- const devStderrPath = dev.stderrPath;1019- await dev.stop();1020- dev = null;1021- const devStderr = await Deno.readTextFile(devStderrPath);1022- assert(1023- !devStderr.includes("error: development server stopped"),1024- `normal development shutdown printed a fatal diagnostic; inspect ${devStderrPath}`,1025- );1026- assertions.push({1027- name: "development shutdown",1028- status: "passed",1029- detail:1030- "The generated development command stopped on the harness signal without a false failure.",1031- });1032- if (restoreHmr) await restoreHmr();1033- restoreHmr = null;1034- for (1035- const [name, task] of [1036- ["check", commands.check],1037- ["test", commands.test],1038- ["build", commands.build],1039- ] as const1040- ) {1041- const record = await runCapturedCommand({1042- cwd: projectRoot,1043- args: taskArgs(task),1044- environment,1045- artifactRoot: artifacts.root,1046- name,1047- redactValues,1048- });1049- commandRecords.push(record);1050- if (record.exitCode !== 0) throw commandFailure(record);1051- }1052- assertions.push({1053- name: "public verification commands",1054- status: "passed",1055- detail: "check, test, and build completed through Deno tasks.",1056- });1057- const productionRoot = join(1058- projectRoot,1059- options.source === "create" ? "dist" : "apps/reference/dist",1060- );1061- const inspectorFiles = await inspectorMarkerFiles(productionRoot);1062- assert(1063- inspectorFiles.length === 0,1064- `production build contains development inspector markers: ${inspectorFiles.join(", ")}`,1065- );1066- assertions.push({1067- name: "production inspector exclusion",1068- status: "passed",1069- detail: "The production bundle contains no development-inspector marker.",1070- });1071-1072- preview = startReadyProcess({1073- cwd: projectRoot,1074- args: taskArgs(commands.preview, ["--port", String(port)]),1075- environment,1076- artifactRoot: artifacts.root,1077- name: "preview",1078- readyPattern: /(http:\/\/127\.0\.0\.1:\d+\/)/,1079- readyCheck: probeHttpReady,1080- timeoutMs,1081- redactValues,1082- });1083- const previewUrl = await preview.ready;1084- assert(new URL(previewUrl).origin === new URL(devUrl).origin, "preview must reuse dev origin");1085- await page.goto(previewUrl, { waitUntil: "domcontentloaded", timeout: timeoutMs });1086- assert(1087- await page.locator('[data-lofi-inspector="lofi-development-inspector"]').count() === 0,1088- "production preview mounted the development inspector",1089- );1090- await waitForItem(page, islandLabels, updatedBody);1091- await waitForProductionPwa(page, timeoutMs);1092- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });1093- await waitForProductionPwa(page, timeoutMs);1094-1095- await context.setOffline(true);1096- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });1097- await waitForItem(page, islandLabels, updatedBody);1098- await addItem(page, islandLabels[0], offlineProductionBody);1099- await waitForItem(page, islandLabels, offlineProductionBody);1100- await waitForLocalDurability(page);1101- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });1102- await waitForItem(page, islandLabels, offlineProductionBody);1103- await context.setOffline(false);1104- if (environmentMode === "cloud-from-root") {1105- await updateItem(page, offlineProductionBody, offlineProductionSyncedBody);1106- await waitForItem(page, islandLabels, offlineProductionSyncedBody);1107- assertions.push(await observeReconnectSettlement(page, timeoutMs, true));1108- }1109- await page.reload({ waitUntil: "domcontentloaded", timeout: timeoutMs });1110- await waitForItem(1111- page,1112- islandLabels,1113- environmentMode === "cloud-from-root" ? offlineProductionSyncedBody : offlineProductionBody,1114- );1115- assertions.push({1116- name: "production offline cold start",1117- status: "passed",1118- detail: "The service-worker shell and OPFS data survived cold offline reload and editing.",1119- });1120-1121- if (environmentMode === "cloud-from-root") {1122- await exerciseTwoClientCloudConvergence(1123- browser,1124- previewUrl,1125- islandLabels,1126- timeoutMs,1127- artifacts.root,1128- redactValues,1129- );1130- assertions.push({1131- name: "cloud two-client convergence",1132- status: "passed",1133- detail:1134- "Two isolated OPFS replicas shared one in-memory-restored identity, retained orthogonal offline edits through reload/page restart, converged after reconnect, and cleaned up globally.",1135- });1136- }1137-1138- if (environmentMode === "cloud-from-root") {1139- for (const body of [updatedBody, offlineDevelopmentBody, offlineProductionSyncedBody]) {1140- await deleteItem(page, body);1141- await waitForItemAbsent(page, islandLabels, body);1142- assertions.push(await observeReconnectSettlement(page, timeoutMs, true));1143- }1144- assertions.push({1145- name: "cloud fixture cleanup",1146- status: "passed",1147- detail:1148- "All golden-path rows were deleted through the public UI and the delete mutations reached global durability before the throwaway browser identity closed.",1149- });1150- }1151-1152- report.status = "passed";1153- } catch (error) {1154- failure = error;1155- assertions.push({1156- name: "golden journey",1157- status: "failed",1158- detail: error instanceof Error ? error.message : String(error),1159- });1160- await screenshotFailure(page, artifacts.screenshot);1161- } finally {1162- if (context) {1163- await context.setOffline(false).catch(() => undefined);1164- try {1165- await context.tracing.stop({ path: artifacts.trace });1166- await sanitizeRetainedTrace(artifacts.trace, redactValues);1167- assertions.push({1168- name: "trace artifact safety",1169- status: "passed",1170- detail:1171- "The snapshot-free retained trace omitted response/source resources, identity-valued results, and configured environment values.",1172- });1173- } catch (error) {1174- await Deno.remove(artifacts.trace).catch(() => undefined);1175- const traceFailure = new Error(1176- `retained trace could not be made value-free: ${1177- error instanceof Error ? error.message : String(error)1178- }`,1179- { cause: error },1180- );1181- if (!failure) failure = traceFailure;1182- report.status = "failed";1183- assertions.push({1184- name: "trace artifact safety",1185- status: "failed",1186- detail: traceFailure.message,1187- });1188- }1189- }1190- await preview?.stop().catch(() => undefined);1191- await dev?.stop().catch(() => undefined);1192- await restoreHmr?.().catch(() => undefined);1193- await context?.close().catch(() => undefined);1194- await browser?.close().catch(() => undefined);1195- if (options.source === "checkout" && projectRoot !== sourceRoot) {1196- await Deno.remove(resolve(projectRoot, ".."), { recursive: true }).catch(() => {1197- assertions.push({1198- name: "clean checkout cleanup",1199- status: "blocked",1200- detail: `Temporary checkout cleanup failed for ${projectRoot}.`,1201- });1202- });1203- }1204- report.completedAt = new Date().toISOString();1205- report.measurements.devReadyMs = devReadyMs;1206- report.measurements.firstRetainedWriteMs = firstRetainedWriteMs;1207- report.measurements.createToFirstRetainedWriteMs = createToFirstRetainedWriteMs;1208- report.measurements.hmrMs = hmrMs;1209- if (hmrMs?.length) {1210- const sorted = [...hmrMs].sort((left, right) => left - right);1211- report.measurements.hmrMedianMs = sorted[Math.floor(sorted.length / 2)];1212- report.measurements.hmrSlowestMs = sorted.at(-1);1213- }1214- report.runtime.browser = browserVersion;1215- await writeJourneyReport(report);1216- }1217-1218- if (failure) throw failure;1219- return report;1220-}
D tools/golden_path_checkout.ts +0 -18

Not shown: this page already shows 6000 lines of diff.

D tools/golden_path_core.ts +0 -707

Not shown: this page already shows 6000 lines of diff.

D tools/golden_path_core_test.ts +0 -340

Not shown: this page already shows 6000 lines of diff.

D tools/golden_path_create.ts +0 -79

Not shown: this page already shows 6000 lines of diff.

D tools/run_jazz2_spike.ts +0 -49

Not shown: this page already shows 6000 lines of diff.

D tools/run_reference.ts +0 -176

Not shown: this page already shows 6000 lines of diff.