diff --git a/.github/workflows/deploy-web-gcp-hipaa.yml b/.github/workflows/deploy-web-gcp-hipaa.yml new file mode 100644 index 0000000..ccf197a --- /dev/null +++ b/.github/workflows/deploy-web-gcp-hipaa.yml @@ -0,0 +1,279 @@ +name: Deploy Web (GCP HIPAA) + +on: + push: + branches: + - codex/prod-hipaa + workflow_dispatch: + +permissions: + contents: read + id-token: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - run: pnpm install --frozen-lockfile + + - uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_DEPLOY_SERVICE_ACCOUNT }} + + - uses: google-github-actions/setup-gcloud@v2 + with: + project_id: ${{ secrets.GCP_PROJECT_ID }} + + - name: Validate required configuration + env: + GCP_REGION: ${{ secrets.GCP_REGION }} + GCP_ARTIFACT_REPO: ${{ secrets.GCP_ARTIFACT_REPO }} + GCP_CLOUD_RUN_SERVICE: ${{ secrets.GCP_CLOUD_RUN_SERVICE }} + GCP_RUNTIME_SERVICE_ACCOUNT: ${{ secrets.GCP_RUNTIME_SERVICE_ACCOUNT }} + GCP_WHISPER_CLOUD_RUN_SERVICE: ${{ secrets.GCP_WHISPER_CLOUD_RUN_SERVICE }} + GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT: ${{ secrets.GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT }} + GCP_VPC_CONNECTOR: ${{ secrets.GCP_VPC_CONNECTOR }} + GCP_CLOUD_SQL_INSTANCE: ${{ secrets.GCP_CLOUD_SQL_INSTANCE }} + GCP_NEXTAUTH_URL: ${{ secrets.GCP_NEXTAUTH_URL }} + NEXT_PUBLIC_SECURE_STORAGE_KEY: ${{ secrets.NEXT_PUBLIC_SECURE_STORAGE_KEY }} + run: | + for key in GCP_REGION GCP_ARTIFACT_REPO GCP_CLOUD_RUN_SERVICE GCP_RUNTIME_SERVICE_ACCOUNT GCP_WHISPER_CLOUD_RUN_SERVICE GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT GCP_VPC_CONNECTOR GCP_CLOUD_SQL_INSTANCE GCP_NEXTAUTH_URL NEXT_PUBLIC_SECURE_STORAGE_KEY; do + if [ -z "${!key}" ]; then + echo "Missing required secret: $key" + exit 1 + fi + done + + - name: Enable required APIs + run: | + gcloud services enable \ + run.googleapis.com \ + cloudbuild.googleapis.com \ + artifactregistry.googleapis.com \ + secretmanager.googleapis.com \ + logging.googleapis.com \ + sqladmin.googleapis.com + + - name: Ensure required Secret Manager secrets exist + run: | + for name in ANTHROPIC_API_KEY AUTH_SECRET GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET DATABASE_URL REDIS_URL; do + gcloud secrets describe "$name" >/dev/null + done + + - name: Run DB migrations via Cloud SQL Proxy + env: + CLOUD_SQL_INSTANCE: ${{ secrets.GCP_CLOUD_SQL_INSTANCE }} + run: | + DATABASE_URL_RAW="$(gcloud secrets versions access latest --secret DATABASE_URL | tr -d '\n')" + DATABASE_URL_PROXY="$(DATABASE_URL_RAW="$DATABASE_URL_RAW" node -e ' + const raw = process.env.DATABASE_URL_RAW?.trim() + if (!raw) process.exit(1) + try { + const url = new URL(raw) + url.hostname = "127.0.0.1" + url.port = "55432" + url.searchParams.delete("sslmode") + process.stdout.write(url.toString()) + } catch { + const separator = "@/"; + const index = raw.indexOf(separator) + if (index <= 0) process.exit(1) + const prefix = raw.slice(0, index) + const remainder = raw.slice(index + separator.length) + const db = remainder.split("?")[0] + if (!db) process.exit(1) + process.stdout.write(`${prefix}@127.0.0.1:55432/${db}`) + } + ')" + + curl -fsSL -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.18.3/cloud-sql-proxy.linux.amd64 + chmod +x cloud-sql-proxy + ./cloud-sql-proxy "$CLOUD_SQL_INSTANCE" --port 55432 >/tmp/cloud-sql-proxy.log 2>&1 & + PROXY_PID=$! + trap 'kill "$PROXY_PID"' EXIT + sleep 5 + + DATABASE_URL="$DATABASE_URL_PROXY" pnpm db:migrate + + - name: Ensure Artifact Registry repo + env: + REGION: ${{ secrets.GCP_REGION }} + REPO: ${{ secrets.GCP_ARTIFACT_REPO }} + run: | + gcloud artifacts repositories describe "$REPO" --location="$REGION" >/dev/null 2>&1 || \ + gcloud artifacts repositories create "$REPO" \ + --repository-format=docker \ + --location="$REGION" \ + --description="OpenScribe production images" + + - name: Build container images + id: image + env: + PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + REGION: ${{ secrets.GCP_REGION }} + REPO: ${{ secrets.GCP_ARTIFACT_REPO }} + NEXT_PUBLIC_SECURE_STORAGE_KEY: ${{ secrets.NEXT_PUBLIC_SECURE_STORAGE_KEY }} + run: | + WEB_IMAGE_URI="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO}/openscribe-web:${GITHUB_SHA::12}" + WHISPER_IMAGE_URI="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO}/openscribe-whisper:${GITHUB_SHA::12}" + + cat >/tmp/cloudbuild-web.yaml <<'YAML' + steps: + - name: gcr.io/cloud-builders/docker + args: + - build + - -t + - ${_WEB_IMAGE_URI} + - -f + - docker/web-cloudrun.Dockerfile + - --build-arg + - NEXT_PUBLIC_SECURE_STORAGE_KEY=${_NEXT_PUBLIC_SECURE_STORAGE_KEY} + - --build-arg + - NEXT_PUBLIC_HIPAA_HOSTED_MODE=${_NEXT_PUBLIC_HIPAA_HOSTED_MODE} + - --build-arg + - DATABASE_URL=${_DATABASE_URL_BUILD} + - . + images: + - ${_WEB_IMAGE_URI} + YAML + + gcloud builds submit \ + --config /tmp/cloudbuild-web.yaml \ + --substitutions "_WEB_IMAGE_URI=${WEB_IMAGE_URI},_NEXT_PUBLIC_SECURE_STORAGE_KEY=${NEXT_PUBLIC_SECURE_STORAGE_KEY},_NEXT_PUBLIC_HIPAA_HOSTED_MODE=true,_DATABASE_URL_BUILD=postgresql://placeholder:placeholder@127.0.0.1:5432/placeholder" \ + --async \ + --format='value(id)' > /tmp/web_build_id.txt + WEB_BUILD_ID="$(tr -d '\n' /tmp/cloudbuild-whisper.yaml <<'YAML' + steps: + - name: gcr.io/cloud-builders/docker + args: + - build + - -t + - ${_WHISPER_IMAGE_URI} + - -f + - docker/whisper-cloudrun.Dockerfile + - . + images: + - ${_WHISPER_IMAGE_URI} + YAML + + gcloud builds submit \ + --config /tmp/cloudbuild-whisper.yaml \ + --substitutions "_WHISPER_IMAGE_URI=${WHISPER_IMAGE_URI}" \ + --async \ + --format='value(id)' > /tmp/whisper_build_id.txt + WHISPER_BUILD_ID="$(tr -d '\n' > "$GITHUB_OUTPUT" + echo "whisper_image_uri=$WHISPER_IMAGE_URI" >> "$GITHUB_OUTPUT" + + - name: Deploy Whisper Cloud Run (private) + env: + REGION: ${{ secrets.GCP_REGION }} + SERVICE_NAME: ${{ secrets.GCP_WHISPER_CLOUD_RUN_SERVICE }} + RUNTIME_SA: ${{ secrets.GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT }} + IMAGE_URI: ${{ steps.image.outputs.whisper_image_uri }} + run: | + gcloud run deploy "$SERVICE_NAME" \ + --image "$IMAGE_URI" \ + --region "$REGION" \ + --platform managed \ + --port 8081 \ + --service-account "$RUNTIME_SA" \ + --ingress all \ + --execution-environment gen2 \ + --cpu 4 \ + --memory 8Gi \ + --min-instances 1 \ + --max-instances 4 \ + --set-env-vars "WHISPER_LOCAL_MODEL=tiny.en,WHISPER_LOCAL_BACKEND=cpp,WHISPER_LOCAL_GPU=1" \ + --no-allow-unauthenticated + + - name: Grant web runtime invoke access to whisper + env: + REGION: ${{ secrets.GCP_REGION }} + WHISPER_SERVICE: ${{ secrets.GCP_WHISPER_CLOUD_RUN_SERVICE }} + WEB_RUNTIME_SA: ${{ secrets.GCP_RUNTIME_SERVICE_ACCOUNT }} + run: | + gcloud run services add-iam-policy-binding "$WHISPER_SERVICE" \ + --region "$REGION" \ + --member "serviceAccount:${WEB_RUNTIME_SA}" \ + --role roles/run.invoker + + - name: Resolve whisper URL + id: whisper + env: + REGION: ${{ secrets.GCP_REGION }} + SERVICE_NAME: ${{ secrets.GCP_WHISPER_CLOUD_RUN_SERVICE }} + run: | + URL="$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --format='value(status.url)')" + echo "url=$URL" >> "$GITHUB_OUTPUT" + + - name: Deploy Web Cloud Run + env: + REGION: ${{ secrets.GCP_REGION }} + SERVICE_NAME: ${{ secrets.GCP_CLOUD_RUN_SERVICE }} + RUNTIME_SA: ${{ secrets.GCP_RUNTIME_SERVICE_ACCOUNT }} + IMAGE_URI: ${{ steps.image.outputs.web_image_uri }} + WHISPER_URL: ${{ steps.whisper.outputs.url }} + VPC_CONNECTOR: ${{ secrets.GCP_VPC_CONNECTOR }} + CLOUD_SQL_INSTANCE: ${{ secrets.GCP_CLOUD_SQL_INSTANCE }} + NEXTAUTH_URL: ${{ secrets.GCP_NEXTAUTH_URL }} + run: | + gcloud run deploy "$SERVICE_NAME" \ + --image "$IMAGE_URI" \ + --region "$REGION" \ + --platform managed \ + --port 8080 \ + --service-account "$RUNTIME_SA" \ + --ingress all \ + --execution-environment gen2 \ + --cpu 1 \ + --memory 2Gi \ + --min-instances 1 \ + --max-instances 20 \ + --vpc-connector "$VPC_CONNECTOR" \ + --vpc-egress private-ranges-only \ + --add-cloudsql-instances "$CLOUD_SQL_INSTANCE" \ + --set-env-vars "NODE_ENV=production,HIPAA_HOSTED_MODE=true,NEXT_PUBLIC_HIPAA_HOSTED_MODE=true,NEXTAUTH_URL=${NEXTAUTH_URL},TRANSCRIPTION_PROVIDER=whisper_local,WHISPER_LOCAL_URL=${WHISPER_URL}/v1/audio/transcriptions,WHISPER_LOCAL_AUTH_TYPE=identity_token" \ + --set-secrets "ANTHROPIC_API_KEY=ANTHROPIC_API_KEY:latest,AUTH_SECRET=AUTH_SECRET:latest,GOOGLE_CLIENT_ID=GOOGLE_CLIENT_ID:latest,GOOGLE_CLIENT_SECRET=GOOGLE_CLIENT_SECRET:latest,DATABASE_URL=DATABASE_URL:latest,REDIS_URL=REDIS_URL:latest" \ + --allow-unauthenticated + + - name: Print service URLs + env: + REGION: ${{ secrets.GCP_REGION }} + WEB_SERVICE: ${{ secrets.GCP_CLOUD_RUN_SERVICE }} + WHISPER_SERVICE: ${{ secrets.GCP_WHISPER_CLOUD_RUN_SERVICE }} + run: | + gcloud run services describe "$WEB_SERVICE" --region "$REGION" --format='value(status.url)' + gcloud run services describe "$WHISPER_SERVICE" --region "$REGION" --format='value(status.url)' diff --git a/.gitignore b/.gitignore index 2befe7b..0a9284c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ yarn-error.log* local-only/openscribe-backend/ollama_startup_report.json local-only/openscribe-backend/recorder_state.json local-only/openscribe-backend/config.json +local-only/openemr-rsa384-private.key diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..e0dc9b3 --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,3 @@ +ed808c5fe7c9ae3130721df4af0a156f2edbd037:GCP_DEPLOY_PLAN.md:generic-api-key:332 +ed808c5fe7c9ae3130721df4af0a156f2edbd037:GCP_DEPLOY_PLAN.md:anthropic-api-key:292 +ed808c5fe7c9ae3130721df4af0a156f2edbd037:scripts/ensure-openemr-env.sh:generic-api-key:10 diff --git a/.playwright-cli/console-2026-03-13T18-03-05-152Z.log b/.playwright-cli/console-2026-03-13T18-03-05-152Z.log new file mode 100644 index 0000000..86ded4a --- /dev/null +++ b/.playwright-cli/console-2026-03-13T18-03-05-152Z.log @@ -0,0 +1,2 @@ +[ 734ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://openscribe-web-c7tayewpaq-uc.a.run.app/api/settings/mixed-auth-status:0 +[ 1255ms] [WARNING] Microphone permission request failed NotAllowedError: Permission denied @ https://openscribe-web-c7tayewpaq-uc.a.run.app/_next/static/chunks/app/page-c3b10d1fde682ec1.js:0 diff --git a/.playwright-cli/console-2026-03-13T18-34-09-601Z.log b/.playwright-cli/console-2026-03-13T18-34-09-601Z.log new file mode 100644 index 0000000..33739b3 --- /dev/null +++ b/.playwright-cli/console-2026-03-13T18-34-09-601Z.log @@ -0,0 +1,2 @@ +[ 7298ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 17487ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 diff --git a/.playwright-cli/console-2026-03-13T18-34-47-030Z.log b/.playwright-cli/console-2026-03-13T18-34-47-030Z.log new file mode 100644 index 0000000..7ae1a9c --- /dev/null +++ b/.playwright-cli/console-2026-03-13T18-34-47-030Z.log @@ -0,0 +1,3 @@ +[ 11048ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 20782ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 40856ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 diff --git a/.playwright-cli/console-2026-03-13T18-35-38-378Z.log b/.playwright-cli/console-2026-03-13T18-35-38-378Z.log new file mode 100644 index 0000000..f413daf --- /dev/null +++ b/.playwright-cli/console-2026-03-13T18-35-38-378Z.log @@ -0,0 +1,3 @@ +[ 4487ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 17080ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 34463ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 diff --git a/.playwright-cli/console-2026-03-13T18-54-55-004Z.log b/.playwright-cli/console-2026-03-13T18-54-55-004Z.log new file mode 100644 index 0000000..de19034 --- /dev/null +++ b/.playwright-cli/console-2026-03-13T18-54-55-004Z.log @@ -0,0 +1,6 @@ +[ 11842ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 +[ 12053ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 +[ 21549ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?format=json&hasfast=true&authuser=0:0 +[ 41915ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 +[ 58498ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 +[ 62861ms] [ERROR] Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID @ https://play.google.com/log?hasfast=true&authuser=0&format=json:0 diff --git a/.playwright-cli/page-2026-03-13T18-03-05-876Z.yml b/.playwright-cli/page-2026-03-13T18-03-05-876Z.yml new file mode 100644 index 0000000..d0109df --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-03-05-876Z.yml @@ -0,0 +1,34 @@ +- generic [active] [ref=e1]: + - generic [ref=e3]: + - generic [ref=e4]: + - generic [ref=e5]: + - button "New Encounter" [ref=e7]: + - img + - text: New Encounter + - generic [ref=e8]: + - heading "Encounters" [level=2] [ref=e9] + - generic [ref=e10]: + - img [ref=e11] + - textbox "Search..." [ref=e14] + - generic [ref=e18]: + - img [ref=e19] + - paragraph [ref=e22]: No encounters yet + - generic [ref=e23]: + - paragraph [ref=e24]: Models + - generic [ref=e25]: + - generic [ref=e26]: + - img [ref=e27] + - generic [ref=e30]: Whisper (Local) + - generic [ref=e31]: + - img [ref=e32] + - generic [ref=e34]: Claude (Cloud) + - button "Settings" [ref=e36]: + - img + - generic [ref=e37]: Settings + - main [ref=e38]: + - generic [ref=e39]: + - button [ref=e40]: + - img [ref=e41] + - heading "Start a new interview" [level=2] [ref=e44] + - paragraph [ref=e45]: Record, transcribe, and generate clinical notes automatically. + - alert [ref=e46] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-03-08-201Z.yml b/.playwright-cli/page-2026-03-13T18-03-08-201Z.yml new file mode 100644 index 0000000..71e91ae --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-03-08-201Z.yml @@ -0,0 +1,41 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - generic [ref=e48]: + - heading "Anthropic Key Required for Mixed Mode" [level=3] [ref=e49] + - paragraph [ref=e50]: Mixed mode uses Claude for note generation. Add your Anthropic key in Settings, or switch to local-only mode. + - generic [ref=e51]: + - button "Add Key in Settings" [ref=e52] + - button "Switch to Local-only" [disabled] [ref=e53] + - generic [ref=e3]: + - generic [ref=e4]: + - generic [ref=e5]: + - button "New Encounter" [ref=e7]: + - img + - text: New Encounter + - generic [ref=e8]: + - heading "Encounters" [level=2] [ref=e9] + - generic [ref=e10]: + - img [ref=e11] + - textbox "Search..." [ref=e14] + - generic [ref=e18]: + - img [ref=e19] + - paragraph [ref=e22]: No encounters yet + - generic [ref=e23]: + - paragraph [ref=e24]: Models + - generic [ref=e25]: + - generic [ref=e26]: + - img [ref=e27] + - generic [ref=e30]: Whisper (Local) + - generic [ref=e31]: + - img [ref=e32] + - generic [ref=e34]: Claude (Cloud) + - button "Settings" [ref=e36]: + - img + - generic [ref=e37]: Settings + - main [ref=e38]: + - generic [ref=e39]: + - button [ref=e40]: + - img [ref=e41] + - heading "Start a new interview" [level=2] [ref=e44] + - paragraph [ref=e45]: Record, transcribe, and generate clinical notes automatically. + - alert [ref=e46] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-31-09-178Z.yml b/.playwright-cli/page-2026-03-13T18-31-09-178Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-31-09-178Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-31-11-063Z.yml b/.playwright-cli/page-2026-03-13T18-31-11-063Z.yml new file mode 100644 index 0000000..54ccb24 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-31-11-063Z.yml @@ -0,0 +1,6 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - heading "OpenScribe HIPAA Hosted" [level=1] [ref=e4] + - paragraph [ref=e5]: Sign in with Google to access the hosted clinical workflow. + - button "Sign in with Google" [ref=e6] + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-31-26-911Z.yml b/.playwright-cli/page-2026-03-13T18-31-26-911Z.yml new file mode 100644 index 0000000..f511d9f --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-31-26-911Z.yml @@ -0,0 +1,119 @@ +- generic [ref=e3]: + - generic [ref=e5]: + - generic [ref=e8]: + - img "Google" [ref=e10] + - generic [ref=e11]: Sign in with Google + - generic [ref=e12]: + - generic [ref=e14]: + - heading "Sign in" [level=1] [ref=e15] + - paragraph [ref=e16]: + - text: to continue to + - button "OpenScribe" [ref=e17] [cursor=pointer] + - generic [ref=e18]: + - generic [ref=e21]: + - generic [ref=e26]: + - textbox "Email or phone" [active] [ref=e27] + - generic: + - generic: Email or phone + - paragraph [ref=e28]: + - link "Forgot email?" [ref=e29] [cursor=pointer]: + - /url: /signin/v2/usernamerecovery?app_domain=http://localhost:3000&client_id=171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com&code_challenge=5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y&code_challenge_method=S256&continue=https://accounts.google.com/signin/oauth/legacy/consent?authuser%3Dunknown%26part%3DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%26flowName%3DGeneralOAuthFlow%26as%3DS506639371%253A1773426685753151%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%23&dsh=S506639371:1773426685753151&flowName=GeneralOAuthLite&o2v=2&opparams=%253F&rart=ANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk&redirect_uri=http://localhost:3000/api/auth/callback/google&response_type=code&scope=openid+email+profile&service=lso&state=R9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg + - generic [ref=e31]: + - button "Next" [ref=e33] + - link "Create account" [ref=e35] [cursor=pointer]: + - /url: /lifecycle/flows/signup?app_domain=http://localhost:3000&client_id=171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com&code_challenge=5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y&code_challenge_method=S256&continue=https://accounts.google.com/signin/oauth/legacy/consent?authuser%3Dunknown%26part%3DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%26flowName%3DGeneralOAuthFlow%26as%3DS506639371%253A1773426685753151%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%23&dsh=S506639371:1773426685753151&flowEntry=SignUp&flowName=GlifWebSignIn&o2v=2&opparams=%253F&rart=ANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk&redirect_uri=http://localhost:3000/api/auth/callback/google&response_type=code&scope=openid+email+profile&service=lso&signInUrl=https://accounts.google.com/signin/oauth?app_domain%3Dhttp://localhost:3000%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%26code_challenge%3D5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y%26code_challenge_method%3DS256%26continue%3Dhttps://accounts.google.com/signin/oauth/legacy/consent?authuser%253Dunknown%2526part%253DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%2526flowName%253DGeneralOAuthFlow%2526as%253DS506639371%25253A1773426685753151%2526client_id%253D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%2523%26dsh%3DS506639371:1773426685753151%26flowName%3DGeneralOAuthLite%26o2v%3D2%26opparams%3D%25253F%26rart%3DANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk%26redirect_uri%3Dhttp://localhost:3000/api/auth/callback/google%26response_type%3Dcode%26scope%3Dopenid%2Bemail%2Bprofile%26service%3Dlso%26state%3DR9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg&state=R9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg + - contentinfo [ref=e36]: + - combobox [ref=e39] [cursor=pointer]: + - option "Afrikaans" + - option "azərbaycan" + - option "bosanski" + - option "català" + - option "Čeština" + - option "Cymraeg" + - option "Dansk" + - option "Deutsch" + - option "eesti" + - option "English (United Kingdom)" + - option "English (United States)" [selected] + - option "Español (España)" + - option "Español (Latinoamérica)" + - option "euskara" + - option "Filipino" + - option "Français (Canada)" + - option "Français (France)" + - option "Gaeilge" + - option "galego" + - option "Hrvatski" + - option "Indonesia" + - option "isiZulu" + - option "íslenska" + - option "Italiano" + - option "Kiswahili" + - option "latviešu" + - option "lietuvių" + - option "magyar" + - option "Melayu" + - option "Nederlands" + - option "norsk" + - option "o‘zbek" + - option "polski" + - option "Português (Brasil)" + - option "Português (Portugal)" + - option "română" + - option "shqip" + - option "Slovenčina" + - option "slovenščina" + - option "srpski (latinica)" + - option "Suomi" + - option "Svenska" + - option "Tiếng Việt" + - option "Türkçe" + - option "Ελληνικά" + - option "беларуская" + - option "български" + - option "кыргызча" + - option "қазақ тілі" + - option "македонски" + - option "монгол" + - option "Русский" + - option "српски (ћирилица)" + - option "Українська" + - option "ქართული" + - option "հայերեն" + - option "‫עברית‬‎" + - option "‫اردو‬‎" + - option "‫العربية‬‎" + - option "‫فارسی‬‎" + - option "አማርኛ" + - option "नेपाली" + - option "मराठी" + - option "हिन्दी" + - option "অসমীয়া" + - option "বাংলা" + - option "ਪੰਜਾਬੀ" + - option "ગુજરાતી" + - option "ଓଡ଼ିଆ" + - option "தமிழ்" + - option "తెలుగు" + - option "ಕನ್ನಡ" + - option "മലയാളം" + - option "සිංහල" + - option "ไทย" + - option "ລາວ" + - option "မြန်မာ" + - option "ខ្មែរ" + - option "한국어" + - option "中文(香港)" + - option "日本語" + - option "简体中文" + - option "繁體中文" + - list [ref=e40]: + - listitem [ref=e41]: + - link "Help" [ref=e42] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e43]: + - link "Privacy" [ref=e44] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e45]: + - link "Terms" [ref=e46] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-31-28-356Z.yml b/.playwright-cli/page-2026-03-13T18-31-28-356Z.yml new file mode 100644 index 0000000..f511d9f --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-31-28-356Z.yml @@ -0,0 +1,119 @@ +- generic [ref=e3]: + - generic [ref=e5]: + - generic [ref=e8]: + - img "Google" [ref=e10] + - generic [ref=e11]: Sign in with Google + - generic [ref=e12]: + - generic [ref=e14]: + - heading "Sign in" [level=1] [ref=e15] + - paragraph [ref=e16]: + - text: to continue to + - button "OpenScribe" [ref=e17] [cursor=pointer] + - generic [ref=e18]: + - generic [ref=e21]: + - generic [ref=e26]: + - textbox "Email or phone" [active] [ref=e27] + - generic: + - generic: Email or phone + - paragraph [ref=e28]: + - link "Forgot email?" [ref=e29] [cursor=pointer]: + - /url: /signin/v2/usernamerecovery?app_domain=http://localhost:3000&client_id=171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com&code_challenge=5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y&code_challenge_method=S256&continue=https://accounts.google.com/signin/oauth/legacy/consent?authuser%3Dunknown%26part%3DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%26flowName%3DGeneralOAuthFlow%26as%3DS506639371%253A1773426685753151%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%23&dsh=S506639371:1773426685753151&flowName=GeneralOAuthLite&o2v=2&opparams=%253F&rart=ANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk&redirect_uri=http://localhost:3000/api/auth/callback/google&response_type=code&scope=openid+email+profile&service=lso&state=R9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg + - generic [ref=e31]: + - button "Next" [ref=e33] + - link "Create account" [ref=e35] [cursor=pointer]: + - /url: /lifecycle/flows/signup?app_domain=http://localhost:3000&client_id=171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com&code_challenge=5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y&code_challenge_method=S256&continue=https://accounts.google.com/signin/oauth/legacy/consent?authuser%3Dunknown%26part%3DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%26flowName%3DGeneralOAuthFlow%26as%3DS506639371%253A1773426685753151%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%23&dsh=S506639371:1773426685753151&flowEntry=SignUp&flowName=GlifWebSignIn&o2v=2&opparams=%253F&rart=ANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk&redirect_uri=http://localhost:3000/api/auth/callback/google&response_type=code&scope=openid+email+profile&service=lso&signInUrl=https://accounts.google.com/signin/oauth?app_domain%3Dhttp://localhost:3000%26client_id%3D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%26code_challenge%3D5fnkHbZiWV4Sf4_uOA1tqcQuEztep46MlqxaxGi6y-Y%26code_challenge_method%3DS256%26continue%3Dhttps://accounts.google.com/signin/oauth/legacy/consent?authuser%253Dunknown%2526part%253DAJi8hAOcSqXxv2-zPMHN3IC_XJLFm-KF6_rnxjTKRV3C3SU5FgmSsHFOYk685zZtVNwQncGjicIIWewF7sI1vu9fTw0zTTH4iAMH_azWQFJfDuqCeRvCvVPdR_FD_9xXibM8za_3gMhSIidKaJ9ZZD4aBtoUiTw0cabYHxd5p5Gkb40j3YEwxjAFywCEcQ3ncGCyrFBFOzZpnFVb3xVV6jl3vijiK4-DtEwmKqgFX6rDUbSH3e6FNTeAR725Bg9V3FtQsbF9PD9ftV0dFEou4zo87o5deJTQ4lz56cnLNBwSNzDnoELcApuRl4HLbV4CqAPO2ORCS34rupjImPwJXNb9jcd31iUep11DsOPpSyt4MhKnfuyDfcxtGfp4LviM5HgLrdVmAdnQy_qhhNoEUPs_PdFf1s0dg_wcm6mCcDd4nQglPtXK4liiOHJMrRXDg4vhaZXuNR8iNpEfiKr8r0CWHN6tEq7T7g%2526flowName%253DGeneralOAuthFlow%2526as%253DS506639371%25253A1773426685753151%2526client_id%253D171545239450-72l0e9vfkqoaoni19jrjpvmt30hgp1fr.apps.googleusercontent.com%2523%26dsh%3DS506639371:1773426685753151%26flowName%3DGeneralOAuthLite%26o2v%3D2%26opparams%3D%25253F%26rart%3DANgoxcf-_D4Kq_UMVstmrH5axlmTHtcl3-1mchAeld0bL2f_gO8pGaD75rowRW-Zak1NWE4iXOYsseDHhnrkIChsa2Vy1EozXhm0T9CM5D3kl2b7xhllzYk%26redirect_uri%3Dhttp://localhost:3000/api/auth/callback/google%26response_type%3Dcode%26scope%3Dopenid%2Bemail%2Bprofile%26service%3Dlso%26state%3DR9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg&state=R9hn96QW52_6xzrlQI13CagJJsyuWcnSxb6P2GxUBCg + - contentinfo [ref=e36]: + - combobox [ref=e39] [cursor=pointer]: + - option "Afrikaans" + - option "azərbaycan" + - option "bosanski" + - option "català" + - option "Čeština" + - option "Cymraeg" + - option "Dansk" + - option "Deutsch" + - option "eesti" + - option "English (United Kingdom)" + - option "English (United States)" [selected] + - option "Español (España)" + - option "Español (Latinoamérica)" + - option "euskara" + - option "Filipino" + - option "Français (Canada)" + - option "Français (France)" + - option "Gaeilge" + - option "galego" + - option "Hrvatski" + - option "Indonesia" + - option "isiZulu" + - option "íslenska" + - option "Italiano" + - option "Kiswahili" + - option "latviešu" + - option "lietuvių" + - option "magyar" + - option "Melayu" + - option "Nederlands" + - option "norsk" + - option "o‘zbek" + - option "polski" + - option "Português (Brasil)" + - option "Português (Portugal)" + - option "română" + - option "shqip" + - option "Slovenčina" + - option "slovenščina" + - option "srpski (latinica)" + - option "Suomi" + - option "Svenska" + - option "Tiếng Việt" + - option "Türkçe" + - option "Ελληνικά" + - option "беларуская" + - option "български" + - option "кыргызча" + - option "қазақ тілі" + - option "македонски" + - option "монгол" + - option "Русский" + - option "српски (ћирилица)" + - option "Українська" + - option "ქართული" + - option "հայերեն" + - option "‫עברית‬‎" + - option "‫اردو‬‎" + - option "‫العربية‬‎" + - option "‫فارسی‬‎" + - option "አማርኛ" + - option "नेपाली" + - option "मराठी" + - option "हिन्दी" + - option "অসমীয়া" + - option "বাংলা" + - option "ਪੰਜਾਬੀ" + - option "ગુજરાતી" + - option "ଓଡ଼ିଆ" + - option "தமிழ்" + - option "తెలుగు" + - option "ಕನ್ನಡ" + - option "മലയാളം" + - option "සිංහල" + - option "ไทย" + - option "ລາວ" + - option "မြန်မာ" + - option "ខ្មែរ" + - option "한국어" + - option "中文(香港)" + - option "日本語" + - option "简体中文" + - option "繁體中文" + - list [ref=e40]: + - listitem [ref=e41]: + - link "Help" [ref=e42] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e43]: + - link "Privacy" [ref=e44] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e45]: + - link "Terms" [ref=e46] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-32-17-628Z.yml b/.playwright-cli/page-2026-03-13T18-32-17-628Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-32-17-628Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-32-19-492Z.yml b/.playwright-cli/page-2026-03-13T18-32-19-492Z.yml new file mode 100644 index 0000000..54ccb24 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-32-19-492Z.yml @@ -0,0 +1,6 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - heading "OpenScribe HIPAA Hosted" [level=1] [ref=e4] + - paragraph [ref=e5]: Sign in with Google to access the hosted clinical workflow. + - button "Sign in with Google" [ref=e6] + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-32-22-851Z.yml b/.playwright-cli/page-2026-03-13T18-32-22-851Z.yml new file mode 100644 index 0000000..bc192d4 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-32-22-851Z.yml @@ -0,0 +1,112 @@ +- generic [ref=e3]: + - generic [ref=e5]: + - generic [ref=e7]: + - img "Google" [ref=e9] + - generic [ref=e10]: Sign in with Google + - generic [ref=e11]: + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e14]' + - generic [ref=e18]: + - paragraph [ref=e19]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e20] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - paragraph [ref=e21]: + - text: If you are a developer of this app, see + - button "error details" [ref=e22] [cursor=pointer] + - text: . + - paragraph [ref=e23]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e24]: + - combobox [ref=e27] [cursor=pointer]: + - option "Afrikaans" + - option "azərbaycan" + - option "bosanski" + - option "català" + - option "Čeština" + - option "Cymraeg" + - option "Dansk" + - option "Deutsch" + - option "eesti" + - option "English (United Kingdom)" + - option "English (United States)" [selected] + - option "Español (España)" + - option "Español (Latinoamérica)" + - option "euskara" + - option "Filipino" + - option "Français (Canada)" + - option "Français (France)" + - option "Gaeilge" + - option "galego" + - option "Hrvatski" + - option "Indonesia" + - option "isiZulu" + - option "íslenska" + - option "Italiano" + - option "Kiswahili" + - option "latviešu" + - option "lietuvių" + - option "magyar" + - option "Melayu" + - option "Nederlands" + - option "norsk" + - option "o‘zbek" + - option "polski" + - option "Português (Brasil)" + - option "Português (Portugal)" + - option "română" + - option "shqip" + - option "Slovenčina" + - option "slovenščina" + - option "srpski (latinica)" + - option "Suomi" + - option "Svenska" + - option "Tiếng Việt" + - option "Türkçe" + - option "Ελληνικά" + - option "беларуская" + - option "български" + - option "кыргызча" + - option "қазақ тілі" + - option "македонски" + - option "монгол" + - option "Русский" + - option "српски (ћирилица)" + - option "Українська" + - option "ქართული" + - option "հայերեն" + - option "‫עברית‬‎" + - option "‫اردو‬‎" + - option "‫العربية‬‎" + - option "‫فارسی‬‎" + - option "አማርኛ" + - option "नेपाली" + - option "मराठी" + - option "हिन्दी" + - option "অসমীয়া" + - option "বাংলা" + - option "ਪੰਜਾਬੀ" + - option "ગુજરાતી" + - option "ଓଡ଼ିଆ" + - option "தமிழ்" + - option "తెలుగు" + - option "ಕನ್ನಡ" + - option "മലയാളം" + - option "සිංහල" + - option "ไทย" + - option "ລາວ" + - option "မြန်မာ" + - option "ខ្មែរ" + - option "한국어" + - option "中文(香港)" + - option "日本語" + - option "简体中文" + - option "繁體中文" + - list [ref=e28]: + - listitem [ref=e29]: + - link "Help" [ref=e30] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e31]: + - link "Privacy" [ref=e32] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e33]: + - link "Terms" [ref=e34] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-34-10-095Z.yml b/.playwright-cli/page-2026-03-13T18-34-10-095Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-34-10-095Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-34-17-384Z.yml b/.playwright-cli/page-2026-03-13T18-34-17-384Z.yml new file mode 100644 index 0000000..6bed247 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-34-17-384Z.yml @@ -0,0 +1,35 @@ +- generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e17]: + - img [ref=e19] + - generic [ref=e24]: Sign in with Google + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e26]' + - generic [ref=e34]: + - generic [ref=e35]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e36] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - generic [ref=e37]: + - text: If you are a developer of this app, see + - button "error details" [ref=e38] [cursor=pointer] + - text: . + - generic [ref=e39]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e44]: + - combobox "Change language English (United States)" [ref=e48] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e50]: + - listitem [ref=e51]: + - link "Help" [ref=e52] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e53]: + - link "Privacy" [ref=e54] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e55]: + - link "Terms" [ref=e56] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-34-41-633Z.png b/.playwright-cli/page-2026-03-13T18-34-41-633Z.png new file mode 100644 index 0000000..4922cd4 Binary files /dev/null and b/.playwright-cli/page-2026-03-13T18-34-41-633Z.png differ diff --git a/.playwright-cli/page-2026-03-13T18-34-47-184Z.yml b/.playwright-cli/page-2026-03-13T18-34-47-184Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-34-47-184Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-34-49-602Z.yml b/.playwright-cli/page-2026-03-13T18-34-49-602Z.yml new file mode 100644 index 0000000..54ccb24 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-34-49-602Z.yml @@ -0,0 +1,6 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - heading "OpenScribe HIPAA Hosted" [level=1] [ref=e4] + - paragraph [ref=e5]: Sign in with Google to access the hosted clinical workflow. + - button "Sign in with Google" [ref=e6] + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-34-58-586Z.yml b/.playwright-cli/page-2026-03-13T18-34-58-586Z.yml new file mode 100644 index 0000000..6bed247 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-34-58-586Z.yml @@ -0,0 +1,35 @@ +- generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e17]: + - img [ref=e19] + - generic [ref=e24]: Sign in with Google + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e26]' + - generic [ref=e34]: + - generic [ref=e35]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e36] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - generic [ref=e37]: + - text: If you are a developer of this app, see + - button "error details" [ref=e38] [cursor=pointer] + - text: . + - generic [ref=e39]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e44]: + - combobox "Change language English (United States)" [ref=e48] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e50]: + - listitem [ref=e51]: + - link "Help" [ref=e52] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e53]: + - link "Privacy" [ref=e54] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e55]: + - link "Terms" [ref=e56] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-35-00-044Z.yml b/.playwright-cli/page-2026-03-13T18-35-00-044Z.yml new file mode 100644 index 0000000..6bed247 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-35-00-044Z.yml @@ -0,0 +1,35 @@ +- generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e17]: + - img [ref=e19] + - generic [ref=e24]: Sign in with Google + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e26]' + - generic [ref=e34]: + - generic [ref=e35]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e36] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - generic [ref=e37]: + - text: If you are a developer of this app, see + - button "error details" [ref=e38] [cursor=pointer] + - text: . + - generic [ref=e39]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e44]: + - combobox "Change language English (United States)" [ref=e48] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e50]: + - listitem [ref=e51]: + - link "Help" [ref=e52] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e53]: + - link "Privacy" [ref=e54] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e55]: + - link "Terms" [ref=e56] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-35-38-950Z.yml b/.playwright-cli/page-2026-03-13T18-35-38-950Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-35-38-950Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-35-40-533Z.yml b/.playwright-cli/page-2026-03-13T18-35-40-533Z.yml new file mode 100644 index 0000000..54ccb24 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-35-40-533Z.yml @@ -0,0 +1,6 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - heading "OpenScribe HIPAA Hosted" [level=1] [ref=e4] + - paragraph [ref=e5]: Sign in with Google to access the hosted clinical workflow. + - button "Sign in with Google" [ref=e6] + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-35-43-653Z.yml b/.playwright-cli/page-2026-03-13T18-35-43-653Z.yml new file mode 100644 index 0000000..6bed247 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-35-43-653Z.yml @@ -0,0 +1,35 @@ +- generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e17]: + - img [ref=e19] + - generic [ref=e24]: Sign in with Google + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e26]' + - generic [ref=e34]: + - generic [ref=e35]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e36] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - generic [ref=e37]: + - text: If you are a developer of this app, see + - button "error details" [ref=e38] [cursor=pointer] + - text: . + - generic [ref=e39]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e44]: + - combobox "Change language English (United States)" [ref=e48] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e50]: + - listitem [ref=e51]: + - link "Help" [ref=e52] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e53]: + - link "Privacy" [ref=e54] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e55]: + - link "Terms" [ref=e56] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-35-45-153Z.yml b/.playwright-cli/page-2026-03-13T18-35-45-153Z.yml new file mode 100644 index 0000000..6bed247 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-35-45-153Z.yml @@ -0,0 +1,35 @@ +- generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e17]: + - img [ref=e19] + - generic [ref=e24]: Sign in with Google + - 'heading "Access blocked: This app’s request is invalid" [level=1] [ref=e26]' + - generic [ref=e34]: + - generic [ref=e35]: + - text: You can’t sign in because this app sent an invalid request. You can try again later, or contact the developer about this issue. + - link "Learn more about this error" [ref=e36] [cursor=pointer]: + - /url: https://developers.google.com/identity/protocols/oauth2/web-server#authorization-errors-redirect-uri-mismatch + - generic [ref=e37]: + - text: If you are a developer of this app, see + - button "error details" [ref=e38] [cursor=pointer] + - text: . + - generic [ref=e39]: "Error 400: redirect_uri_mismatch" + - contentinfo [ref=e44]: + - combobox "Change language English (United States)" [ref=e48] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e50]: + - listitem [ref=e51]: + - link "Help" [ref=e52] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e53]: + - link "Privacy" [ref=e54] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e55]: + - link "Terms" [ref=e56] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-54-55-669Z.yml b/.playwright-cli/page-2026-03-13T18-54-55-669Z.yml new file mode 100644 index 0000000..0f28185 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-54-55-669Z.yml @@ -0,0 +1,3 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: Loading session... + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-54-57-148Z.yml b/.playwright-cli/page-2026-03-13T18-54-57-148Z.yml new file mode 100644 index 0000000..54ccb24 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-54-57-148Z.yml @@ -0,0 +1,6 @@ +- generic [active] [ref=e1]: + - generic [ref=e2]: + - heading "OpenScribe HIPAA Hosted" [level=1] [ref=e4] + - paragraph [ref=e5]: Sign in with Google to access the hosted clinical workflow. + - button "Sign in with Google" [ref=e6] + - alert [ref=e3] \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-55-07-315Z.yml b/.playwright-cli/page-2026-03-13T18-55-07-315Z.yml new file mode 100644 index 0000000..c20a6d5 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-55-07-315Z.yml @@ -0,0 +1,42 @@ +- generic [ref=e1]: + - generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e18]: + - img [ref=e20] + - generic [ref=e25]: Sign in with Google + - generic [ref=e26]: + - heading "Sign in" [level=1] [ref=e27] + - generic [ref=e29]: + - text: to continue to + - button "openscribe-web-c7tayewpaq-uc.a.run.app" [ref=e30] [cursor=pointer] + - generic [ref=e38]: + - generic [ref=e43]: + - textbox "Email or phone" [active] [ref=e44] + - generic: Email or phone + - button "Forgot email?" [ref=e48] [cursor=pointer] + - generic [ref=e50]: + - button "Next" [ref=e54]: + - generic [ref=e57]: Next + - button "Create account" [ref=e62]: + - generic [ref=e65]: Create account + - contentinfo [ref=e69]: + - combobox "Change language English (United States)" [ref=e73] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e75]: + - listitem [ref=e76]: + - link "Help" [ref=e77] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e78]: + - link "Privacy" [ref=e79] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e80]: + - link "Terms" [ref=e81] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US + - iframe [ref=e82]: + \ No newline at end of file diff --git a/.playwright-cli/page-2026-03-13T18-55-08-821Z.yml b/.playwright-cli/page-2026-03-13T18-55-08-821Z.yml new file mode 100644 index 0000000..c20a6d5 --- /dev/null +++ b/.playwright-cli/page-2026-03-13T18-55-08-821Z.yml @@ -0,0 +1,42 @@ +- generic [ref=e1]: + - generic [ref=e3]: + - generic [ref=e4]: + - progressbar [ref=e6] + - main [ref=e14]: + - generic [ref=e15]: + - generic [ref=e18]: + - img [ref=e20] + - generic [ref=e25]: Sign in with Google + - generic [ref=e26]: + - heading "Sign in" [level=1] [ref=e27] + - generic [ref=e29]: + - text: to continue to + - button "openscribe-web-c7tayewpaq-uc.a.run.app" [ref=e30] [cursor=pointer] + - generic [ref=e38]: + - generic [ref=e43]: + - textbox "Email or phone" [active] [ref=e44] + - generic: Email or phone + - button "Forgot email?" [ref=e48] [cursor=pointer] + - generic [ref=e50]: + - button "Next" [ref=e54]: + - generic [ref=e57]: Next + - button "Create account" [ref=e62]: + - generic [ref=e65]: Create account + - contentinfo [ref=e69]: + - combobox "Change language English (United States)" [ref=e73] [cursor=pointer]: + - generic: + - generic: English (United States) + - generic: + - img + - list [ref=e75]: + - listitem [ref=e76]: + - link "Help" [ref=e77] [cursor=pointer]: + - /url: https://support.google.com/accounts?hl=en-US&p=account_iph + - listitem [ref=e78]: + - link "Privacy" [ref=e79] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US&privacy=true + - listitem [ref=e80]: + - link "Terms" [ref=e81] [cursor=pointer]: + - /url: https://accounts.google.com/TOS?loc=US&hl=en-US + - iframe [ref=e82]: + \ No newline at end of file diff --git a/README.md b/README.md index 6f546ed..9234b16 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ OpenScribe is a free MIT license open source AI Medical Scribe that helps clinic - [Contributing](./CONTRIBUTING.md) - [Download and Use Desktop](./docs/DOWNLOAD_AND_USE.md) - [Desktop Release Runbook](./docs/RELEASE_RUNBOOK.md) +- [HIPAA GCP Web Hosting](./docs/HIPAA_GCP_WEB_HOSTING.md) +- [HIPAA Evidence Index](./docs/HIPAA_EVIDENCE_INDEX.md) The current project is not yet HIPAA compliant; however, we recently signed up with Delve and will be HIPAA compliant in the next few weeks. diff --git a/apps/web/.env.local.example b/apps/web/.env.local.example index 0e40079..7b5392a 100644 --- a/apps/web/.env.local.example +++ b/apps/web/.env.local.example @@ -34,3 +34,48 @@ ANTHROPIC_API_KEY="sk-ant-your-key" # Base64-encoded 32-byte secret used for client-side secure storage. # Generate with: openssl rand -base64 32 NEXT_PUBLIC_SECURE_STORAGE_KEY="base64-secret" + +# HIPAA hosted mode (Cloud Run production) +HIPAA_HOSTED_MODE="false" +NEXT_PUBLIC_HIPAA_HOSTED_MODE="false" + +# Google OAuth (required when HIPAA_HOSTED_MODE=true) +GOOGLE_CLIENT_ID="" +GOOGLE_CLIENT_SECRET="" +AUTH_SECRET="" + +# Postgres for auth/compliance metadata (required when HIPAA_HOSTED_MODE=true) +DATABASE_URL="" +REDIS_URL="" + +# Whisper auth mode for internal Cloud Run service-to-service invocation +WHISPER_LOCAL_AUTH_TYPE="" + +# OpenEMR integration (optional — omit to disable) +# Auth uses RS384 JWT client assertion (RFC 7521 / SMART Backend Services). +# No client_secret — identity is proved by the signed JWT. +# +# Setup: +# 1. Admin → System → API Clients → create client, scope: api:oemr +# 2. Generate an RSA key pair: +# openssl genrsa -out openemr-private.pem 2048 +# openssl rsa -in openemr-private.pem -pubout -out openemr-public.pem +# 3. Register the public key with the OAuth2 client in OpenEMR. +# 4. Set the vars below. +# +OPENEMR_BASE_URL="http://localhost:8080" +OPENEMR_CLIENT_ID="" + +# Inline PEM (use \n for newlines) or an absolute file path to the private key. +# Example inline: "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----" +# Example path: "/run/secrets/openemr-private.pem" +OPENEMR_JWT_PRIVATE_KEY_PEM="/path/to/openemr-private.pem" + +# Optional: override the token endpoint (defaults to {OPENEMR_BASE_URL}/oauth2/default/token) +# OPENEMR_TOKEN_URL="http://localhost:8080/oauth2/default/token" + +# Build-time flag — enables the "Push to OpenEMR" button in the note editor. +# Must be set explicitly alongside the server vars above. +# NEXT_PUBLIC_* vars are inlined at build time by Next.js; they cannot be +# derived at runtime from server-only vars in Cloud Run / Docker deployments. +NEXT_PUBLIC_OPENEMR_ENABLED="false" diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/apps/web/next-env.d.ts +++ b/apps/web/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/web/src/app/actions.ts b/apps/web/src/app/actions.ts index 23e478a..ac57d07 100644 --- a/apps/web/src/app/actions.ts +++ b/apps/web/src/app/actions.ts @@ -4,8 +4,24 @@ import type { ClinicalNoteRequest } from "@note-core" import { createClinicalNoteText } from "@note-core" import { getAnthropicApiKey } from "@storage/server-api-keys" import { writeAuditEntry } from "@storage/audit-log" +import { getServerSession } from "next-auth" +import { hasAcceptedTerms } from "@/lib/compliance" export async function generateClinicalNote(params: ClinicalNoteRequest): Promise { + let userId = "local-user" + if (process.env.HIPAA_HOSTED_MODE === "true") { + const { authOptions } = await import("@/lib/auth") + const session = await getServerSession(authOptions) + userId = session?.user?.id || "" + if (!userId) { + throw new Error("Unauthorized") + } + const accepted = await hasAcceptedTerms(userId) + if (!accepted) { + throw new Error("Terms acceptance required") + } + } + const apiKey = getAnthropicApiKey() try { @@ -13,6 +29,7 @@ export async function generateClinicalNote(params: ClinicalNoteRequest): Promise await writeAuditEntry({ event_type: "note.generation_started", success: true, + user_id: userId, metadata: { template: params.template || "default", transcript_length: params.transcript?.length || 0, @@ -25,6 +42,7 @@ export async function generateClinicalNote(params: ClinicalNoteRequest): Promise await writeAuditEntry({ event_type: "note.generated", success: true, + user_id: userId, metadata: { template: params.template || "default", note_length: result.length, @@ -37,6 +55,7 @@ export async function generateClinicalNote(params: ClinicalNoteRequest): Promise await writeAuditEntry({ event_type: "note.generation_failed", success: false, + user_id: userId, error_message: error instanceof Error ? error.message : String(error), metadata: { template: params.template || "default", diff --git a/apps/web/src/app/api/auth/[...nextauth]/route.ts b/apps/web/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..236a422 --- /dev/null +++ b/apps/web/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,3 @@ +import authHandler from "@/lib/auth" + +export { authHandler as GET, authHandler as POST } diff --git a/apps/web/src/app/api/compliance/session/route.ts b/apps/web/src/app/api/compliance/session/route.ts new file mode 100644 index 0000000..5e77f1e --- /dev/null +++ b/apps/web/src/app/api/compliance/session/route.ts @@ -0,0 +1,26 @@ +import type { NextRequest } from "next/server" +import { NextResponse } from "next/server" +import { requireAuthenticatedUser } from "@/lib/auth-guard" +import { writeAuthEvent } from "@/lib/compliance" + +export async function GET(req: NextRequest) { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + + await writeAuthEvent({ + userId: auth.userId, + eventType: "session_checked", + provider: "google", + success: true, + req, + }) + + return NextResponse.json({ + authenticated: true, + user: { + id: auth.userId, + email: auth.session.user?.email || null, + name: auth.session.user?.name || null, + }, + }) +} diff --git a/apps/web/src/app/api/compliance/terms/route.ts b/apps/web/src/app/api/compliance/terms/route.ts new file mode 100644 index 0000000..1d7c331 --- /dev/null +++ b/apps/web/src/app/api/compliance/terms/route.ts @@ -0,0 +1,20 @@ +import type { NextRequest } from "next/server" +import { NextResponse } from "next/server" +import { acceptTerms, hasAcceptedTerms, TERMS_VERSION } from "@/lib/compliance" +import { requireAuthenticatedUser } from "@/lib/auth-guard" + +export async function GET() { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + + const accepted = await hasAcceptedTerms(auth.userId) + return NextResponse.json({ accepted, termsVersion: TERMS_VERSION }) +} + +export async function POST(req: NextRequest) { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + + await acceptTerms(auth.userId, req) + return NextResponse.json({ accepted: true, termsVersion: TERMS_VERSION }) +} diff --git a/apps/web/src/app/api/integrations/openemr/auth/setup/route.ts b/apps/web/src/app/api/integrations/openemr/auth/setup/route.ts new file mode 100644 index 0000000..773051b --- /dev/null +++ b/apps/web/src/app/api/integrations/openemr/auth/setup/route.ts @@ -0,0 +1,11 @@ +import { NextResponse } from "next/server" +import { requireAuthenticatedUser } from "@/lib/auth-guard" +import { setupOpenEMRAuth } from "@/lib/openemr-client" + +export async function POST() { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + + const result = await setupOpenEMRAuth() + return NextResponse.json(result, { status: result.success ? 200 : 400 }) +} diff --git a/apps/web/src/app/api/integrations/openemr/push/route.ts b/apps/web/src/app/api/integrations/openemr/push/route.ts new file mode 100644 index 0000000..d720bb7 --- /dev/null +++ b/apps/web/src/app/api/integrations/openemr/push/route.ts @@ -0,0 +1,28 @@ +import { NextRequest, NextResponse } from "next/server" +import { requireAuthenticatedUser } from "@/lib/auth-guard" +import { handlePushRequest } from "@/lib/openemr-push-handler" +import { pushNoteToOpenEMR } from "@/lib/openemr-client" + +export async function POST(req: NextRequest) { + const auth = await requireAuthenticatedUser() + + let body: unknown + try { + body = await req.json() + } catch { + body = null + } + + const result = await handlePushRequest( + { isAuthenticated: auth.ok }, + body, + pushNoteToOpenEMR + ) + + // When unauthenticated, defer to the auth guard's response (may include redirect headers) + if (!auth.ok && result.status === 401) { + return auth.response + } + + return NextResponse.json(result.json, { status: result.status }) +} diff --git a/apps/web/src/app/api/integrations/openemr/status/route.ts b/apps/web/src/app/api/integrations/openemr/status/route.ts new file mode 100644 index 0000000..9e5654a --- /dev/null +++ b/apps/web/src/app/api/integrations/openemr/status/route.ts @@ -0,0 +1,22 @@ +import { NextRequest, NextResponse } from "next/server" +import { requireAuthenticatedUser } from "@/lib/auth-guard" +import { getOpenEMRPushStatus } from "@/lib/openemr-client" + +export async function GET(req: NextRequest) { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + + const patientId = req.nextUrl.searchParams.get("patientId") ?? "" + const noteMarkdown = req.nextUrl.searchParams.get("noteMarkdown") ?? "" + const documentId = req.nextUrl.searchParams.get("documentId") ?? undefined + + const status = await getOpenEMRPushStatus({ patientId, noteMarkdown, documentId }) + return NextResponse.json(status, { + status: 200, + headers: { + "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate", + Pragma: "no-cache", + Expires: "0", + }, + }) +} diff --git a/apps/web/src/app/api/settings/api-keys/route.ts b/apps/web/src/app/api/settings/api-keys/route.ts index 38d7d02..6867994 100644 --- a/apps/web/src/app/api/settings/api-keys/route.ts +++ b/apps/web/src/app/api/settings/api-keys/route.ts @@ -3,11 +3,12 @@ import { promises as fs } from "fs" import path from "path" import crypto from "crypto" import { writeAuditEntry } from "@storage/audit-log" +import { isHipaaHostedMode } from "@/lib/hipaa-config" +import { requireAuthenticatedUser } from "@/lib/auth-guard" // Encryption configuration const ALGORITHM = "aes-256-gcm" const IV_LENGTH = 12 -const AUTH_TAG_LENGTH = 16 const KEY_LENGTH = 32 /** @@ -16,7 +17,7 @@ const KEY_LENGTH = 32 * so we store an encrypted key in a separate file. */ async function getEncryptionKey(): Promise { - const configDir = path.dirname(getConfigPath()) + const configDir = path.dirname(await getConfigPath()) const keyPath = path.join(configDir, ".encryption-key") try { @@ -30,7 +31,9 @@ async function getEncryptionKey(): Promise { // Ensure directory exists try { await fs.mkdir(configDir, { recursive: true }) - } catch {} + } catch { + // Directory creation races are safe to ignore. + } // Store key with restrictive permissions await fs.writeFile(keyPath, key, { mode: 0o600 }) @@ -82,15 +85,16 @@ async function decryptData(payload: string): Promise { } // Get the app data directory for storing config -function getConfigPath(): string { +async function getConfigPath(): Promise { try { - const { app } = require("electron") + const electron = await import("electron") + const app = electron.app if (app && app.getPath) { // Electron environment const userDataPath = app.getPath("userData") return path.join(userDataPath, "api-keys.json") } - } catch (error) { + } catch { // Electron not available (development or build time) } // Development environment - use temp directory @@ -98,11 +102,21 @@ function getConfigPath(): string { } export async function POST(req: NextRequest) { + if (isHipaaHostedMode()) { + return NextResponse.json( + { error: "API key management is disabled in hosted HIPAA mode" }, + { status: 410 }, + ) + } + + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + try { const body = await req.json() const { openaiApiKey, anthropicApiKey } = body - const configPath = getConfigPath() + const configPath = await getConfigPath() // Prepare data const data = JSON.stringify( @@ -152,8 +166,18 @@ export async function POST(req: NextRequest) { } export async function GET() { + if (isHipaaHostedMode()) { + return NextResponse.json( + { error: "API key management is disabled in hosted HIPAA mode" }, + { status: 410 }, + ) + } + + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + try { - const configPath = getConfigPath() + const configPath = await getConfigPath() try { const fileContent = await fs.readFile(configPath, "utf-8") @@ -163,7 +187,7 @@ export async function GET() { const keys = JSON.parse(decrypted) return NextResponse.json(keys) - } catch (error) { + } catch { // File doesn't exist or is invalid, return empty keys return NextResponse.json({ openaiApiKey: "", diff --git a/apps/web/src/app/api/settings/mixed-auth-status/route.ts b/apps/web/src/app/api/settings/mixed-auth-status/route.ts index 9f6d0d8..02200c3 100644 --- a/apps/web/src/app/api/settings/mixed-auth-status/route.ts +++ b/apps/web/src/app/api/settings/mixed-auth-status/route.ts @@ -1,7 +1,11 @@ import { NextResponse } from "next/server" import { getAnthropicApiKeyStatus } from "@storage/server-api-keys" +import { requireAuthenticatedUser } from "@/lib/auth-guard" export async function GET() { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + try { const status = getAnthropicApiKeyStatus() return NextResponse.json({ diff --git a/apps/web/src/app/api/transcription/final/route.ts b/apps/web/src/app/api/transcription/final/route.ts index 00a7bb8..d42597f 100644 --- a/apps/web/src/app/api/transcription/final/route.ts +++ b/apps/web/src/app/api/transcription/final/route.ts @@ -1,8 +1,14 @@ import type { NextRequest } from "next/server" import { toPipelineError } from "@pipeline-errors" import { parseWavHeader, resolveTranscriptionProvider, transcribeWithResolvedProvider } from "@transcription" -import { transcriptionSessionStore } from "@transcript-assembly" +import { + emitTranscriptionError, + setTranscriptionFinal, + setTranscriptionStatus, +} from "@/lib/transcription-store" import { writeAuditEntry } from "@storage/audit-log" +import { requireAuthenticatedUser, requireAcceptedTerms } from "@/lib/auth-guard" +import { logServer } from "@/lib/server-logger" export const runtime = "nodejs" @@ -70,6 +76,11 @@ function isBlankTranscript(text: string): boolean { export async function POST(req: NextRequest) { try { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + const terms = await requireAcceptedTerms(auth.userId) + if (!terms.ok) return terms.response + const formData = await req.formData() const sessionId = formData.get("session_id") const file = formData.get("file") @@ -78,7 +89,7 @@ export async function POST(req: NextRequest) { return jsonError(400, "validation_error", "Missing session_id or file", false) } - transcriptionSessionStore.setStatus(sessionId, "finalizing") + await setTranscriptionStatus(sessionId, "finalizing", auth.userId) const arrayBuffer = await file.arrayBuffer() let wavInfo @@ -105,10 +116,13 @@ export async function POST(req: NextRequest) { ) const latencyMs = Date.now() - startedAtMs if (isBlankTranscript(transcript)) { - transcriptionSessionStore.emitError( + await emitTranscriptionError( sessionId, - "blank_audio", - "No detectable speech signal in the recording. Check microphone input/device and retry.", + toPipelineError( + new Error("No detectable speech signal in the recording. Check microphone input/device and retry."), + { code: "blank_audio", message: "No detectable speech signal in the recording. Check microphone input/device and retry.", recoverable: true }, + ), + auth.userId, ) return jsonError( 422, @@ -117,12 +131,12 @@ export async function POST(req: NextRequest) { ) } if (likelySilentAudio) { - console.warn("[transcription.final] low-energy capture produced transcript", { + logServer("warn", "Low-energy capture produced transcript", { sessionId, durationMs: wavInfo.durationMs, }) } - transcriptionSessionStore.setFinalTranscript(sessionId, transcript) + await setTranscriptionFinal(sessionId, transcript, auth.userId) // Audit log: final transcription completed await writeAuditEntry({ @@ -142,14 +156,16 @@ export async function POST(req: NextRequest) { headers: { "Content-Type": "application/json" }, }) } catch (error) { - console.error("Final audio processing failed", error) + logServer("error", "Final audio processing failed", { + code: error instanceof Error ? error.name : "unknown_error", + }) const resolvedProvider = resolveTranscriptionProvider() const pipelineError = toPipelineError(error, { code: "api_error", message: "Transcription API failure", recoverable: true, }) - transcriptionSessionStore.emitError(sessionId, pipelineError) + await emitTranscriptionError(sessionId, pipelineError, auth.userId) // Audit log: final transcription failed await writeAuditEntry({ @@ -166,7 +182,9 @@ export async function POST(req: NextRequest) { return jsonError(502, pipelineError.code, pipelineError.message, pipelineError.recoverable) } } catch (error) { - console.error("Final recording ingestion failed", error) + logServer("error", "Final recording ingestion failed", { + code: error instanceof Error ? error.name : "unknown_error", + }) return jsonError(500, "storage_error", "Failed to process final recording", false) } } diff --git a/apps/web/src/app/api/transcription/segment/route.ts b/apps/web/src/app/api/transcription/segment/route.ts index 7e4ede1..f2ad6f6 100644 --- a/apps/web/src/app/api/transcription/segment/route.ts +++ b/apps/web/src/app/api/transcription/segment/route.ts @@ -1,8 +1,10 @@ import type { NextRequest } from "next/server" import { toPipelineError } from "@pipeline-errors" import { parseWavHeader, resolveTranscriptionProvider, transcribeWithResolvedProvider } from "@transcription" -import { transcriptionSessionStore } from "@transcript-assembly" +import { addTranscriptionSegment, emitTranscriptionError } from "@/lib/transcription-store" import { writeAuditEntry } from "@storage/audit-log" +import { requireAuthenticatedUser, requireAcceptedTerms } from "@/lib/auth-guard" +import { logServer } from "@/lib/server-logger" export const runtime = "nodejs" @@ -59,6 +61,11 @@ function isLikelySilentPcm16(buffer: ArrayBuffer): boolean { export async function POST(req: NextRequest) { try { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + const terms = await requireAcceptedTerms(auth.userId) + if (!terms.ok) return terms.response + const formData = await req.formData() const sessionId = formData.get("session_id") const seqNo = Number(formData.get("seq_no")) @@ -113,14 +120,14 @@ export async function POST(req: NextRequest) { const startedAtMs = Date.now() const transcript = await transcribeWithResolvedProvider(Buffer.from(arrayBuffer), `segment-${seqNo}.wav`, resolvedProvider) const latencyMs = Date.now() - startedAtMs - transcriptionSessionStore.addSegment(sessionId, { + await addTranscriptionSegment(sessionId, { seqNo, startMs, endMs, durationMs, overlapMs, transcript, - }) + }, auth.userId) // Audit log: segment transcribed successfully await writeAuditEntry({ @@ -140,14 +147,16 @@ export async function POST(req: NextRequest) { headers: { "Content-Type": "application/json" }, }) } catch (error) { - console.error("Segment audio processing failed", error) + logServer("error", "Segment audio processing failed", { + code: error instanceof Error ? error.name : "unknown_error", + }) const resolvedProvider = resolveTranscriptionProvider() const pipelineError = toPipelineError(error, { code: "api_error", message: "Transcription API failure", recoverable: true, }) - transcriptionSessionStore.emitError(sessionId, pipelineError) + await emitTranscriptionError(sessionId, pipelineError, auth.userId) // Audit log: segment transcription failed await writeAuditEntry({ @@ -165,7 +174,9 @@ export async function POST(req: NextRequest) { return jsonError(502, pipelineError.code, pipelineError.message, pipelineError.recoverable) } } catch (error) { - console.error("Segment ingestion failed", error) + logServer("error", "Segment ingestion failed", { + code: error instanceof Error ? error.name : "unknown_error", + }) return jsonError(500, "storage_error", "Failed to process audio segment", false) } } diff --git a/apps/web/src/app/api/transcription/stream/[sessionId]/route.ts b/apps/web/src/app/api/transcription/stream/[sessionId]/route.ts index 3846269..d224dd8 100644 --- a/apps/web/src/app/api/transcription/stream/[sessionId]/route.ts +++ b/apps/web/src/app/api/transcription/stream/[sessionId]/route.ts @@ -1,5 +1,6 @@ import type { NextRequest } from "next/server" -import { transcriptionSessionStore } from "@transcript-assembly" +import { subscribeTranscriptionEvents } from "@/lib/transcription-store" +import { requireAuthenticatedUser, requireAcceptedTerms } from "@/lib/auth-guard" export const runtime = "nodejs" @@ -11,18 +12,30 @@ export async function GET( req: NextRequest, context: { params: Promise<{ sessionId: string }> | { sessionId: string } }, ) { + const auth = await requireAuthenticatedUser() + if (!auth.ok) return auth.response + const terms = await requireAcceptedTerms(auth.userId) + if (!terms.ok) return terms.response + const resolvedParams = "then" in context.params ? await context.params : context.params const { sessionId } = resolvedParams let cleanup: (() => void) | null = null const stream = new ReadableStream({ - start(controller) { + async start(controller) { let closed = false const sendEvent = (event: { event: string; data: Record }) => { controller.enqueue(formatSseEvent(event.event, event.data)) } - const unsubscribe = transcriptionSessionStore.subscribe(sessionId, sendEvent) + let unsubscribe: (() => void) | null = null + try { + unsubscribe = await subscribeTranscriptionEvents(sessionId, auth.userId, sendEvent) + } catch { + controller.enqueue(formatSseEvent("error", { code: "forbidden", message: "Session access denied" })) + controller.close() + return + } const keepAlive = setInterval(() => { controller.enqueue(formatSseEvent("keepalive", { session_id: sessionId, ts: Date.now() })) }, 15000) @@ -34,7 +47,7 @@ export async function GET( if (closed) return closed = true clearInterval(keepAlive) - unsubscribe() + unsubscribe?.() req.signal.removeEventListener("abort", abortHandler) try { controller.close() diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 7b90d6f..a2f8492 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,9 +1,8 @@ import type React from "react" import type { Metadata } from "next" -import { Analytics } from "@vercel/analytics/next" import "./globals.css" +import { Providers } from "./providers" -// Updated metadata for OpenScribe clinical documentation app export const metadata: Metadata = { title: "OpenScribe", description: "AI-powered clinical documentation assistant", @@ -23,8 +22,7 @@ export default function RootLayout({ return ( - {children} - + {children} ) diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 096aded..25c0153 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -13,6 +13,7 @@ import { useEncounters, EncounterList, IdleView, NewEncounterForm, RecordingView import { NoteEditor } from "@note-rendering" import { useAudioRecorder, type RecordedSegment, warmupMicrophonePermission, warmupSystemAudioPermission } from "@audio" import { useSegmentUpload, type UploadError } from "@transcription"; +import { signIn, signOut, useSession } from "next-auth/react" import { WorkflowErrorDisplay } from "./workflow-error-display" import { generateClinicalNote } from "@/app/actions" import { @@ -129,6 +130,7 @@ function resolveApiBaseUrl(): string { function HomePageContent() { const { encounters, addEncounter, updateEncounter, deleteEncounter: removeEncounter, refresh } = useEncounters() + const hipaaHostedMode = process.env.NEXT_PUBLIC_HIPAA_HOSTED_MODE === "true" // HIPAA Compliance: Warn if production build is served over HTTP const httpsWarning = useHttpsWarning() @@ -198,6 +200,13 @@ function HomePageContent() { useEffect(() => { const loadApiKeys = async () => { try { + if (hipaaHostedMode) { + setAnthropicApiKeyInput("") + setHasAnthropicApiKey(true) + setMixedAuthSource("env") + setMixedAuthStatusLoaded(true) + return + } const [keys, mixedAuthStatus] = await Promise.all([getApiKeys(), getMixedModeAuthStatus()]) const anthropicKey = (keys.anthropicApiKey || "").trim() setAnthropicApiKeyInput(anthropicKey) @@ -216,7 +225,7 @@ function HomePageContent() { } } void loadApiKeys() - }, []) + }, [hipaaHostedMode]) useEffect(() => { if (typeof window === "undefined") return @@ -278,8 +287,8 @@ function HomePageContent() { }, [localBackendAvailable, processingMode]) useEffect(() => { - setShowMixedKeyPrompt(mixedAuthStatusLoaded && processingMode === "mixed" && !hasAnthropicApiKey) - }, [mixedAuthStatusLoaded, processingMode, hasAnthropicApiKey]) + setShowMixedKeyPrompt(!hipaaHostedMode && mixedAuthStatusLoaded && processingMode === "mixed" && !hasAnthropicApiKey) + }, [mixedAuthStatusLoaded, processingMode, hasAnthropicApiKey, hipaaHostedMode]) useEffect(() => { if (typeof window === "undefined") return @@ -993,7 +1002,7 @@ function HomePageContent() { return } } - if (!useLocalBackend && !hasAnthropicApiKey) { + if (!useLocalBackend && !hipaaHostedMode && !hasAnthropicApiKey) { setShowMixedKeyPrompt(true) setShowSettingsDialog(true) return @@ -1719,9 +1728,106 @@ function HomePageContent() { } export default function HomePage() { + const hipaaHostedMode = process.env.NEXT_PUBLIC_HIPAA_HOSTED_MODE === "true" + const { status } = useSession() + const [termsAccepted, setTermsAccepted] = useState(false) + const [termsLoading, setTermsLoading] = useState(hipaaHostedMode) + + useEffect(() => { + if (!hipaaHostedMode) return + if (status !== "authenticated") return + void fetch("/api/compliance/session", { method: "GET" }) + }, [hipaaHostedMode, status]) + + useEffect(() => { + if (!hipaaHostedMode) return + if (status !== "authenticated") return + const loadTerms = async () => { + try { + const response = await fetch("/api/compliance/terms", { method: "GET" }) + if (!response.ok) { + setTermsAccepted(false) + return + } + const payload = (await response.json()) as { accepted?: boolean } + setTermsAccepted(!!payload.accepted) + } finally { + setTermsLoading(false) + } + } + void loadTerms() + }, [hipaaHostedMode, status]) + + if (hipaaHostedMode && status === "loading") { + return
Loading session...
+ } + + if (hipaaHostedMode && status !== "authenticated") { + return ( +
+

OpenScribe HIPAA Hosted

+

+ Sign in with Google to access the hosted clinical workflow. +

+ +
+ ) + } + + if (hipaaHostedMode && termsLoading) { + return
Loading compliance policy...
+ } + + if (hipaaHostedMode && !termsAccepted) { + return ( +
+

Terms Acceptance Required

+

+ By continuing, you acknowledge this hosted environment processes PHI and agree to the HIPAA/privacy terms. +

+ + +
+ ) + } + return ( - - - +
+ {hipaaHostedMode && ( +
+ +
+ )} + + + +
) } diff --git a/apps/web/src/app/providers.tsx b/apps/web/src/app/providers.tsx new file mode 100644 index 0000000..15b7663 --- /dev/null +++ b/apps/web/src/app/providers.tsx @@ -0,0 +1,8 @@ +"use client" + +import { SessionProvider } from "next-auth/react" +import type { ReactNode } from "react" + +export function Providers({ children }: { children: ReactNode }) { + return {children} +} diff --git a/apps/web/src/lib/__tests__/openemr-auth-state.test.ts b/apps/web/src/lib/__tests__/openemr-auth-state.test.ts new file mode 100644 index 0000000..6ebe30e --- /dev/null +++ b/apps/web/src/lib/__tests__/openemr-auth-state.test.ts @@ -0,0 +1,36 @@ +import { describe, it } from "node:test" +import assert from "node:assert/strict" +import os from "node:os" +import path from "node:path" +import { mkdtempSync } from "node:fs" +import { + getOpenEMRTokenState, + persistOpenEMRRefreshToken, + recordOpenEMRRefreshAttempt, +} from "../openemr-auth-state.js" + +describe("openemr-auth-state", () => { + it("prefers persisted token over env fallback", async () => { + const dir = mkdtempSync(path.join(os.tmpdir(), "openemr-auth-state-")) + process.env.OPENEMR_AUTH_STATE_FILE = path.join(dir, "state.json") + + const before = await getOpenEMRTokenState("env-token") + assert.equal(before.source, "env") + assert.equal(before.refreshToken, "env-token") + + await persistOpenEMRRefreshToken("persisted-token") + const after = await getOpenEMRTokenState("env-token") + assert.equal(after.source, "persisted") + assert.equal(after.refreshToken, "persisted-token") + }) + + it("records last refresh attempt metadata", async () => { + const dir = mkdtempSync(path.join(os.tmpdir(), "openemr-auth-state-")) + process.env.OPENEMR_AUTH_STATE_FILE = path.join(dir, "state.json") + await persistOpenEMRRefreshToken("persisted-token") + await recordOpenEMRRefreshAttempt("user_auth_failure") + const state = await getOpenEMRTokenState("env-token") + assert.equal(state.lastRefreshError, "user_auth_failure") + assert.ok(state.lastRefreshAttempt) + }) +}) diff --git a/apps/web/src/lib/__tests__/openemr-client.test.ts b/apps/web/src/lib/__tests__/openemr-client.test.ts new file mode 100644 index 0000000..f146234 --- /dev/null +++ b/apps/web/src/lib/__tests__/openemr-client.test.ts @@ -0,0 +1,293 @@ +import { afterEach, before, beforeEach, describe, it } from "node:test" +import assert from "node:assert/strict" +import crypto from "node:crypto" +import os from "node:os" +import path from "node:path" +import { mkdtempSync } from "node:fs" +import { + _resetTokenCacheForTesting, + getOpenEMRPushStatus, + isOpenEMRConfigured, + pushNoteToOpenEMR, +} from "../openemr-client.js" + +type FetchCall = { + url: string + init?: RequestInit + body?: Record +} + +function jsonResp(status: number, body: unknown): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "Content-Type": "application/json" }, + }) +} + +function makeFetch(responses: Response[]): { fn: typeof fetch; calls: FetchCall[] } { + const calls: FetchCall[] = [] + let index = 0 + const fn = async (url: string | URL | Request, init?: RequestInit) => { + const urlStr = typeof url === "string" ? url : url.toString() + let body: Record | undefined + if (typeof init?.body === "string") { + try { + body = JSON.parse(init.body) + } catch { + try { + body = Object.fromEntries(new URLSearchParams(init.body).entries()) + } catch { + body = undefined + } + } + } + calls.push({ url: urlStr, init, body }) + const response = responses[index++] + if (!response) { + throw new Error(`Unexpected fetch call #${index} to ${urlStr}`) + } + return response + } + return { fn: fn as unknown as typeof fetch, calls } +} + +const PUSH_PARAMS = { + patientId: "a1392bc9-b9b8-4dc0-aa48-d1df64f98773", + noteMarkdown: + "# Clinical Note\n\n## Chief Complaint\nPatient reports mild headache and dizziness for several days with intermittent nausea.\n\n## History of Present Illness\nSymptoms started three days ago, worsen with sudden position changes, and improve with rest and hydration.", + patientName: "Jane Doe", + visitReason: "annual_exam", + encounterId: "enc-1", +} + +let TEST_PRIVATE_KEY_PEM = "" + +before(() => { + const { privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }) + TEST_PRIVATE_KEY_PEM = privateKey.export({ type: "pkcs8", format: "pem" }) as string +}) + +afterEach(() => { + _resetTokenCacheForTesting() +}) + +describe("isOpenEMRConfigured", () => { + it("returns true when required env vars are set", () => { + const saved = { + OPENEMR_BASE_URL: process.env.OPENEMR_BASE_URL, + OPENEMR_CLIENT_ID: process.env.OPENEMR_CLIENT_ID, + OPENEMR_JWT_PRIVATE_KEY_PEM: process.env.OPENEMR_JWT_PRIVATE_KEY_PEM, + } + process.env.OPENEMR_BASE_URL = "http://localhost:8080" + process.env.OPENEMR_CLIENT_ID = "test-client-id" + process.env.OPENEMR_JWT_PRIVATE_KEY_PEM = TEST_PRIVATE_KEY_PEM + assert.equal(isOpenEMRConfigured(), true) + for (const [k, v] of Object.entries(saved)) { + if (v === undefined) delete process.env[k] + else process.env[k] = v + } + }) +}) + +describe("pushNoteToOpenEMR", () => { + before(() => { + process.env.OPENEMR_BASE_URL = "http://localhost:8080" + process.env.OPENEMR_CLIENT_ID = "test-client-id" + process.env.OPENEMR_JWT_PRIVATE_KEY_PEM = TEST_PRIVATE_KEY_PEM + process.env.OPENEMR_TOKEN_SCOPE = "system/DocumentReference.write system/Patient.read" + delete process.env.OPENEMR_CLIENT_SECRET + }) + + beforeEach(() => { + const tmpDir = mkdtempSync(path.join(os.tmpdir(), "openemr-client-test-")) + process.env.OPENEMR_AUTH_STATE_FILE = path.join(tmpDir, "state.json") + delete process.env.OPENEMR_USER_REFRESH_TOKEN + delete process.env.OPENEMR_USER_TOKEN_SCOPE + }) + + it("returns auth failure when token exchange fails", async () => { + const { fn, calls } = makeFetch([jsonResp(401, { error: "unauthorized" })]) + const result = await pushNoteToOpenEMR(PUSH_PARAMS, fn) + assert.equal(result.success, false) + assert.ok(result.error?.includes("authentication failed")) + assert.equal(calls.length, 1) + }) + + it("token request uses JWT assertion and not client_secret", async () => { + const { fn, calls } = makeFetch([jsonResp(401, { error: "unauthorized" })]) + await pushNoteToOpenEMR(PUSH_PARAMS, fn) + const body = calls[0]?.body + assert.equal(body?.grant_type, "client_credentials") + assert.equal( + body?.client_assertion_type, + "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + ) + assert.equal(body?.scope, "system/DocumentReference.write system/Patient.read") + assert.equal(body?.client_secret, undefined) + assert.ok( + typeof body?.client_assertion === "string" && + (body.client_assertion as string).split(".").length === 3, + ) + }) + + it("reuses cached token on second push", async () => { + const { fn, calls } = makeFetch([ + jsonResp(200, { access_token: "tok", expires_in: 3600 }), + jsonResp(200, { + rest: [{ resource: [{ type: "DocumentReference", interaction: [{ code: "create" }] }] }], + }), + jsonResp(200, { resourceType: "Patient", id: PUSH_PARAMS.patientId }), + jsonResp(201, { id: "doc-1" }), + jsonResp(200, { resourceType: "Patient", id: PUSH_PARAMS.patientId }), + jsonResp(201, { id: "doc-2" }), + ]) + + await pushNoteToOpenEMR(PUSH_PARAMS, fn) + await pushNoteToOpenEMR(PUSH_PARAMS, fn) + + const tokenCalls = calls.filter((call) => call.url.includes("/oauth2/")) + assert.equal(tokenCalls.length, 1) + }) + + it("rejects non-UUID patient ids before network calls", async () => { + const { fn, calls } = makeFetch([]) + const result = await pushNoteToOpenEMR({ ...PUSH_PARAMS, patientId: "abc" }, fn) + assert.equal(result.success, false) + assert.ok(result.error?.includes("numeric PID")) + assert.equal(calls.length, 0) + }) + + it("supports numeric PID when user refresh-token mode is enabled", async () => { + process.env.OPENEMR_USER_REFRESH_TOKEN = "test-refresh" + process.env.OPENEMR_USER_TOKEN_SCOPE = "api:oemr user/document.write user/document.read user/patient.read" + + const { fn, calls } = makeFetch([ + jsonResp(200, { access_token: "user-tok", expires_in: 3600 }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(500, { error: "RestControllerHelper::getResponseForPayload() expects a string, array, numeric, or JsonSerializable object, bool given." }), + jsonResp(200, [{ filename: "openscribe-note-final.txt", id: 123 }]), + jsonResp(200, [{ filename: "openscribe-note-final.txt", id: 123 }]), + ]) + + const result = await pushNoteToOpenEMR({ ...PUSH_PARAMS, patientId: "3" }, fn) + assert.equal(result.success, true, JSON.stringify(result)) + assert.equal((result as { success: true; id: string }).id, "123") + assert.equal((result as { success: true; verifiedLength: number }).verifiedLength, PUSH_PARAMS.noteMarkdown.length) + const resolveCalls = calls.filter((call) => call.url.endsWith("/api/patient/3")) + assert.equal(resolveCalls.length, 1) + + delete process.env.OPENEMR_USER_REFRESH_TOKEN + delete process.env.OPENEMR_USER_TOKEN_SCOPE + }) + + it("verifies latest uploaded doc id when filename already exists", async () => { + process.env.OPENEMR_USER_REFRESH_TOKEN = "test-refresh" + process.env.OPENEMR_USER_TOKEN_SCOPE = "api:oemr user/document.write user/document.read user/patient.read" + + const { fn } = makeFetch([ + jsonResp(200, { access_token: "user-tok", expires_in: 3600 }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(500, { + error: + "RestControllerHelper::getResponseForPayload() expects a string, array, numeric, or JsonSerializable object, bool given.", + }), + jsonResp(200, [ + { filename: "openscribe-note-final.txt", id: 15 }, + { filename: "openscribe-note-final.txt", id: 18 }, + ]), + jsonResp(200, [{ filename: "openscribe-note-final.txt", id: 18 }]), + ]) + + const result = await pushNoteToOpenEMR({ ...PUSH_PARAMS, patientId: "3" }, fn) + assert.equal(result.success, true, JSON.stringify(result)) + assert.equal((result as { success: true; id: string }).id, "18") + + delete process.env.OPENEMR_USER_REFRESH_TOKEN + delete process.env.OPENEMR_USER_TOKEN_SCOPE + }) + + it("fails with OPENEMR_NOTE_TOO_SHORT when note quality gate is not met", async () => { + const { fn, calls } = makeFetch([]) + const result = await pushNoteToOpenEMR( + { + ...PUSH_PARAMS, + patientId: "3", + noteMarkdown: "too short", + }, + fn, + ) + assert.equal(result.success, false) + assert.equal((result as { success: false; code?: string }).code, "OPENEMR_NOTE_TOO_SHORT") + assert.equal(calls.length, 0) + }) + + it("status returns blockers when note and patient id are invalid", async () => { + const status = await getOpenEMRPushStatus({ patientId: "bad-id", noteMarkdown: "short" }) + assert.equal(status.patient_id_valid, false) + assert.equal(status.note_ok, false) + assert.equal(status.can_push, false) + assert.ok(status.blockers.some((b) => b.code === "OPENEMR_PATIENT_ID_INVALID")) + assert.ok(status.blockers.some((b) => b.code === "OPENEMR_NOTE_TOO_SHORT")) + }) + + it("returns patient not found when Patient endpoint fails", async () => { + const { fn, calls } = makeFetch([ + jsonResp(200, { access_token: "tok", expires_in: 3600 }), + jsonResp(404, { error: "not found" }), + jsonResp(404, { error: "not found" }), + ]) + const result = await pushNoteToOpenEMR({ ...PUSH_PARAMS, patientId: "3" }, fn) + assert.equal(result.success, false) + assert.ok(result.error?.includes("3")) + const docCalls = calls.filter((call) => call.url.includes("/DocumentReference")) + assert.equal(docCalls.length, 0) + }) + + it("returns explicit error when server does not support DocumentReference create", async () => { + const { fn, calls } = makeFetch([ + jsonResp(200, { access_token: "tok", expires_in: 3600 }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(500, { error: "upload failed" }), + jsonResp(200, { + rest: [{ resource: [{ type: "DocumentReference", interaction: [{ code: "read" }] }] }], + }), + ]) + const result = await pushNoteToOpenEMR(PUSH_PARAMS, fn) + assert.equal(result.success, false) + assert.ok(result.error?.includes("does not support")) + assert.equal(calls.length, 5) + }) + + it("binds patient id and note markdown in DocumentReference payload", async () => { + const { fn, calls } = makeFetch([ + jsonResp(200, { access_token: "tok", expires_in: 3600 }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(200, { data: { id: 3 } }), + jsonResp(500, { error: "upload failed" }), + jsonResp(200, { + rest: [{ resource: [{ type: "DocumentReference", interaction: [{ code: "create" }] }] }], + }), + jsonResp(200, { resourceType: "Patient", id: PUSH_PARAMS.patientId }), + jsonResp(201, { id: "doc-777" }), + ]) + + const result = await pushNoteToOpenEMR(PUSH_PARAMS, fn) + assert.equal(result.success, true) + assert.equal((result as { success: true; id: string }).id, "doc-777") + + const docCall = calls.find((call) => call.url.endsWith("/fhir/DocumentReference")) + assert.ok(docCall?.body) + const payload = docCall.body as Record + assert.equal((payload.subject as { reference: string }).reference, `Patient/${PUSH_PARAMS.patientId}`) + const attachment = ( + ( + (payload.content as Array<{ attachment: { data: string } }>)[0] ?? { + attachment: { data: "" }, + } + ).attachment + ) + const decoded = Buffer.from(attachment.data, "base64").toString("utf8") + assert.equal(decoded, PUSH_PARAMS.noteMarkdown) + }) +}) diff --git a/apps/web/src/lib/__tests__/openemr-push-handler.test.ts b/apps/web/src/lib/__tests__/openemr-push-handler.test.ts new file mode 100644 index 0000000..7b256db --- /dev/null +++ b/apps/web/src/lib/__tests__/openemr-push-handler.test.ts @@ -0,0 +1,197 @@ +/** + * Trust boundary tests for openemr-push-handler.ts + * + * Boundaries tested: + * ① Auth identity check — unauthenticated requests return 401 before any push + * ② Input validation — missing required fields return 400 before any push + * ③ Identity binding — all 4 params flow to pushFn unchanged + * + * Uses Node.js built-in test runner (node:test + node:assert/strict). + */ + +import { describe, it } from "node:test" +import assert from "node:assert/strict" +import { handlePushRequest } from "../openemr-push-handler.js" +import type { PushResult } from "../openemr-client.js" + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makePushFn(result: PushResult) { + let called = false + let calledWith: unknown = null + const fn = async (params: unknown) => { + called = true + calledWith = params + return result + } + return { + fn: fn as Parameters[2], + wasCalled: () => called, + calledWith: () => calledWith, + } +} + +const AUTHENTICATED = { isAuthenticated: true } +const UNAUTHENTICATED = { isAuthenticated: false } + +const VALID_BODY = { + encounterId: "enc-001", + patientId: "42", + noteMarkdown: "# Note", + patientName: "Jane Doe", + visitReason: "Annual physical", +} + +// --------------------------------------------------------------------------- +// Auth boundary (①) +// --------------------------------------------------------------------------- + +describe("handlePushRequest — auth boundary ①", () => { + it("returns 401 when not authenticated", async () => { + const { fn, wasCalled } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + const result = await handlePushRequest(UNAUTHENTICATED, VALID_BODY, fn) + assert.equal(result.status, 401) + assert.equal(wasCalled(), false, "pushFn must not be called when unauthenticated") + }) + + it("proceeds past auth check when authenticated", async () => { + const { fn, wasCalled } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + const result = await handlePushRequest(AUTHENTICATED, VALID_BODY, fn) + assert.equal(result.status, 200) + assert.equal(wasCalled(), true) + }) +}) + +// --------------------------------------------------------------------------- +// Input guard (②) +// --------------------------------------------------------------------------- + +describe("handlePushRequest — input guard ②", () => { + it("returns 400 when body is null", async () => { + const { fn, wasCalled } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + const result = await handlePushRequest(AUTHENTICATED, null, fn) + assert.equal(result.status, 400) + assert.equal(wasCalled(), false) + }) + + it("returns 400 when patientId is missing", async () => { + const { fn, wasCalled } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + const body = { ...VALID_BODY, patientId: undefined } + const result = await handlePushRequest(AUTHENTICATED, body, fn) + assert.equal(result.status, 400) + assert.equal(wasCalled(), false) + }) + + it("returns 400 when noteMarkdown is missing", async () => { + const { fn, wasCalled } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + const body = { ...VALID_BODY, noteMarkdown: undefined } + const result = await handlePushRequest(AUTHENTICATED, body, fn) + assert.equal(result.status, 400) + assert.equal(wasCalled(), false) + }) +}) + +// --------------------------------------------------------------------------- +// Identity binding (③) +// --------------------------------------------------------------------------- + +describe("handlePushRequest — identity binding ③", () => { + it("passes all 4 required fields to pushFn unchanged", async () => { + const { fn, calledWith } = makePushFn({ + success: true, + id: "doc-1", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 123, + openEMRDocumentUrl: null, + }) + await handlePushRequest(AUTHENTICATED, VALID_BODY, fn) + const params = calledWith() as Record + assert.equal(params.patientId, VALID_BODY.patientId) + assert.equal(params.noteMarkdown, VALID_BODY.noteMarkdown) + assert.equal(params.patientName, VALID_BODY.patientName) + assert.equal(params.visitReason, VALID_BODY.visitReason) + }) +}) + +// --------------------------------------------------------------------------- +// Response shape +// --------------------------------------------------------------------------- + +describe("handlePushRequest — response shape", () => { + it("returns 200 with id on success", async () => { + const { fn } = makePushFn({ + success: true, + id: "doc-777", + uploadedAt: "2026-03-17T00:00:00.000Z", + verifiedPreview: "preview", + verifiedLength: 456, + openEMRDocumentUrl: "http://localhost:8080/controller.php?document&retrieve&patient_id=3&document_id=777&", + }) + const result = await handlePushRequest(AUTHENTICATED, VALID_BODY, fn) + assert.equal(result.status, 200) + const json = result.json as { + success: boolean + id: string + uploadedAt: string + verifiedPreview: string + verifiedLength: number + openEMRDocumentUrl: string | null + } + assert.equal(json.success, true) + assert.equal(json.id, "doc-777") + assert.equal(json.verifiedLength, 456) + assert.equal(json.verifiedPreview, "preview") + }) + + it("returns 500 with error on push failure", async () => { + const { fn } = makePushFn({ + success: false, + error: "Patient not found", + code: "OPENEMR_PATIENT_NOT_FOUND", + }) + const result = await handlePushRequest(AUTHENTICATED, VALID_BODY, fn) + assert.equal(result.status, 500) + const json = result.json as { success: boolean; error: string; code: string } + assert.equal(json.success, false) + assert.equal(json.error, "Patient not found") + assert.equal(json.code, "OPENEMR_PATIENT_NOT_FOUND") + }) +}) diff --git a/apps/web/src/lib/auth-guard.ts b/apps/web/src/lib/auth-guard.ts new file mode 100644 index 0000000..45eb7b2 --- /dev/null +++ b/apps/web/src/lib/auth-guard.ts @@ -0,0 +1,33 @@ +import { getServerSession } from "next-auth" +import { hasAcceptedTerms } from "./compliance" +import { isHipaaHostedMode } from "./hipaa-config" + +export async function requireAuthenticatedUser() { + if (!isHipaaHostedMode()) { + return { ok: true as const, userId: "local-user", session: { user: { id: "local-user" } } } + } + const { authOptions } = await import("./auth") + const session = await getServerSession(authOptions) + const userId = session?.user?.id + if (!userId) { + return { ok: false as const, response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 }) } + } + return { ok: true as const, userId, session } +} + +export async function requireAcceptedTerms(userId: string) { + if (!isHipaaHostedMode()) { + return { ok: true as const } + } + const accepted = await hasAcceptedTerms(userId) + if (!accepted) { + return { + ok: false as const, + response: new Response(JSON.stringify({ error: "Terms acceptance required" }), { + status: 403, + headers: { "Content-Type": "application/json" }, + }), + } + } + return { ok: true as const } +} diff --git a/apps/web/src/lib/auth.ts b/apps/web/src/lib/auth.ts new file mode 100644 index 0000000..a1fa865 --- /dev/null +++ b/apps/web/src/lib/auth.ts @@ -0,0 +1,56 @@ +import NextAuth, { type NextAuthOptions } from "next-auth" +import GoogleProvider from "next-auth/providers/google" +import PostgresAdapter from "@auth/pg-adapter" +import { getDbPool } from "./db" +import { isHipaaHostedMode } from "./hipaa-config" + +const baseAuthOptions: NextAuthOptions = { + providers: [ + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID || "", + clientSecret: process.env.GOOGLE_CLIENT_SECRET || "", + allowDangerousEmailAccountLinking: false, + }), + ], + secret: process.env.AUTH_SECRET || "local-dev-auth-secret", + trustHost: true, + session: { + strategy: "jwt", + maxAge: 8 * 60 * 60, + updateAge: 60 * 60, + }, + callbacks: { + async session({ session, user, token }) { + const userId = user?.id || (typeof token?.sub === "string" ? token.sub : undefined) + if (session.user && userId) { + ;(session.user as { id?: string }).id = userId + } + return session + }, + }, +} + +export const authOptions: NextAuthOptions = isHipaaHostedMode() + ? { + ...baseAuthOptions, + adapter: PostgresAdapter(getDbPool()), + session: { + strategy: "database", + maxAge: 8 * 60 * 60, + updateAge: 60 * 60, + }, + cookies: { + sessionToken: { + name: process.env.NODE_ENV === "production" ? "__Secure-next-auth.session-token" : "next-auth.session-token", + options: { + httpOnly: true, + sameSite: "lax", + path: "/", + secure: process.env.NODE_ENV === "production", + }, + }, + }, + } + : baseAuthOptions + +export default NextAuth(authOptions) diff --git a/apps/web/src/lib/compliance.ts b/apps/web/src/lib/compliance.ts new file mode 100644 index 0000000..00089ce --- /dev/null +++ b/apps/web/src/lib/compliance.ts @@ -0,0 +1,62 @@ +import crypto from "crypto" +import type { NextRequest } from "next/server" +import { ensureComplianceTables, getDbPool } from "./db" + +export const TERMS_VERSION = "2026-03-hipaa-hosted-v1" + +function hashValue(input: string): string { + return crypto.createHash("sha256").update(input).digest("hex") +} + +function requestIp(req: NextRequest): string { + const xff = req.headers.get("x-forwarded-for") || "" + if (xff) return xff.split(",")[0]?.trim() || "unknown" + return "unknown" +} + +function requestUa(req: NextRequest): string { + return req.headers.get("user-agent") || "unknown" +} + +export async function hasAcceptedTerms(userId: string): Promise { + await ensureComplianceTables() + const db = getDbPool() + const result = await db.query( + `SELECT id FROM user_terms_acceptance WHERE user_id = $1 AND terms_version = $2 LIMIT 1`, + [userId, TERMS_VERSION], + ) + return result.rowCount > 0 +} + +export async function acceptTerms(userId: string, req: NextRequest): Promise { + await ensureComplianceTables() + const db = getDbPool() + await db.query( + `INSERT INTO user_terms_acceptance (user_id, terms_version, ip_hash, ua_hash) + VALUES ($1, $2, $3, $4)`, + [userId, TERMS_VERSION, hashValue(requestIp(req)), hashValue(requestUa(req))], + ) +} + +export async function writeAuthEvent(params: { + userId?: string + eventType: string + provider?: string + success: boolean + req: NextRequest +}): Promise { + await ensureComplianceTables() + const db = getDbPool() + await db.query( + `INSERT INTO auth_events (user_id, event_type, provider, success, ip_hash, ua_hash) + VALUES ($1, $2, $3, $4, $5, $6)`, + [ + params.userId || null, + params.eventType, + params.provider || null, + params.success, + hashValue(requestIp(params.req)), + hashValue(requestUa(params.req)), + ], + ) +} diff --git a/apps/web/src/lib/db.ts b/apps/web/src/lib/db.ts new file mode 100644 index 0000000..a8e94d2 --- /dev/null +++ b/apps/web/src/lib/db.ts @@ -0,0 +1,24 @@ +import { Pool } from "pg" + +let pool: Pool | null = null + +export function getDbPool(): Pool { + if (pool) return pool + const connectionString = process.env.DATABASE_URL + if (!connectionString) { + throw new Error("Missing DATABASE_URL") + } + pool = new Pool({ connectionString }) + return pool +} + +let initialized = false + +export async function ensureComplianceTables(): Promise { + if (initialized) return + const db = getDbPool() + await db.query("SELECT 1 FROM user_terms_acceptance LIMIT 1") + await db.query("SELECT 1 FROM auth_events LIMIT 1") + + initialized = true +} diff --git a/apps/web/src/lib/hipaa-config.ts b/apps/web/src/lib/hipaa-config.ts new file mode 100644 index 0000000..69dd5b1 --- /dev/null +++ b/apps/web/src/lib/hipaa-config.ts @@ -0,0 +1,11 @@ +export function isHipaaHostedMode(): boolean { + return process.env.HIPAA_HOSTED_MODE === "true" +} + +export function requireHipaaEnv(name: string): string { + const value = (process.env[name] || "").trim() + if (!value) { + throw new Error(`Missing required environment variable: ${name}`) + } + return value +} diff --git a/apps/web/src/lib/openemr-auth-state.ts b/apps/web/src/lib/openemr-auth-state.ts new file mode 100644 index 0000000..83227f3 --- /dev/null +++ b/apps/web/src/lib/openemr-auth-state.ts @@ -0,0 +1,162 @@ +import { promises as fs } from "node:fs" +import path from "node:path" +import crypto from "node:crypto" + +const ALGORITHM = "aes-256-gcm" +const IV_LENGTH = 12 +const KEY_LENGTH = 32 + +type PersistedAuthState = { + refreshToken: string + lastRefreshAttempt: string | null + lastRefreshError: string | null + updatedAt: string +} + +export type OpenEMRTokenState = { + hasToken: boolean + source: "persisted" | "env" | "none" + refreshToken: string | null + lastRefreshAttempt: string | null + lastRefreshError: string | null +} + +async function getStatePath(): Promise { + const explicit = process.env.OPENEMR_AUTH_STATE_FILE?.trim() + if (explicit) return explicit + try { + const electron = await import("electron") + const app = electron.app + if (app?.getPath) { + return path.join(app.getPath("userData"), "openemr-auth-state.json") + } + } catch { + // noop + } + return path.join(process.cwd(), ".openemr-auth-state.json") +} + +async function getKeyPath(): Promise { + const statePath = await getStatePath() + return path.join(path.dirname(statePath), ".openemr-auth-state.key") +} + +async function getEncryptionKey(): Promise { + const keyPath = await getKeyPath() + try { + const existing = new Uint8Array(await fs.readFile(keyPath)) + if (existing.length === KEY_LENGTH) return existing + } catch { + // noop + } + + const key = new Uint8Array(crypto.randomBytes(KEY_LENGTH)) + await fs.mkdir(path.dirname(keyPath), { recursive: true }) + await fs.writeFile(keyPath, key, { mode: 0o600 }) + return key +} + +async function encrypt(plaintext: string): Promise { + const key = await getEncryptionKey() + const iv = new Uint8Array(crypto.randomBytes(IV_LENGTH)) + const cipher = crypto.createCipheriv(ALGORITHM, key, iv) + const encrypted = cipher.update(plaintext, "utf8", "base64") + cipher.final("base64") + const authTag = cipher.getAuthTag() + return `enc.v1.${Buffer.from(iv).toString("base64")}.${Buffer.from(authTag as Uint8Array).toString("base64")}.${encrypted}` +} + +async function decrypt(payload: string): Promise { + const parts = payload.split(".") + if (parts.length === 5 && parts[0] === "enc" && parts[1] === "v1") { + const key = await getEncryptionKey() + const iv = new Uint8Array(Buffer.from(parts[2] ?? "", "base64")) + const authTag = new Uint8Array(Buffer.from(parts[3] ?? "", "base64")) + const ciphertext = parts[4] ?? "" + const decipher = crypto.createDecipheriv(ALGORITHM, key, iv) + decipher.setAuthTag(authTag) + return decipher.update(ciphertext, "base64", "utf8") + decipher.final("utf8") + } + return payload +} + +async function loadPersistedAuthState(): Promise { + const statePath = await getStatePath() + try { + const raw = await fs.readFile(statePath, "utf8") + const decrypted = await decrypt(raw) + const parsed = JSON.parse(decrypted) as Partial + if (!parsed.refreshToken || typeof parsed.refreshToken !== "string") return null + return { + refreshToken: parsed.refreshToken, + lastRefreshAttempt: parsed.lastRefreshAttempt ?? null, + lastRefreshError: parsed.lastRefreshError ?? null, + updatedAt: parsed.updatedAt ?? new Date(0).toISOString(), + } + } catch { + return null + } +} + +async function savePersistedAuthState(next: PersistedAuthState): Promise { + const statePath = await getStatePath() + await fs.mkdir(path.dirname(statePath), { recursive: true }) + const encrypted = await encrypt(JSON.stringify(next, null, 2)) + await fs.writeFile(statePath, encrypted, { mode: 0o600 }) +} + +export async function getOpenEMRTokenState(envRefreshToken: string | null | undefined): Promise { + const persisted = await loadPersistedAuthState() + if (persisted?.refreshToken) { + return { + hasToken: true, + source: "persisted", + refreshToken: persisted.refreshToken, + lastRefreshAttempt: persisted.lastRefreshAttempt, + lastRefreshError: persisted.lastRefreshError, + } + } + + const envToken = envRefreshToken?.trim() || null + if (envToken) { + return { + hasToken: true, + source: "env", + refreshToken: envToken, + lastRefreshAttempt: null, + lastRefreshError: null, + } + } + + return { + hasToken: false, + source: "none", + refreshToken: null, + lastRefreshAttempt: null, + lastRefreshError: null, + } +} + +export async function persistOpenEMRRefreshToken(refreshToken: string): Promise { + const now = new Date().toISOString() + const current = await loadPersistedAuthState() + await savePersistedAuthState({ + refreshToken, + lastRefreshAttempt: now, + lastRefreshError: null, + updatedAt: now, + }) + if (current && current.refreshToken === refreshToken) { + return + } +} + +export async function recordOpenEMRRefreshAttempt(error: string | null): Promise { + const current = await loadPersistedAuthState() + if (!current?.refreshToken) return + await savePersistedAuthState({ + ...current, + lastRefreshAttempt: new Date().toISOString(), + lastRefreshError: error, + updatedAt: new Date().toISOString(), + }) +} diff --git a/apps/web/src/lib/openemr-client.ts b/apps/web/src/lib/openemr-client.ts new file mode 100644 index 0000000..e9e119a --- /dev/null +++ b/apps/web/src/lib/openemr-client.ts @@ -0,0 +1,1098 @@ +/** + * OpenEMR FHIR client + * + * Push-only integration: OpenScribe → OpenEMR via FHIR R4 DocumentReference. + * + * Auth: OAuth2 client_credentials with RS384 JWT client assertion + * (RFC 7523 / SMART Backend Services). + * + * Trust boundaries implemented here: + * ④ Credential boundary — JWT assertion token fetch; auth failure stops execution + * ⑤ Patient existence — GET Patient/{uuid}; rejects non-UUID ids and missing patients + * ⑥ Identity binding — patientId and noteMarkdown land in DocumentReference payload verbatim + */ + +import crypto from "node:crypto" +import { readFileSync } from "node:fs" +import { + getOpenEMRTokenState, + persistOpenEMRRefreshToken, + recordOpenEMRRefreshAttempt, + type OpenEMRTokenState, +} from "./openemr-auth-state" + +export interface PushParams { + patientId: string + noteMarkdown: string + patientName: string + visitReason: string + encounterId: string +} + +export type PushResult = + | { + success: true + id: string + uploadedAt: string + verifiedPreview: string + verifiedLength: number + openEMRDocumentUrl: string | null + } + | { success: false; error: string; code?: string } + +export interface OpenEMRStatusBlocker { + code: string + message: string +} + +export interface OpenEMRPushStatus { + configured: boolean + auth_ok: boolean + patient_id_valid: boolean + patient_resolvable: boolean + note_ok: boolean + can_push: boolean + document_verified: boolean | null + blockers: OpenEMRStatusBlocker[] + token_state: { + has_token: boolean + source: OpenEMRTokenState["source"] + last_refresh_attempt: string | null + last_refresh_error: string | null + } +} + +export type OpenEMRAuthSetupResult = + | { + success: true + message: string + mode: "user" | "service" + } + | { + success: false + error: string + code?: string + } + +interface Config { + base: string + clientId: string + tokenUrl: string + privateKeyPem: string + scope: string + userRefreshToken: string | null + userRefreshTokenSource: OpenEMRTokenState["source"] + tokenState: OpenEMRTokenState + userScope: string + documentPath: string + pushAuthMode: "service_first" | "user_first" + passwordGrantFallbackEnabled: boolean + username: string | null + password: string | null + userRole: "users" | "patient" +} + +interface TokenCache { + token: string + expiresAt: number +} + +interface CapabilityCache { + supportsDocumentReferenceCreate: boolean + expiresAt: number +} + +interface UserTokenCache { + token: string + expiresAt: number +} + +const DEFAULT_SCOPE = "system/DocumentReference.write system/Patient.read" +const DEFAULT_USER_SCOPE = "api:oemr user/document.write user/document.read user/patient.read" +const DEFAULT_DOCUMENT_PATH = "/Categories/Medical_Record" +const DEFAULT_PUSH_AUTH_MODE: Config["pushAuthMode"] = "service_first" +const FETCH_TIMEOUT_MS = 15_000 +const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000 +const CAPABILITY_CACHE_MS = 5 * 60 * 1000 +const FHIR_UUID_PATTERN = + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i +const OPENEMR_PID_PATTERN = /^[1-9]\d*$/ + +let _tokenCache: TokenCache | null = null +let _capabilityCache: CapabilityCache | null = null +let _userTokenCache: UserTokenCache | null = null +let _userRefreshTokenOverride: string | null = null + +export function isOpenEMRConfigured(): boolean { + return !!( + process.env.OPENEMR_BASE_URL && + process.env.OPENEMR_CLIENT_ID && + process.env.OPENEMR_JWT_PRIVATE_KEY_PEM + ) +} + +export function _resetTokenCacheForTesting(): void { + _tokenCache = null + _capabilityCache = null + _userTokenCache = null + _userRefreshTokenOverride = null +} + +async function getConfig(): Promise { + const base = process.env.OPENEMR_BASE_URL + const clientId = process.env.OPENEMR_CLIENT_ID + const rawKey = process.env.OPENEMR_JWT_PRIVATE_KEY_PEM + if (!base || !clientId || !rawKey) return null + const tokenState = await getOpenEMRTokenState(process.env.OPENEMR_USER_REFRESH_TOKEN ?? null) + + return { + base: base.replace(/\/+$/, ""), + clientId, + tokenUrl: process.env.OPENEMR_TOKEN_URL ?? `${base.replace(/\/+$/, "")}/oauth2/default/token`, + privateKeyPem: loadPrivateKey(rawKey), + scope: process.env.OPENEMR_TOKEN_SCOPE ?? DEFAULT_SCOPE, + userRefreshToken: tokenState.refreshToken, + userRefreshTokenSource: tokenState.source, + tokenState, + userScope: process.env.OPENEMR_USER_TOKEN_SCOPE ?? DEFAULT_USER_SCOPE, + documentPath: process.env.OPENEMR_DOCUMENT_PATH ?? DEFAULT_DOCUMENT_PATH, + pushAuthMode: + process.env.OPENEMR_PUSH_AUTH_MODE === "user_first" + ? "user_first" + : DEFAULT_PUSH_AUTH_MODE, + passwordGrantFallbackEnabled: process.env.OPENEMR_ENABLE_PASSWORD_GRANT_FALLBACK === "true", + username: process.env.OPENEMR_USERNAME ?? null, + password: process.env.OPENEMR_PASSWORD ?? null, + userRole: process.env.OPENEMR_USER_ROLE === "patient" ? "patient" : "users", + } +} + +function loadPrivateKey(raw: string): string { + const normalized = raw.replace(/\\n/g, "\n") + if (normalized.trimStart().startsWith("-----BEGIN")) { + return normalized + } + return readFileSync(raw.trim(), "utf-8") +} + +function buildClientAssertion(clientId: string, tokenUrl: string, privateKeyPem: string): string { + const header = { alg: "RS384", typ: "JWT" } + const now = Math.floor(Date.now() / 1000) + const payload = { + iss: clientId, + sub: clientId, + aud: tokenUrl, + exp: now + 300, + iat: now, + jti: crypto.randomUUID(), + } + + const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url") + const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url") + const signingInput = `${headerB64}.${payloadB64}` + + const sign = crypto.createSign("RSA-SHA384") + sign.update(signingInput) + const signature = sign.sign(privateKeyPem).toString("base64url") + return `${signingInput}.${signature}` +} + +async function fetchWithTimeout(url: string, init: RequestInit, fetchFn: typeof fetch): Promise { + const controller = new AbortController() + const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS) + try { + return await fetchFn(url, { ...init, signal: controller.signal }) + } finally { + clearTimeout(timer) + } +} + +async function getAccessToken(config: Config, fetchFn: typeof fetch): Promise { + const now = Date.now() + if (_tokenCache && _tokenCache.expiresAt > now) { + return _tokenCache.token + } + + const assertion = buildClientAssertion(config.clientId, config.tokenUrl, config.privateKeyPem) + const body = new URLSearchParams({ + grant_type: "client_credentials", + client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + client_assertion: assertion, + scope: config.scope, + }) + + const resp = await fetchWithTimeout( + config.tokenUrl, + { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: body.toString(), + }, + fetchFn, + ) + + if (!resp.ok) { + throw Object.assign(new Error("auth_failure"), { type: "auth_failure" }) + } + + const json = (await resp.json()) as { access_token?: string; expires_in?: number } + if (!json.access_token || !json.expires_in) { + throw Object.assign(new Error("auth_failure"), { type: "auth_failure" }) + } + + _tokenCache = { + token: json.access_token, + expiresAt: now + json.expires_in * 1000 - TOKEN_EXPIRY_BUFFER_MS, + } + + return _tokenCache.token +} + +function parsePatientIdentifier(patientId: string): { kind: "uuid" | "pid"; value: string } { + const normalized = patientId.trim() + if (FHIR_UUID_PATTERN.test(normalized)) { + return { kind: "uuid", value: normalized } + } + if (OPENEMR_PID_PATTERN.test(normalized)) { + return { kind: "pid", value: normalized } + } + throw Object.assign(new Error(`patient_id_format:${patientId}`), { + type: "patient_id_format", + patientId, + }) +} + +function validateNoteQuality(noteMarkdown: string): { ok: boolean; blocker?: OpenEMRStatusBlocker } { + const trimmed = noteMarkdown.trim() + const headerMatches = trimmed.match(/^##\s+/gm) ?? [] + if (trimmed.length < 120 || headerMatches.length < 2) { + return { + ok: false, + blocker: { + code: "OPENEMR_NOTE_TOO_SHORT", + message: "Note must be at least 120 characters and include at least 2 section headers (##).", + }, + } + } + return { ok: true } +} + +function buildDocumentUrl(base: string, pid: number, docId: string): string { + return `${base}/controller.php?document&retrieve&patient_id=${pid}&document_id=${docId}&` +} + +async function validatePatientPid(config: Config, pid: number, token: string, fetchFn: typeof fetch): Promise { + const resp = await fetchWithTimeout( + `${config.base}/apis/default/api/patient/${pid}`, + { + headers: { Authorization: `Bearer ${token}` }, + }, + fetchFn, + ) + if (!resp.ok) { + if (resp.status === 401 || resp.status === 403) { + throw Object.assign(new Error("openemr_access_denied"), { type: "openemr_access_denied" }) + } + throw Object.assign(new Error(`patient_not_found:${pid}`), { + type: "patient_not_found", + patientId: String(pid), + }) + } + const json = (await resp.json()) as { + data?: { id?: number } + } + if (!json.data?.id || !Number.isInteger(json.data.id)) { + throw Object.assign(new Error("patient_resolution_error"), { type: "patient_resolution_error" }) + } +} + +async function ensurePatientDocumentPathAccessible( + config: Config, + pid: number, + token: string, + fetchFn: typeof fetch, +): Promise { + const url = new URL(`${config.base}/apis/default/api/patient/${pid}/document`) + url.searchParams.set("path", config.documentPath) + const resp = await fetchWithTimeout( + url.toString(), + { + headers: { Authorization: `Bearer ${token}` }, + }, + fetchFn, + ) + if (resp.ok) return + if (resp.status === 404) { + throw Object.assign(new Error(`patient_not_found:${pid}`), { + type: "patient_not_found", + patientId: String(pid), + }) + } + if (resp.status === 401 || resp.status === 403) { + throw Object.assign(new Error("openemr_access_denied"), { type: "openemr_access_denied" }) + } + throw Object.assign(new Error(`fhir_error:patient_document_path_unavailable:${resp.status}`), { type: "fhir_error" }) +} + +async function ensurePatientResolvableForDocumentFlow( + config: Config, + pid: number, + token: string, + fetchFn: typeof fetch, +): Promise { + try { + await validatePatientPid(config, pid, token, fetchFn) + return + } catch (err) { + const type = (err as { type?: string }).type + if (type !== "patient_not_found" && type !== "user_auth_failure" && type !== "openemr_access_denied") { + throw err + } + } + + await ensurePatientDocumentPathAccessible(config, pid, token, fetchFn) +} + +async function ensureDocumentReferenceCreateSupported(config: Config, token: string, fetchFn: typeof fetch): Promise { + const now = Date.now() + if (_capabilityCache && _capabilityCache.expiresAt > now) { + if (_capabilityCache.supportsDocumentReferenceCreate) return + throw Object.assign(new Error("unsupported_endpoint"), { type: "unsupported_endpoint" }) + } + + const resp = await fetchWithTimeout( + `${config.base}/apis/default/fhir/metadata`, + { headers: { Authorization: `Bearer ${token}` } }, + fetchFn, + ) + + if (!resp.ok) { + throw Object.assign(new Error(`capability_error:${resp.status}`), { type: "capability_error" }) + } + + const json = (await resp.json()) as { + rest?: Array<{ + resource?: Array<{ + type?: string + interaction?: Array<{ code?: string }> + }> + }> + } + + const supportsCreate = Boolean( + json.rest?.some((rest) => + rest.resource?.some( + (resource) => + resource.type === "DocumentReference" && + resource.interaction?.some((interaction) => interaction.code === "create"), + ), + ), + ) + + _capabilityCache = { + supportsDocumentReferenceCreate: supportsCreate, + expiresAt: now + CAPABILITY_CACHE_MS, + } + + if (!supportsCreate) { + throw Object.assign(new Error("unsupported_endpoint"), { type: "unsupported_endpoint" }) + } +} + +async function validatePatient(config: Config, patientId: string, token: string, fetchFn: typeof fetch): Promise { + const resp = await fetchWithTimeout( + `${config.base}/apis/default/fhir/Patient/${patientId}`, + { headers: { Authorization: `Bearer ${token}` } }, + fetchFn, + ) + + if (!resp.ok) { + throw Object.assign(new Error(`patient_not_found:${patientId}`), { + type: "patient_not_found", + patientId, + }) + } +} + +async function getUserAccessTokenFromRefreshToken(config: Config, fetchFn: typeof fetch): Promise { + const now = Date.now() + if (_userTokenCache && _userTokenCache.expiresAt > now) { + return _userTokenCache.token + } + + const refreshToken = _userRefreshTokenOverride ?? config.userRefreshToken + const tryPasswordGrantFallback = async () => { + if (!config.passwordGrantFallbackEnabled || !config.username || !config.password) { + throw Object.assign(new Error("user_auth_failure"), { type: "user_auth_failure" }) + } + + const scopeParts = config.userScope.split(/\s+/).filter(Boolean) + if (!scopeParts.includes("offline_access")) scopeParts.unshift("offline_access") + if (!scopeParts.includes("openid")) scopeParts.unshift("openid") + if (!scopeParts.includes("api:oemr")) scopeParts.push("api:oemr") + + const assertion = buildClientAssertion(config.clientId, config.tokenUrl, config.privateKeyPem) + const passwordBody = new URLSearchParams({ + grant_type: "password", + client_id: config.clientId, + scope: scopeParts.join(" "), + user_role: config.userRole, + username: config.username, + password: config.password, + client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + client_assertion: assertion, + }) + const passwordResp = await fetchWithTimeout( + config.tokenUrl, + { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: passwordBody.toString(), + }, + fetchFn, + ) + + if (!passwordResp.ok) { + throw Object.assign(new Error("user_auth_failure"), { type: "user_auth_failure" }) + } + + const passwordJson = (await passwordResp.json()) as { + access_token?: string + expires_in?: number + refresh_token?: string + } + if (!passwordJson.access_token) { + throw Object.assign(new Error("user_auth_failure"), { type: "user_auth_failure" }) + } + + if (passwordJson.refresh_token) { + _userRefreshTokenOverride = passwordJson.refresh_token + await persistOpenEMRRefreshToken(passwordJson.refresh_token) + } + await recordOpenEMRRefreshAttempt(null) + + if (passwordJson.expires_in) { + _userTokenCache = { + token: passwordJson.access_token, + expiresAt: now + passwordJson.expires_in * 1000 - TOKEN_EXPIRY_BUFFER_MS, + } + } else { + _userTokenCache = null + } + return passwordJson.access_token + } + + if (!refreshToken) { + return tryPasswordGrantFallback() + } + await recordOpenEMRRefreshAttempt(null) + + const assertion = buildClientAssertion(config.clientId, config.tokenUrl, config.privateKeyPem) + const body = new URLSearchParams({ + grant_type: "refresh_token", + refresh_token: refreshToken, + scope: config.userScope, + client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + client_assertion: assertion, + }) + + const resp = await fetchWithTimeout( + config.tokenUrl, + { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: body.toString(), + }, + fetchFn, + ) + + if (!resp.ok) { + await recordOpenEMRRefreshAttempt("user_auth_failure") + return tryPasswordGrantFallback() + } + + const json = (await resp.json()) as { access_token?: string; expires_in?: number; refresh_token?: string } + if (!json.access_token) { + await recordOpenEMRRefreshAttempt("user_auth_failure") + return tryPasswordGrantFallback() + } + + if (json.refresh_token) { + _userRefreshTokenOverride = json.refresh_token + await persistOpenEMRRefreshToken(json.refresh_token) + } + await recordOpenEMRRefreshAttempt(null) + + if (json.expires_in) { + _userTokenCache = { + token: json.access_token, + expiresAt: now + json.expires_in * 1000 - TOKEN_EXPIRY_BUFFER_MS, + } + } else { + _userTokenCache = null + } + + return json.access_token +} + +async function resolvePatientPid(config: Config, patientUuid: string, token: string, fetchFn: typeof fetch): Promise { + const resp = await fetchWithTimeout( + `${config.base}/apis/default/api/patient/${patientUuid}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + }, + fetchFn, + ) + + if (!resp.ok) { + throw Object.assign(new Error(`patient_not_found:${patientUuid}`), { + type: "patient_not_found", + patientId: patientUuid, + }) + } + + const json = (await resp.json()) as { + data?: { + id?: number + } + } + const pid = json.data?.id + if (!pid || !Number.isInteger(pid)) { + throw Object.assign(new Error("patient_resolution_error"), { type: "patient_resolution_error" }) + } + return pid +} + +async function verifyUploadedDocument( + config: Config, + pid: number, + filename: string, + token: string, + fetchFn: typeof fetch, +): Promise<{ id: string; date: string | null } | null> { + const url = new URL(`${config.base}/apis/default/api/patient/${pid}/document`) + url.searchParams.set("path", config.documentPath) + + const resp = await fetchWithTimeout( + url.toString(), + { + headers: { Authorization: `Bearer ${token}` }, + }, + fetchFn, + ) + if (!resp.ok) return null + + const json = (await resp.json()) as Array<{ filename?: string; id?: number; date?: string }> + const latestMatch = json + .filter((item) => item.filename === filename && Number.isInteger(item.id)) + .reduce<{ filename?: string; id?: number; date?: string } | null>((best, item) => { + if (!best) return item + return (item.id as number) > (best.id as number) ? item : best + }, null) + return latestMatch?.id ? { id: String(latestMatch.id), date: latestMatch.date ?? null } : null +} + +async function verifyDocumentById( + config: Config, + pid: number, + documentId: string, + token: string, + fetchFn: typeof fetch, +): Promise<{ found: boolean; date: string | null }> { + const url = new URL(`${config.base}/apis/default/api/patient/${pid}/document`) + url.searchParams.set("path", config.documentPath) + const resp = await fetchWithTimeout( + url.toString(), + { + headers: { Authorization: `Bearer ${token}` }, + }, + fetchFn, + ) + if (!resp.ok) return { found: false, date: null } + const json = (await resp.json()) as Array<{ id?: number; date?: string }> + const match = json.find((item) => String(item.id) === documentId) + return { found: Boolean(match), date: match?.date ?? null } +} + +async function uploadNoteAsPatientDocument( + config: Config, + params: PushParams, + pid: number, + token: string, + fetchFn: typeof fetch, +): Promise { + const filename = "openscribe-note-final.txt" + const url = new URL(`${config.base}/apis/default/api/patient/${pid}/document`) + url.searchParams.set("path", config.documentPath) + + const form = new FormData() + form.append("document", new Blob([params.noteMarkdown], { type: "text/plain" }), filename) + + const resp = await fetchWithTimeout( + url.toString(), + { + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + body: form, + }, + fetchFn, + ) + + if (resp.ok) { + const verifiedId = await verifyUploadedDocument(config, pid, filename, token, fetchFn) + return verifiedId?.id ?? filename + } + + const text = await resp.text() + const boolBugSignature = "bool given" + if (resp.status === 500 && text.includes(boolBugSignature)) { + const verifiedId = await verifyUploadedDocument(config, pid, filename, token, fetchFn) + if (verifiedId) return verifiedId.id + throw Object.assign(new Error("upload_verification_failed"), { type: "upload_verification_failed" }) + } + + throw Object.assign(new Error(`fhir_error:${text}`), { type: "fhir_error" }) +} + +async function createDocumentReference( + config: Config, + params: PushParams, + token: string, + fetchFn: typeof fetch, +): Promise { + const noteBase64 = Buffer.from(params.noteMarkdown, "utf8").toString("base64") + const resource = { + resourceType: "DocumentReference", + status: "current", + type: { + coding: [ + { + system: "http://loinc.org", + code: "34109-9", + display: "Note", + }, + ], + }, + category: [ + { + coding: [ + { + system: "http://hl7.org/fhir/us/core/CodeSystem/us-core-documentreference-category", + code: "clinical-note", + display: "Clinical Note", + }, + ], + }, + ], + subject: { reference: `Patient/${params.patientId}` }, + date: new Date().toISOString(), + description: params.visitReason, + content: [ + { + attachment: { + contentType: "text/markdown", + data: noteBase64, + title: `Clinical Note — ${params.patientName}`, + }, + }, + ], + } + + const resp = await fetchWithTimeout( + `${config.base}/apis/default/fhir/DocumentReference`, + { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/fhir+json", + }, + body: JSON.stringify(resource), + }, + fetchFn, + ) + + if (!resp.ok) { + const text = await resp.text() + throw Object.assign(new Error(`fhir_error:${text}`), { type: "fhir_error" }) + } + + const created = (await resp.json()) as { id?: string } + if (!created.id) { + throw Object.assign(new Error("fhir_error:missing id"), { type: "fhir_error" }) + } + return created.id +} + +async function pushViaPatientDocumentFlow( + config: Config, + params: PushParams, + patientIdentifier: { kind: "uuid" | "pid"; value: string }, + token: string, + fetchFn: typeof fetch, +): Promise> { + const pid = + patientIdentifier.kind === "pid" + ? Number(patientIdentifier.value) + : await resolvePatientPid(config, patientIdentifier.value, token, fetchFn) + await ensurePatientResolvableForDocumentFlow(config, pid, token, fetchFn) + const id = await uploadNoteAsPatientDocument(config, params, pid, token, fetchFn) + const verification = await verifyDocumentById(config, pid, id, token, fetchFn) + if (!verification.found) { + throw Object.assign(new Error("upload_verification_failed"), { type: "upload_verification_failed" }) + } + const uploadedAt = verification.date ?? new Date().toISOString() + return { + success: true, + id, + uploadedAt, + verifiedPreview: params.noteMarkdown.slice(0, 200), + verifiedLength: params.noteMarkdown.length, + openEMRDocumentUrl: buildDocumentUrl(config.base, pid, id), + } +} + +export async function getOpenEMRPushStatus( + params: Pick & { documentId?: string }, + fetchFn: typeof fetch = fetch, +): Promise { + const config = await getConfig() + const blockers: OpenEMRStatusBlocker[] = [] + const noteCheck = validateNoteQuality(params.noteMarkdown) + const note_ok = noteCheck.ok + if (!noteCheck.ok && noteCheck.blocker) blockers.push(noteCheck.blocker) + + let patient_id_valid = false + let patient_resolvable = false + let auth_ok = false + let authTokenForVerification: string | null = null + let patientIdentifier: { kind: "uuid" | "pid"; value: string } | null = null + let resolvedPid: number | null = null + + if (!config) { + blockers.push({ + code: "OPENEMR_NOT_CONFIGURED", + message: "OpenEMR is not configured. Set OpenEMR environment variables and restart OpenScribe.", + }) + return { + configured: false, + auth_ok: false, + patient_id_valid: false, + patient_resolvable: false, + note_ok, + can_push: false, + document_verified: null, + blockers, + token_state: { + has_token: false, + source: "none", + last_refresh_attempt: null, + last_refresh_error: null, + }, + } + } + + try { + patientIdentifier = parsePatientIdentifier(params.patientId) + patient_id_valid = true + } catch { + blockers.push({ + code: "OPENEMR_PATIENT_ID_INVALID", + message: "Patient ID must be a numeric PID (for example: 3) or a valid FHIR UUID.", + }) + } + + const tryServiceAuth = async () => { + const serviceToken = await getAccessToken(config, fetchFn) + auth_ok = true + authTokenForVerification = serviceToken + if (patientIdentifier) { + if (patientIdentifier.kind === "pid") { + resolvedPid = Number(patientIdentifier.value) + await ensurePatientResolvableForDocumentFlow(config, resolvedPid, serviceToken, fetchFn) + } else { + resolvedPid = await resolvePatientPid(config, patientIdentifier.value, serviceToken, fetchFn) + } + patient_resolvable = true + } + } + const tryUserAuth = async () => { + if (!config.userRefreshToken) { + throw Object.assign(new Error("user_refresh_token_missing"), { type: "user_refresh_token_missing" }) + } + const userToken = await getUserAccessTokenFromRefreshToken(config, fetchFn) + auth_ok = true + authTokenForVerification = userToken + if (patientIdentifier) { + if (patientIdentifier.kind === "pid") { + resolvedPid = Number(patientIdentifier.value) + await ensurePatientResolvableForDocumentFlow(config, resolvedPid, userToken, fetchFn) + } else { + resolvedPid = await resolvePatientPid(config, patientIdentifier.value, userToken, fetchFn) + } + patient_resolvable = true + } + } + + const hasUserRefreshToken = Boolean(config.userRefreshToken) + const attempts: Array<() => Promise> = + config.pushAuthMode === "user_first" + ? hasUserRefreshToken + ? [tryUserAuth, tryServiceAuth] + : [tryServiceAuth] + : [tryServiceAuth] + let lastAuthError: { message: string; code?: string } | null = null + for (const attempt of attempts) { + if (patient_resolvable) break + try { + await attempt() + } catch (err) { + lastAuthError = mapError(err, config.base, params.patientId) + } + } + if (!patient_resolvable && lastAuthError) { + blockers.push({ + code: lastAuthError.code ?? "OPENEMR_AUTH_INVALID", + message: lastAuthError.message, + }) + } + + let document_verified: boolean | null = null + if (params.documentId && auth_ok && patient_resolvable && resolvedPid && authTokenForVerification) { + try { + const verification = await verifyDocumentById( + config, + resolvedPid, + params.documentId, + authTokenForVerification, + fetchFn, + ) + document_verified = verification.found + if (!verification.found) { + blockers.push({ + code: "OPENEMR_UPLOAD_VERIFY_FAILED", + message: `OpenEMR document ${params.documentId} was not found for this patient.`, + }) + } + } catch { + document_verified = false + blockers.push({ + code: "OPENEMR_UPLOAD_VERIFY_FAILED", + message: "Could not verify document existence in OpenEMR.", + }) + } + } + + return { + configured: true, + auth_ok, + patient_id_valid, + patient_resolvable, + note_ok, + can_push: Boolean(auth_ok && patient_id_valid && patient_resolvable && note_ok), + document_verified, + blockers, + token_state: { + has_token: config.tokenState.hasToken, + source: config.tokenState.source, + last_refresh_attempt: config.tokenState.lastRefreshAttempt, + last_refresh_error: config.tokenState.lastRefreshError, + }, + } +} + +export async function setupOpenEMRAuth(fetchFn: typeof fetch = fetch): Promise { + const config = await getConfig() + if (!config) { + return { + success: false, + error: "OpenEMR is not configured. Set OpenEMR environment variables and restart OpenScribe.", + code: "OPENEMR_NOT_CONFIGURED", + } + } + + try { + if (config.pushAuthMode === "user_first") { + await getUserAccessTokenFromRefreshToken(config, fetchFn) + return { + success: true, + message: "OpenEMR user auth is now ready.", + mode: "user", + } + } + + await getAccessToken(config, fetchFn) + return { + success: true, + message: "OpenEMR service auth is now ready.", + mode: "service", + } + } catch (err) { + const mapped = mapError(err, config.base, "") + return { + success: false, + error: mapped.message, + code: mapped.code, + } + } +} + +export async function pushNoteToOpenEMR(params: PushParams, fetchFn: typeof fetch = fetch): Promise { + const config = await getConfig() + if (!config) { + return { success: false, error: "OpenEMR is not configured.", code: "OPENEMR_NOT_CONFIGURED" } + } + + const noteCheck = validateNoteQuality(params.noteMarkdown) + if (!noteCheck.ok) { + return { + success: false, + error: noteCheck.blocker?.message ?? "Note quality requirements not met.", + code: "OPENEMR_NOTE_TOO_SHORT", + } + } + + try { + const patientIdentifier = parsePatientIdentifier(params.patientId) + const serviceAttempt = async () => { + const serviceToken = await getAccessToken(config, fetchFn) + return pushViaPatientDocumentFlow(config, params, patientIdentifier, serviceToken, fetchFn) + } + const userAttempt = async () => { + const userToken = await getUserAccessTokenFromRefreshToken(config, fetchFn) + return pushViaPatientDocumentFlow(config, params, patientIdentifier, userToken, fetchFn) + } + const hasUserRefreshToken = Boolean(config.userRefreshToken) + const attempts: Array<() => Promise>> = + config.pushAuthMode === "user_first" + ? hasUserRefreshToken + ? [userAttempt, serviceAttempt] + : [serviceAttempt] + : [serviceAttempt] + let lastError: unknown = null + for (const attempt of attempts) { + try { + return await attempt() + } catch (err) { + lastError = err + } + } + + const lastErrorType = (lastError as { type?: string } | null)?.type + if ( + patientIdentifier.kind === "uuid" && + lastErrorType !== "auth_failure" && + lastErrorType !== "user_auth_failure" + ) { + const systemToken = await getAccessToken(config, fetchFn) + await ensureDocumentReferenceCreateSupported(config, systemToken, fetchFn) + await validatePatient(config, patientIdentifier.value, systemToken, fetchFn) + const id = await createDocumentReference(config, params, systemToken, fetchFn) + return { + success: true, + id, + uploadedAt: new Date().toISOString(), + verifiedPreview: params.noteMarkdown.slice(0, 200), + verifiedLength: params.noteMarkdown.length, + openEMRDocumentUrl: null, + } + } + + throw lastError ?? Object.assign(new Error("push_failed"), { type: "fhir_error" }) + } catch (err: unknown) { + const mapped = mapError(err, config.base, params.patientId) + return { success: false, error: mapped.message, code: mapped.code } + } +} + +function mapError(err: unknown, baseUrl: string, patientId: string): { message: string; code?: string } { + if (!(err instanceof Error)) return { message: "Unexpected error." } + + if (err.name === "AbortError") { + return { + message: `OpenEMR request timed out after ${FETCH_TIMEOUT_MS / 1000}s.`, + code: "OPENEMR_TIMEOUT", + } + } + + const code = (err as NodeJS.ErrnoException).code + if (code === "ECONNREFUSED" || code === "ENOTFOUND") { + return { + message: `Could not reach OpenEMR at ${baseUrl}. Check that the server is running.`, + code: "OPENEMR_NETWORK_ERROR", + } + } + + const type = (err as { type?: string }).type + if (type === "auth_failure") { + return { + message: "OpenEMR authentication failed. Check OPENEMR_CLIENT_ID and OPENEMR_JWT_PRIVATE_KEY_PEM.", + code: "OPENEMR_AUTH_INVALID", + } + } + if (type === "openemr_access_denied") { + return { + message: + "OpenEMR token does not have required patient/document API permissions. Ensure scopes include system/Patient.read and system/DocumentReference.write, or switch to OPENEMR_PUSH_AUTH_MODE=user_first with a valid refresh token.", + code: "OPENEMR_AUTH_INVALID", + } + } + if (type === "user_refresh_token_missing") { + return { + message: "OpenEMR user OAuth is enabled but no refresh token is available. Reconnect OpenEMR.", + code: "OPENEMR_AUTH_INVALID", + } + } + if (type === "user_auth_failure") { + return { + message: "OpenEMR user token refresh failed. Re-authorize and retry push.", + code: "OPENEMR_AUTH_EXPIRED", + } + } + if (type === "patient_id_format") { + return { + message: "OpenEMR Patient ID must be a numeric PID (for example: 3) or a FHIR UUID.", + code: "OPENEMR_PATIENT_ID_INVALID", + } + } + if (type === "patient_id_format_uuid_required") { + return { + message: "This OpenEMR mode requires a FHIR UUID patient identifier.", + code: "OPENEMR_PATIENT_ID_INVALID", + } + } + if (type === "patient_not_found") { + return { + message: `Patient ID ${patientId} was not found in OpenEMR. Verify the ID and try again.`, + code: "OPENEMR_PATIENT_NOT_FOUND", + } + } + if (type === "patient_resolution_error") { + return { + message: "OpenEMR returned an invalid patient record while resolving UUID to PID.", + code: "OPENEMR_PATIENT_NOT_FOUND", + } + } + if (type === "upload_verification_failed") { + return { + message: "OpenEMR returned an ambiguous upload response and verification failed. Check document list in OpenEMR.", + code: "OPENEMR_UPLOAD_VERIFY_FAILED", + } + } + if (type === "unsupported_endpoint") { + return { + message: + "This OpenEMR instance does not support FHIR DocumentReference create. Enable a server that supports POST /fhir/DocumentReference.", + code: "OPENEMR_UNSUPPORTED", + } + } + if (type === "fhir_error") { + return { + message: `OpenEMR push failed: ${err.message.replace("fhir_error:", "")}`, + code: "OPENEMR_PUSH_FAILED", + } + } + + return { message: `OpenEMR push failed: ${err.message}`, code: "OPENEMR_PUSH_FAILED" } +} diff --git a/apps/web/src/lib/openemr-push-handler.ts b/apps/web/src/lib/openemr-push-handler.ts new file mode 100644 index 0000000..c90a594 --- /dev/null +++ b/apps/web/src/lib/openemr-push-handler.ts @@ -0,0 +1,86 @@ +/** + * Pure request handler for POST /api/integrations/openemr/push + * + * Extracted from the Next.js route so it can be tested without importing + * next/server (which cannot be compiled by the NodeNext test runner). + * + * Trust boundaries enforced here: + * ① Auth identity check — rejects unauthenticated callers with 401 + * ② Input validation — rejects missing patientId/noteMarkdown with 400 + * ③ Identity binding — all 4 required fields forwarded to pushFn unchanged + * + * The route (route.ts) is a thin wrapper that calls this function. + */ + +import type { PushParams, PushResult } from "./openemr-client.js" + +export interface AuthContext { + isAuthenticated: boolean +} + +export type PushFn = (params: PushParams) => Promise + +export interface HandlerResult { + status: number + json: unknown +} + +/** + * Handle a push request. + * + * @param auth Authentication context (from requireAuthenticatedUser) + * @param body Parsed request body (unknown — validated inside) + * @param pushFn Function that performs the actual OpenEMR push (injectable for testing) + */ +export async function handlePushRequest( + auth: AuthContext, + body: unknown, + pushFn: PushFn +): Promise { + // Boundary ①: reject unauthenticated requests + if (!auth.isAuthenticated) { + return { status: 401, json: { success: false, error: "Unauthorized" } } + } + + // Boundary ②: validate required fields + if (!body || typeof body !== "object") { + return { status: 400, json: { success: false, error: "Request body is required" } } + } + + const b = body as Record + + if (!b.patientId || typeof b.patientId !== "string") { + return { status: 400, json: { success: false, error: "patientId is required" } } + } + + if (!b.noteMarkdown || typeof b.noteMarkdown !== "string") { + return { status: 400, json: { success: false, error: "noteMarkdown is required" } } + } + + // Boundary ③: forward fields verbatim to pushFn + const params: PushParams = { + patientId: b.patientId, + noteMarkdown: b.noteMarkdown, + patientName: typeof b.patientName === "string" ? b.patientName : "", + visitReason: typeof b.visitReason === "string" ? b.visitReason : "", + encounterId: typeof b.encounterId === "string" ? b.encounterId : "", + } + + const result = await pushFn(params) + + if (result.success) { + return { + status: 200, + json: { + success: true, + id: result.id, + uploadedAt: result.uploadedAt, + verifiedPreview: result.verifiedPreview, + verifiedLength: result.verifiedLength, + openEMRDocumentUrl: result.openEMRDocumentUrl, + }, + } + } else { + return { status: 500, json: { success: false, error: result.error, code: result.code } } + } +} diff --git a/apps/web/src/lib/redis.ts b/apps/web/src/lib/redis.ts new file mode 100644 index 0000000..3d5f3dc --- /dev/null +++ b/apps/web/src/lib/redis.ts @@ -0,0 +1,29 @@ +import Redis from "ioredis" +import { isHipaaHostedMode } from "./hipaa-config" + +let client: Redis | null = null + +export function getRedisClient(): Redis { + if (client) return client + + const url = (process.env.REDIS_URL || "").trim() + if (!url) { + if (!isHipaaHostedMode()) { + throw new Error("REDIS_URL is required only in HIPAA hosted mode") + } + throw new Error("Missing REDIS_URL") + } + + client = new Redis(url, { + maxRetriesPerRequest: 3, + enableReadyCheck: true, + lazyConnect: true, + }) + + return client +} + +export async function ensureRedisConnection(redis: Redis): Promise { + if (redis.status === "ready") return + await redis.connect() +} diff --git a/apps/web/src/lib/server-logger.ts b/apps/web/src/lib/server-logger.ts new file mode 100644 index 0000000..fbc2b86 --- /dev/null +++ b/apps/web/src/lib/server-logger.ts @@ -0,0 +1,30 @@ +type LogLevel = "info" | "warn" | "error" + +function toSafeMetadata(metadata?: Record): Record { + if (!metadata) return {} + const redactedKeys = new Set(["transcript", "note", "patient_name", "patient_id", "audio", "file", "text"]) + const safe: Record = {} + for (const [key, value] of Object.entries(metadata)) { + safe[key] = redactedKeys.has(key.toLowerCase()) ? "[REDACTED]" : value + } + return safe +} + +export function logServer(level: LogLevel, message: string, metadata?: Record) { + const payload = { + level, + message, + metadata: toSafeMetadata(metadata), + ts: new Date().toISOString(), + } + + if (level === "error") { + console.error(JSON.stringify(payload)) + return + } + if (level === "warn") { + console.warn(JSON.stringify(payload)) + return + } + console.log(JSON.stringify(payload)) +} diff --git a/apps/web/src/lib/transcription-store.ts b/apps/web/src/lib/transcription-store.ts new file mode 100644 index 0000000..fd5f1d2 --- /dev/null +++ b/apps/web/src/lib/transcription-store.ts @@ -0,0 +1,293 @@ +import type { PipelineError } from "@pipeline-errors" +import { transcriptionSessionStore, type TranscriptionEvent } from "@transcript-assembly" +import { toPipelineError } from "@pipeline-errors" +import { getRedisClient, ensureRedisConnection } from "./redis" +import { isHipaaHostedMode } from "./hipaa-config" + +type TranscriptionStatus = "recording" | "finalizing" | "completed" | "error" + +type SegmentInput = { + seqNo: number + startMs: number + endMs: number + durationMs: number + overlapMs: number + transcript: string +} + +type SessionSnapshot = { + status: TranscriptionStatus + stitchedText: string + finalTranscript: string | null +} + +const SESSION_TTL_SECONDS = 60 * 60 + +function normalizeToken(token: string): string { + return token + .toLowerCase() + .replace(/^[^A-Za-z0-9]+/g, "") + .replace(/[^A-Za-z0-9]+$/g, "") +} + +function trimOverlapText(previousText: string, nextText: string): string { + if (!previousText) return nextText + + const previousTokens = previousText.split(/\s+/).filter(Boolean) + const nextTokens = nextText.split(/\s+/).filter(Boolean) + const maxComparable = Math.min(20, previousTokens.length, nextTokens.length) + + for (let overlap = maxComparable; overlap > 0; overlap--) { + const prevSlice = previousTokens.slice(-overlap).map(normalizeToken) + const nextSlice = nextTokens.slice(0, overlap).map(normalizeToken) + const matches = prevSlice.every((token, idx) => token && token === nextSlice[idx]) + if (matches) { + return nextTokens.slice(overlap).join(" ") + } + } + + return nextText +} + +function keys(sessionId: string) { + return { + meta: `openscribe:tx:${sessionId}:meta`, + segments: `openscribe:tx:${sessionId}:segments`, + channel: `openscribe:tx:${sessionId}:events`, + } +} + +async function ensureOwner(sessionId: string, userId?: string): Promise { + if (!isHipaaHostedMode()) return + if (!userId) throw new Error("Missing user owner") + + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta } = keys(sessionId) + + const currentOwner = await redis.hget(meta, "ownerUserId") + if (!currentOwner) { + const tx = redis.multi() + tx.hsetnx(meta, "ownerUserId", userId) + tx.hsetnx(meta, "status", "recording") + tx.hsetnx(meta, "stitchedText", "") + tx.expire(meta, SESSION_TTL_SECONDS) + await tx.exec() + return + } + if (currentOwner !== userId) { + throw new Error("Unauthorized session access") + } + await redis.expire(meta, SESSION_TTL_SECONDS) +} + +async function getSnapshot(sessionId: string): Promise { + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta } = keys(sessionId) + const data = await redis.hgetall(meta) + return { + status: ((data.status as TranscriptionStatus) || "recording") as TranscriptionStatus, + stitchedText: data.stitchedText || "", + finalTranscript: data.finalTranscript || null, + } +} + +async function publishEvent(sessionId: string, event: TranscriptionEvent): Promise { + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { channel } = keys(sessionId) + await redis.publish(channel, JSON.stringify(event)) +} + +async function addSegmentDistributed(sessionId: string, segment: SegmentInput, userId?: string): Promise { + await ensureOwner(sessionId, userId) + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta, segments } = keys(sessionId) + + await redis.hset(segments, String(segment.seqNo), JSON.stringify(segment)) + + const rawSegments = await redis.hgetall(segments) + const ordered = Object.values(rawSegments) + .map((raw) => JSON.parse(raw) as SegmentInput) + .sort((a, b) => a.seqNo - b.seqNo) + + let stitched = "" + for (const seg of ordered) { + const text = trimOverlapText(stitched, seg.transcript) + stitched = stitched ? `${stitched} ${text}` : text + } + stitched = stitched.trim() + + const tx = redis.multi() + tx.hset(meta, "status", "recording", "stitchedText", stitched) + tx.expire(meta, SESSION_TTL_SECONDS) + tx.expire(segments, SESSION_TTL_SECONDS) + await tx.exec() + + await publishEvent(sessionId, { + event: "segment", + data: { + session_id: sessionId, + seq_no: segment.seqNo, + start_ms: segment.startMs, + end_ms: segment.endMs, + duration_ms: segment.durationMs, + overlap_ms: segment.overlapMs, + transcript: segment.transcript, + stitched_text: stitched, + }, + }) +} + +async function setStatusDistributed(sessionId: string, status: TranscriptionStatus, userId?: string): Promise { + await ensureOwner(sessionId, userId) + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta } = keys(sessionId) + + await redis.hset(meta, "status", status) + await redis.expire(meta, SESSION_TTL_SECONDS) + const snapshot = await getSnapshot(sessionId) + + await publishEvent(sessionId, { + event: "status", + data: { + session_id: sessionId, + status, + stitched_text: snapshot.stitchedText, + final_transcript: snapshot.finalTranscript, + }, + }) +} + +async function setFinalTranscriptDistributed(sessionId: string, transcript: string, userId?: string): Promise { + await ensureOwner(sessionId, userId) + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta, segments } = keys(sessionId) + + const tx = redis.multi() + tx.hset(meta, "status", "completed", "finalTranscript", transcript) + tx.expire(meta, SESSION_TTL_SECONDS) + tx.expire(segments, SESSION_TTL_SECONDS) + await tx.exec() + + await publishEvent(sessionId, { + event: "final", + data: { + session_id: sessionId, + final_transcript: transcript, + }, + }) +} + +async function emitErrorDistributed(sessionId: string, error: PipelineError | Error | unknown, userId?: string): Promise { + await ensureOwner(sessionId, userId) + const redis = getRedisClient() + await ensureRedisConnection(redis) + const { meta } = keys(sessionId) + + const normalizedError = toPipelineError(error, { + code: "assembly_error", + message: "Failed to assemble transcript", + recoverable: true, + }) + + await redis.hset(meta, "status", "error") + await redis.expire(meta, SESSION_TTL_SECONDS) + + await publishEvent(sessionId, { + event: "error", + data: { + session_id: sessionId, + code: normalizedError.code, + message: normalizedError.message, + recoverable: normalizedError.recoverable, + details: normalizedError.details, + }, + }) +} + +async function subscribeDistributed( + sessionId: string, + userId: string | undefined, + listener: (event: TranscriptionEvent) => void, +): Promise<() => void> { + await ensureOwner(sessionId, userId) + const snapshot = await getSnapshot(sessionId) + + listener({ + event: "status", + data: { + session_id: sessionId, + status: snapshot.status, + stitched_text: snapshot.stitchedText, + final_transcript: snapshot.finalTranscript, + }, + }) + + const redis = getRedisClient() + await ensureRedisConnection(redis) + const subscriber = redis.duplicate() + await ensureRedisConnection(subscriber) + const { channel } = keys(sessionId) + + await subscriber.subscribe(channel) + subscriber.on("message", (_channel, payload) => { + try { + listener(JSON.parse(payload) as TranscriptionEvent) + } catch { + // ignore malformed events + } + }) + + return () => { + void subscriber.unsubscribe(channel) + void subscriber.quit() + } +} + +export async function addTranscriptionSegment(sessionId: string, segment: SegmentInput, userId?: string): Promise { + if (!isHipaaHostedMode()) { + transcriptionSessionStore.addSegment(sessionId, segment, userId) + return + } + await addSegmentDistributed(sessionId, segment, userId) +} + +export async function setTranscriptionStatus(sessionId: string, status: TranscriptionStatus, userId?: string): Promise { + if (!isHipaaHostedMode()) { + transcriptionSessionStore.setStatus(sessionId, status, userId) + return + } + await setStatusDistributed(sessionId, status, userId) +} + +export async function setTranscriptionFinal(sessionId: string, transcript: string, userId?: string): Promise { + if (!isHipaaHostedMode()) { + transcriptionSessionStore.setFinalTranscript(sessionId, transcript, userId) + return + } + await setFinalTranscriptDistributed(sessionId, transcript, userId) +} + +export async function emitTranscriptionError(sessionId: string, error: PipelineError | Error | unknown, userId?: string): Promise { + if (!isHipaaHostedMode()) { + transcriptionSessionStore.emitError(sessionId, error, userId) + return + } + await emitErrorDistributed(sessionId, error, userId) +} + +export async function subscribeTranscriptionEvents( + sessionId: string, + userId: string | undefined, + listener: (event: TranscriptionEvent) => void, +): Promise<() => void> { + if (!isHipaaHostedMode()) { + return transcriptionSessionStore.subscribe(sessionId, listener, userId) + } + return subscribeDistributed(sessionId, userId, listener) +} diff --git a/apps/web/src/types/next-auth.d.ts b/apps/web/src/types/next-auth.d.ts new file mode 100644 index 0000000..da4252e --- /dev/null +++ b/apps/web/src/types/next-auth.d.ts @@ -0,0 +1,9 @@ +import type { DefaultSession } from "next-auth" + +declare module "next-auth" { + interface Session { + user?: DefaultSession["user"] & { + id?: string + } + } +} diff --git a/apps/web/tsconfig.tsbuildinfo b/apps/web/tsconfig.tsbuildinfo index 01a5acc..5195639 100644 --- a/apps/web/tsconfig.tsbuildinfo +++ b/apps/web/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.float16.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.error.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/css.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/macro.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/style.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/global.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/get-page-files.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/assert.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/assert/strict.d.ts","../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/header.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/readable.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/file.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/fetch.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/formdata.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/connector.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/client.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/errors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/dispatcher.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/global-origin.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/pool-stats.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/handlers.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/balanced-pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-client.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-errors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/proxy-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/retry-handler.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/retry-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/api.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/util.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/cookies.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/patch.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/websocket.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/eventsource.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/filereader.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/content-type.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/cache.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/interceptors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/index.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/globals.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/async_hooks.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/buffer.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/child_process.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/cluster.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/console.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/constants.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/crypto.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dgram.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dns.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dns/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/domain.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dom-events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/fs.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/fs/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/http.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/http2.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/https.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/inspector.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/module.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/net.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/os.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/path.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/perf_hooks.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/process.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/punycode.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/querystring.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/readline.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/readline/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/repl.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/sea.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/consumers.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/web.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/string_decoder.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/test.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/timers.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/timers/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/tls.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/trace_events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/tty.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/url.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/util.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/v8.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/vm.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/wasi.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/worker_threads.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/zlib.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/globals.global.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/index.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/canary.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/experimental.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/index.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/canary.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/experimental.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/fallback.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/webpack/webpack.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/entry-constants.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/constants.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/load-custom-routes.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/body-streams.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/cache-control.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/setup-exception-listeners.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/worker.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/constants.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/bundler.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/app-router-headers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/flight-data-helpers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/app-router-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/static-paths/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/rendering-mode.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/require-hook.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/experimental/ppr.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/page-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/analysis/get-page-static-info.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-polyfill-crypto.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-baseline.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/random.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/date.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/page-extensions-type.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-kind.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/cache-handlers/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/response-cache/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/render-result.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/instrumentation/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/coalesced-function.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/trace.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/shared.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/load-jsconfig.d.ts","../../node_modules/.pnpm/@next+env@16.0.3/node_modules/@next/env/dist/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/telemetry/storage.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/build-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/bloom-filter.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack-config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/swc/generated-native.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/swc/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/parse-version-info.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/shared/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/parse-stack.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/server/shared.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/jsx-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/debug-channel.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/hot-reloader-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/i18n-provider.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/next-url.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/cookies.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/request.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/builtin-request-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/response.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-http/node.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/mitt.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/with-router.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/router.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/route-loader.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/page-loader.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/router.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/pages.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/module.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/deep-readonly.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/render.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/response-cache/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matchers/route-matcher.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/normalizer.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/suffix.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/rsc.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/prefetch-rsc.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/next-data.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/async-callback-set.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","../../node_modules/.pnpm/sharp@0.34.5/node_modules/sharp/lib/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/image-optimizer.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/next-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/lru-cache.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/dev-bundler-service.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/use-cache/cache-life.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/static-paths-worker.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/next-dev-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/next.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/render-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/route-module.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/load-components.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/adapter.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/app-dir-module.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/cache-signal.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/fallback-params.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/lazy-result.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/implicit-tags.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/staged-rendering.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/app-render.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/error-boundary.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/layout-router.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/render-from-template-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/client-page.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/client-segment.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/search-params.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/hooks-server-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/extra-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/resolvers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/icons.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/metadata.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/framework/boundary-components.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/preloads.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/postpone.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/taint.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/collect-segment-data.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/entry-base.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/app-page.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/jsx-dev-runtime.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/compiler-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/client.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/module.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/async-storage/work-store.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/http.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect-status-code.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect-error.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/app-route.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/module.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/app/app-segments.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/utils.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/result.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/routes/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/worker.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/worker.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/incremental-cache/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/after.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/after-context.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/params.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matches/route-match.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request-meta.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/cli/next-test.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/config-shared.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-http/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/api-utils/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/adapter/build-complete.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/utils.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_app.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/app.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/use-cache/cache-tag.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/cache.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_document.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/document.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/dynamic.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dynamic.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_error.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/error.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/head.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/head.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/cookies.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/headers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/draft-mode.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/headers.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/get-img-props.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/image-component.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-external.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/image.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/link.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/link.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/readonly-url-search-params.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unrecognized-action-error.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/not-found.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/forbidden.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unauthorized.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unstable-rethrow.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/navigation.react-server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/navigation.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/navigation.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/router.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/script.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/script.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/image-response.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/connection.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/server.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types/global.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types/compiled.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/index.d.ts","../../node_modules/.pnpm/next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/image-types/global.d.ts","./.next/dev/types/routes.d.ts","./next-env.d.ts","./src/middleware.ts","../../packages/pipeline/note-core/src/clinical-models/clinical-note.ts","../../packages/pipeline/note-core/src/clinical-models/markdown-note.ts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/builtin-types.d.mts","../../node_modules/.pnpm/node_modules/undici-types/index.d.ts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/types.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/headers.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/shim-types.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/streaming.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/request-options.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/utils/log.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/error.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/parse.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/api-promise.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/pagination.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/uploads.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/to-file.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/uploads.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/shared.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/resource.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/files.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/models.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/beta-parser.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/error.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/betamessagestream.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/decoders/line.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/batches.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/messagestream.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/versions.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/skills.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/betarunnabletool.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/compactioncontrol.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/betatoolrunner.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/beta.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/completions.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/models.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/client.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/index.d.mts","../../packages/llm/src/prompts/clinical-note/templates/index.ts","../../packages/llm/src/prompts/clinical-note/v1.ts","../../packages/llm/src/prompts/clinical-note/index.ts","../../packages/llm/src/prompts/index.ts","../../packages/llm/src/index.ts","../../packages/storage/src/types.ts","../../packages/storage/src/secure-storage.ts","../../packages/storage/src/encounters.ts","../../packages/storage/src/debug-logger.ts","../../packages/storage/src/audit-log.ts","../../packages/storage/src/preferences.ts","../../packages/storage/src/api-keys.ts","../../packages/storage/src/index.ts","../../packages/pipeline/note-core/src/note-generator.ts","../../packages/pipeline/note-core/src/index.ts","../../packages/storage/src/server-api-keys.ts","./src/app/actions.ts","./src/app/api/settings/api-keys/route.ts","../../packages/pipeline/transcribe/src/core/wav.ts","../../packages/pipeline/transcribe/src/hooks/segment-upload-controller.ts","../../packages/pipeline/transcribe/src/hooks/use-segment-upload.ts","../../packages/pipeline/transcribe/src/providers/whisper-transcriber.ts","../../packages/pipeline/transcribe/src/index.ts","../../packages/pipeline/assemble/src/session-store.ts","../../packages/pipeline/assemble/src/index.ts","./src/app/api/transcription/final/route.ts","./src/app/api/transcription/segment/route.ts","./src/app/api/transcription/stream/[sessionid]/route.ts","./src/types/desktop.d.ts","../../node_modules/.pnpm/@vercel+analytics@1.5.0_next@16.0.3_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@vercel/analytics/dist/next/index.d.mts","./src/app/layout.tsx","../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/clsx.d.mts","../../node_modules/.pnpm/tailwind-merge@2.5.5/node_modules/tailwind-merge/dist/types.d.ts","../../packages/ui/src/lib/utils/cn.ts","../../packages/ui/src/lib/utils/index.ts","../../packages/ui/src/lib/ui/input.tsx","../../node_modules/.pnpm/@radix-ui+react-slot@1.1.1_@types+react@19.0.0_react@19.2.0/node_modules/@radix-ui/react-slot/dist/index.d.mts","../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/types.d.ts","../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.d.ts","../../packages/ui/src/lib/ui/button.tsx","../../node_modules/.pnpm/@radix-ui+react-context@1.1.1_@types+react@19.0.0_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.d.mts","../../node_modules/.pnpm/@radix-ui+react-primitive@2.0.1_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@radix-ui/react-primitive/dist/index.d.mts","../../node_modules/.pnpm/@radix-ui+react-scroll-area@1.2.2_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom_d8f8bb762f9ee8d27d701c95d38a5f99/node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","../../packages/ui/src/lib/ui/scroll-area.tsx","../../node_modules/.pnpm/lucide-react@0.454.0_react@19.2.0/node_modules/lucide-react/dist/lucide-react.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constants.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/fp/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/add.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/adddays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/areintervalsoverlapping.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/clamp.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/closestindexto.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/closestto.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/compareasc.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/comparedesc.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constructfrom.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constructnow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/daystoweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendardays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarisoweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendaryears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceindays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachdayofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachhourofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachminuteofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachmonthofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachquarterofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachyearofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofhour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofsecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endoftoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endoftomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/formatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/longformatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/format.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistance.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancestrict.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancetonow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancetonowstrict.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatiso.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatiso9075.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatisoduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrfc3339.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrfc7231.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrelative.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/fromunixtime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdaysinmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdaysinyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/defaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdefaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/gethours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweeksinyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getoverlappingdaysinintervals.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/gettime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getunixtime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweekofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweeksinmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/interval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intervaltoduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intlformat.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intlformatdistance.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isafter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isbefore.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isequal.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isexists.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfirstdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfuture.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/islastdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isleapyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ismatch.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ismonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ispast.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamehour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamemonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamequarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamesecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthishour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthismonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthissecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isvalid.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/iswednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isweekend.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/iswithininterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/lightformatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lightformat.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/max.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/milliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/min.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/monthstoquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/monthstoyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextmonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextsaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextsunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nexttuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextwednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/setter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parser.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parseiso.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parsejson.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousmonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoussaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoussunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoustuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previouswednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/quarterstomonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/quarterstoyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/roundtonearesthours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/roundtonearestminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/set.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdefaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/sethours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofhour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofsecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startoftoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startoftomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/sub.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/submilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/submonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/todate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/transpose.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/weekstodays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstodays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstomonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstoquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/index.d.ts","../../packages/ui/src/components/encounter-list.tsx","../../packages/ui/src/components/idle-view.tsx","../../node_modules/.pnpm/@radix-ui+react-label@2.1.1_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@radix-ui/react-label/dist/index.d.mts","../../packages/ui/src/lib/ui/label.tsx","../../packages/ui/src/components/new-encounter-form.tsx","../../packages/ui/src/components/recording-view.tsx","../../packages/ui/src/components/processing-view.tsx","../../packages/ui/src/components/error-boundary.tsx","../../packages/ui/src/components/permissions-dialog.tsx","../../packages/ui/src/components/audit-log-viewer.tsx","../../packages/ui/src/components/settings-dialog.tsx","../../packages/ui/src/components/settings-bar.tsx","../../node_modules/.pnpm/swr@2.3.6_react@19.2.0/node_modules/swr/dist/_internal/events.d.mts","../../node_modules/.pnpm/swr@2.3.6_react@19.2.0/node_modules/swr/dist/_internal/types.d.mts","../../node_modules/.pnpm/swr@2.3.6_react@19.2.0/node_modules/swr/dist/_internal/constants.d.mts","../../node_modules/.pnpm/dequal@2.0.3/node_modules/dequal/index.d.ts","../../node_modules/.pnpm/swr@2.3.6_react@19.2.0/node_modules/swr/dist/_internal/index.d.mts","../../node_modules/.pnpm/swr@2.3.6_react@19.2.0/node_modules/swr/dist/index/index.d.mts","../../packages/ui/src/hooks/use-encounters.ts","../../packages/ui/src/hooks/use-https-warning.ts","../../packages/ui/src/index.ts","../../packages/ui/src/lib/ui/textarea.tsx","../../packages/ui/src/lib/ui/badge.tsx","../../packages/pipeline/render/src/components/note-editor.tsx","../../packages/pipeline/render/src/index.ts","../../packages/pipeline/audio-ingest/src/devices/system-audio.ts","../../packages/pipeline/audio-ingest/src/capture/audio-processing.ts","../../packages/pipeline/audio-ingest/src/capture/use-audio-recorder.ts","../../packages/pipeline/audio-ingest/src/index.ts","./src/app/page.tsx"],"fileIdsList":[[491,492,493],[269,554,559,560],[138,146,155,269,487,554],[269,487,554,560,567,569],[269,487,569],[85,269,491,574],[85,269,550,557,561,567,868,872,876],[269,487],[498,500,501,504,505,506,508,509,512,526,539,540,541,542],[500,507,543],[504,507,508,543],[543],[502,543],[510,511],[506],[506,508,509,512,543],[520],[504,509,543],[498,500,501,503],[167],[498],[130],[498,504,543],[504,543],[538,543],[504,517,518,538,543],[504,518,524],[533],[504,519,533,534,536,544],[535],[542],[532],[514,515,516,530,538],[504,508,509,512,514,539],[515,516,528,531,539],[504,508,509,514,521,526,538,539],[527,538],[503,504,508,514,517,519,526,527,537,538,539],[504,508,509,514,539],[529,530],[504,508,509,512,514,529,539],[503,504,508,514,526,539,540],[513,526,539,540,541],[523],[504,508,509,513,514,521,526],[522,526],[503,504,508,514,522,525,526],[85],[85,586],[85,585,586],[85,269],[92],[132],[133,138,167],[134,139,145,146,153,164,175],[134,135,145,153],[136,176],[137,138,146,154],[138,164,172],[139,141,145,153],[132,140],[141,142],[145],[143,145],[132,145],[145,146,147,164,175],[145,146,147,160,164,167],[130,133,180],[141,145,148,153,164,175],[145,146,148,149,153,164,172,175],[148,150,164,172,175],[92,93,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182],[145,151],[152,175,180],[141,145,153,164],[154],[155],[132,156],[153,154,157,174,180],[158],[159],[145,160,161],[160,162,176,178],[133,145,164,165,166,167],[133,164,166],[164,165],[168],[132,164],[145,170,171],[170,171],[138,153,164,172],[173],[153,174],[133,148,159,175],[138,176],[164,177],[152,178],[179],[133,138,145,147,156,164,175,178,180],[164,181],[85,186,188],[85,186,187],[85,399],[85,89,185,437,484],[85,89,184,437,484],[83,84],[576,582],[576],[593],[591,593],[591],[593,657,658],[593,660],[593,661],[678],[593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846],[593,754],[593,658,778],[591,775,776],[777],[593,775],[590,591,592],[440],[442,443,444,445],[193,195,199,211,220,423,433],[195,215,216,217,219,433],[195,250,252,254,255,258,433,435],[195,199,201,202,203,204,210,211,212,422,433,435],[433],[209,210,216,403,412,429],[195],[189,209,429],[260],[259,433,435],[148,394,403,489],[148,362,374,412,428],[148,305],[416],[415,416,417],[415],[91,148,189,195,199,202,210,213,214,216,220,232,233,260,335,413,423,433,437],[193,195,218,250,251,256,257,433,489],[218,489],[193,233,349,433,489],[489],[195,218,219,489],[253,489],[213,414,421],[159,269,429],[269,429],[85,366],[302,303,429,465,466,473],[409,465,467,468,469,470,472],[408],[408,409],[204,205,206,207,209],[208,209],[471],[209],[85,196,459],[85,175],[85,218,293],[85,218],[291,295],[85,292,439],[85,89,148,183,184,185,437,482,483],[148],[148,199,240,310,325,346,348,418,419,433,434],[232,420],[437],[194],[85,351,364,373,383,385,428],[159,351,364,382,383,384,428,488],[376,377,378,379,380,381],[378],[382],[267,268,269,271],[85,261,262,263,264,270],[267,270],[265],[266],[85,269,292,439],[85,269,438,439],[85,269,439],[325,425],[425],[148,434,439],[370],[132,369],[209,241,242,308,311,348,357,360,362,363,402,428,431,434],[209,242,391],[362,428],[85,362,367,368,370,371,372,373,374,375,386,387,388,389,390,392,393,428,429,489],[356],[148,159,196,240,242,243,264,287,308,325,335,346,347,402,424,433,434,435,437,489],[428],[132,216,308,335,359,424,426,427,434],[362],[132,240,277,311,352,353,354,355,356,357,358,360,361,428,429],[148,277,278,352,434,435],[216,325,335,348,424,428,434],[148,433,435],[148,164,431,434,435],[148,159,175,189,199,210,218,241,242,243,245,274,279,284,287,308,310,311,313,316,318,321,322,323,324,346,348,423,424,429,431,433,434,435],[148,164],[195,196,197,214,431,432,437,439,489],[193,433],[273],[148,164,175,235,258,260,261,262,263,264,271,272,489],[159,175,189,210,235,250,283,284,285,286,311,316,325,331,334,336,346,348,424,429,431],[210,213,214,232,335,424,433],[148,175,196,199,311,329,431,433],[350],[148,264,272,273,332,333,343],[431,433],[357,359],[308,311,423,439],[148,159,246,250,286,316,331,334,338,431],[148,213,232,250,339],[195,245,341,423,433],[148,175,264,433],[148,218,244,245,246,255,273,340,342,423,433],[91,242,308,345,437,439],[148,159,175,199,213,220,232,241,243,279,283,284,285,286,287,311,313,325,326,328,330,346,348,423,424,429,430,431,439],[148,164,213,331,337,343,431],[223,224,225,226,227,228,229,230,231],[274,317],[319],[317],[319,320],[148,199,202,204,240,434],[148,159,194,196,241,242,287,307,308,309,346,431,435,437,439],[148,159,175,198,204,309,311,357,424,430,434],[352],[353],[209,210,402],[354],[234,238],[148,199,234,241],[237,238],[239],[234,235],[234,288],[234],[274,315,430],[314],[235,429,430],[312,430],[235,429],[402],[199,209,211,236,241,308,311,345,348,351,357,364,365,395,398,401,423,431,434],[296,299,300,301,302,303],[85,186,188,269,396,397],[85,186,188,269,396,397,400],[411],[216,278,308,345,348,362,370,374,404,405,406,407,409,410,413,423,428,433],[302],[307],[148,241,289,304,306,310,345,431,437,439],[296,297,298,299,300,301,302,303,438],[91,148,159,175,234,235,243,287,308,311,343,344,346,423,424,433,434,437],[278,280,283,424],[148,274,433],[277,362],[276],[278,279],[275,277,433],[148,198,278,280,281,282,433,434],[85,205,209,429],[85,208],[191,192],[85,196],[85,429],[85,91,287,308,437,439],[196,459,460],[85,295],[85,159,175,194,257,290,292,294,439],[218,429,434],[327,429],[85,146,148,159,193,194,252,295,437,438],[85,184,185,437,484],[85,86,87,88,89],[138],[247,248,249],[247],[85,89,148,150,159,183,184,185,186,188,189,194,243,338,382,435,436,439,484],[447],[449],[451],[453],[455,456,457],[461],[90,441,446,448,450,452,454,458,462,464,475,476,478,487,488,489,490],[463],[474],[292],[477],[132,278,280,281,283,479,480,481,484,485,486],[183],[97,98,99,100,101,102,103,104,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,129],[164,183],[85,860,861,862,863],[860,865],[85,864],[103,107,175],[103,164,175],[98],[100,103,172,175],[153,172],[98,183],[100,103,153,175],[95,96,99,102,133,145,164,175],[95,101],[122,123],[99,103,133,167,175,183],[133,183],[122,133,183],[97,98,183],[103],[103,110,111],[101,103,111,112],[102],[95,98,103],[103,107,111,112],[107],[101,103,106,175],[95,100,103,110],[133,164],[95,100,103,110,117],[98,103,122,133,180,183],[269,544,548],[269,546],[269],[269,545],[269,547],[269,568],[85,269,873,874],[269,873,875],[269,496,497,558],[269,497,549,557],[85,269,550,579,584,588,589,847,869,870],[269,871],[85,269,564],[269,563,565,566],[269,551],[269,550,551,553],[269,550,551],[269,550,551,552,553,554,555,556],[269,554],[138,146,155,269],[85,269,550,553,554,584,851],[85,269,550,579,580,584,588,589,847],[85,269,584,589],[269,589],[85,269,580,584,589,851],[269,579,584,589],[269,584,589],[85,269,554,555,557,580,584,589,851,857],[269,550,552,554,865],[269,848,849,852,853,854,855,856,858,859,866,867],[85,269,579,581,583],[85,269,579],[85,269,579,850],[85,269,579,587],[269,576,577],[269,578]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"a305ee2f90e34e9e70aba9a9e9a154ce20c4d5cd1499cd21b8dc3617e1e5c810","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"e142fda89ed689ea53d6f2c93693898464c7d29a0ae71c6dc8cdfe5a1d76c775","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"80da4eb8151b94ac3b7997e513a54c3cf105b0d7d0456a172d43809b30cfefc6","impliedFormat":1},{"version":"3e4825171442666d31c845aeb47fcd34b62e14041bb353ae2b874285d78482aa","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"e9775e97ac4877aebf963a0289c81abe76d1ec9a2a7778dbe637e5151f25c5f3","impliedFormat":1},{"version":"ed4af8c2d6cd8869aca311076fe78dd841c4ab316a24170fc61171de5eb9b51f","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"3a84b7cb891141824bd00ef8a50b6a44596aded4075da937f180c90e362fe5f6","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"8b9bf58d580d9b36ab2f23178c88757ce7cc6830ccbdd09e8a76f4cb1bc0fcf7","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"7782678102bd835ef2c54330ee16c31388e51dfd9ca535b47f6fd8f3d6e07993","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","impliedFormat":1},{"version":"24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","impliedFormat":1},{"version":"1a42891defae8cec268a4f8903140dbf0d214c0cf9ed8fdc1eb6c25e5b3e9a5c","impliedFormat":1},{"version":"339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"d32275be3546f252e3ad33976caf8c5e842c09cb87d468cb40d5f4cf092d1acc","impliedFormat":1},{"version":"37e97c64b890352421ccb29cd8ede863774df8f03763416f6a572093f6058284","impliedFormat":1},{"version":"e7be367719c613d580d4b27fdf8fe64c9736f48217f4b322c0d63b2971460918","affectsGlobalScope":true,"impliedFormat":1},{"version":"db3ec8993b7596a4ef47f309c7b25ee2505b519c13050424d9c34701e5973315","impliedFormat":1},{"version":"e7f13a977b01cc54adb4408a9265cda9ddf11db878d70f4f3cac64bef00062e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"af49b066a76ce26673fe49d1885cc6b44153f1071ed2d952f2a90fccba1095c9","impliedFormat":1},{"version":"f22fd1dc2df53eaf5ce0ff9e0a3326fc66f880d6a652210d50563ae72625455f","impliedFormat":1},{"version":"3ddbdb519e87a7827c4f0c4007013f3628ca0ebb9e2b018cf31e5b2f61c593f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"6d498d4fd8036ea02a4edcae10375854a0eb1df0496cf0b9d692577d3c0fd603","affectsGlobalScope":true,"impliedFormat":1},{"version":"24642567d3729bcc545bacb65ee7c0db423400c7f1ef757cab25d05650064f98","impliedFormat":1},{"version":"fd09b892597ab93e7f79745ce725a3aaf6dd005e8db20f0c63a5d10984cba328","impliedFormat":1},{"version":"6b053e5c7523625a3a3363e0a7979de0f8c455ded2a1c63bf76d7b40530c36d9","impliedFormat":1},{"version":"5433f7f77cd1fd53f45bd82445a4e437b2f6a72a32070e907530a4fea56c30c8","impliedFormat":1},{"version":"9be74296ee565af0c12d7071541fdd23260f53c3da7731fb6361f61150a791f6","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"f501a53b94ba382d9ba396a5c486969a3abc68309828fa67f916035f5d37fe2b","affectsGlobalScope":true,"impliedFormat":1},{"version":"2908b517c61155bcbeb3f14dcb8f26fa52fb7bbdcc34837125ecce7d75934df3","impliedFormat":1},{"version":"81e3cba7568a2c9b0603e684e28eaf81c5ff0edc9bc0bfb7ec74b6c80809b625","impliedFormat":1},{"version":"bcfcff784a59db3f323c25cea5ae99a903ca9292c060f2c7e470ea73aaf71b44","impliedFormat":1},{"version":"672ad3045f329e94002256f8ed460cfd06173a50c92cde41edaadfacffd16808","impliedFormat":1},{"version":"64da4965d1e0559e134d9c1621ae400279a216f87ed00c4cce4f2c7c78021712","impliedFormat":1},{"version":"ddbf3aac94f85dbb8e4d0360782e60020da75a0becfc0d3c69e437c645feb30f","impliedFormat":1},{"version":"0166fce1204d520fdfd6b5febb3cda3deee438bcbf8ce9ffeb2b1bcde7155346","affectsGlobalScope":true,"impliedFormat":1},{"version":"d8b13eab85b532285031b06a971fa051bf0175d8fff68065a24a6da9c1c986cf","impliedFormat":1},{"version":"50c382ba1827988c59aa9cc9d046e386d55d70f762e9e352e95ee8cb7337cdb8","impliedFormat":1},{"version":"2178ab4b68402d1de2dda199d3e4a55f7200e3334f5a9727fbd9d16975cdf75f","impliedFormat":1},{"version":"e686bec498fbde620cc6069cc60c968981edd7591db7ca7e4614e77417eb41f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e523e73ee7dd119d99072fd855404efc33938c168063771528bd1deb6df56d2","affectsGlobalScope":true,"impliedFormat":1},{"version":"a215554477f7629e3dcbc8cde104bec036b78673650272f5ffdc5a2cee399a0a","impliedFormat":1},{"version":"c3497fc242aabfedcd430b5932412f94f157b5906568e737f6a18cc77b36a954","impliedFormat":1},{"version":"cdc1de3b672f9ef03ff15c443aa1b631edca35b6ae6970a7da6400647ff74d95","impliedFormat":1},{"version":"139ad1dc93a503da85b7a0d5f615bddbae61ad796bc68fedd049150db67a1e26","impliedFormat":1},{"version":"bf01fdd3b93cf633b3f7420718457af19c57ab8cbfea49268df60bae2e84d627","impliedFormat":1},{"version":"15c5e91b5f08be34a78e3d976179bf5b7a9cc28dc0ef1ffebffeb3c7812a2dca","impliedFormat":1},{"version":"65b39cc6b610a4a4aecc321f6efb436f10c0509d686124795b4c36a5e915b89e","impliedFormat":1},{"version":"269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","impliedFormat":1},{"version":"93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","impliedFormat":1},{"version":"3c1f19c7abcda6b3a4cf9438a15c7307a080bd3b51dfd56b198d9f86baf19447","impliedFormat":1},{"version":"d3edb86744e2c19f2c1503849ac7594a5e06024f2451bacae032390f2e20314a","impliedFormat":1},{"version":"a289e90dfa7a494f8b6276573d8641fa1aa2b2e92c6874ac842782d63ee3b852","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a3e61347b8f80aa5af532094498bceb0c0b257b25a6aa8ab4880fd6ed57c95a","affectsGlobalScope":true,"impliedFormat":1},{"version":"98e00f3613402504bc2a2c9a621800ab48e0a463d1eed062208a4ae98ad8f84c","impliedFormat":1},{"version":"4301becc26a79eb5f4552f7bee356c2534466d3b5cd68b71523e1929d543de89","impliedFormat":1},{"version":"5475df7cfc493a08483c9d7aa61cc04791aecba9d0a2efc213f23c4006d4d3cd","impliedFormat":1},{"version":"000720870b275764c65e9f28ac97cc9e4d9e4a36942d4750ca8603e416e9c57c","impliedFormat":1},{"version":"d9d9c04fd280b0c364a18ff058a68eee451a3b860f9f8b6cb44cb027a59d24e5","affectsGlobalScope":true,"impliedFormat":1},{"version":"1d274b8bb8ca011148f87e128392bfcd17a12713b6a4e843f0fa9f3f6b45e2b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"4c48e931a72f6971b5add7fdb1136be1d617f124594e94595f7114af749395e0","impliedFormat":1},{"version":"478eb5c32250678a906d91e0529c70243fc4d75477a08f3da408e2615396f558","impliedFormat":1},{"version":"e686a88c9ee004c8ba12ffc9d674ca3192a4c50ed0ca6bd5b2825c289e2b2bfe","impliedFormat":1},{"version":"98d547613610452ac9323fb9ec4eafc89acab77644d6e23105b3c94913f712b3","affectsGlobalScope":true,"impliedFormat":1},{"version":"3c1fa648ff7a62e4054bc057f7d392cb96dd019130c71d13894337add491d9f3","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a42be67ed1ddaec743582f41fc219db96a1b69719fccac6d1464321178d610fc","impliedFormat":1},{"version":"865a2612f5ec073dd48d454307ccabb04c48f8b96fda9940c5ebfe6b4b451f51","impliedFormat":1},{"version":"89e7fd23f6e6ced38596054161f5fb88737018909c6529c946cb349b74b95275","impliedFormat":1},{"version":"115b2ad73fa7d175cd71a5873d984c21593b2a022f1a2036cc39d9f53629e5dc","impliedFormat":1},{"version":"1be330b3a0b00590633f04c3b35db7fa618c9ee079258e2b24c137eb4ffcd728","impliedFormat":1},{"version":"bb7a61dd55dc4b9422d13da3a6bb9cc5e89be888ef23bbcf6558aa9726b89a1c","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"14109b34dc927e3b872c0f954a8d2536c245e38062bc47e8f97ba27f922fc9bd","impliedFormat":1},{"version":"1214c8bb321e2376f9dfc174a97b06c6e7bef05a61a1c50f094617d99fc4c9dd","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"5c24c66b3ba29ce9f2a79c719967e6e944131352a117a0bc43fa5b346b5562b3","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"496bbf339f3838c41f164238543e9fe5f1f10659cb30b68903851618464b98ba","impliedFormat":1},{"version":"099f915371bf0f8fd812d48a088531397f9edaf2ebfefe422cbe774c274a1621","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f0a1bd6ad77f98dd7ed0d3207fcbcb5dd109ba144799cf41b8ea4dacb4e3e009","impliedFormat":1},{"version":"197efda3bbcdd3f1bc5379cd0534f1ab740f3be957efb17b320da8e7dcb2743b","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"612f05ebdd6c4c3bab261d327082ad0c876332263b23cb29ea37ef5921086a2e","impliedFormat":1},{"version":"42277254e219cd5b047373e39d48248cd228d84b200b08e4d4d0949d6a48ef86","impliedFormat":1},{"version":"b06d68a692d3c1dd12bed02eaa3b4c06cfc2a3e9560b0cecd2014bba480c4e8e","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"fb1d8e814a3eeb5101ca13515e0548e112bd1ff3fb358ece535b93e94adf5a3a","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"892258709c8fc69cc1711d3554503f35101381df7e33eec344356bdc443ba07b","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"0d8f2b8781c721170b87a6b662b3cb038fd1a721165ecca390352c818d425872","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"380647d8f3b7f852cca6d154a376dbf8ac620a2f12b936594504a8a852e71d2f","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"581e67350f422c7a7bb1794356f21c9342ccbcff2e510620434307d480f39547","impliedFormat":1},{"version":"5e3cc568d8a72c39c2f1acfde5b464867ba900cfe157e9160d83be7b14d768e7","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"5ab8a9b437a9b2d1d3729def9694ba15525fd4028307e803fafc09aa30a8486a","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"42189cd810c0bf1247da0742d5744bb7c1486de6fd62269d5c25833b7ec38732","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"40436e992021afc07b61da5f488e9671729a3c5b5e6665b99b1fb43a39081ee3","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"162e071992b34bc36ca257d629547f93cb43728d6fe073ad18a237e4f7c52d7d","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"45490817629431853543adcb91c0673c25af52a456479588b6486daba34f68bb","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"d76bd0317e0958a220262a40d24f43fd5db2ff6e0ef0b2e14d2acdf7f88a78af","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"8c50ee1fcb97de2860d9ebd76561614ab6d365ac8390ef4a02bb4e76929705d1","impliedFormat":1},{"version":"cff125b5bbb8b819d7835c6b78809416d08da8b00e66611bfe368e0964be7b83","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"985153f0deb9b4391110331a2f0c114019dbea90cba5ca68a4107700796e0d75","impliedFormat":1},{"version":"382654d5da3eda8ea18f931d380ab6b099daa4913ae5b64265e6960338572914","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"d8cdd9477b9c5d1a8fbf2fa58e2eb6723969e7201b3549f998e0d2661dfec9d8","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"20e1c8beced348a9bf7864dd2b3ca7efa9ea6675dde8ecae6109b1a3f7248cd2","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"19c3d6db2020cee6f9d8d79e13c15e546e05b6db2020a3ee63789ec74a9990b3","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"0285dbbb2fdb8c5e9b50b92570c4c039b1eea2da4cfb5a04e77c1ca8b1949771","impliedFormat":1},{"version":"301cf1d98bce8b1666184888c7aaacd6c9dfed9185510f4317ed623596e38d2c","impliedFormat":1},{"version":"6c66d5cf284a56109703f941c92b9a22f2472c14645f80a2dbb8e4ef2128d67c","impliedFormat":1},{"version":"a3e7d932dc9c09daa99141a8e4800fc6c58c625af0d4bbb017773dc36da75426","impliedFormat":1},{"version":"0b888a0aa10655cadc0dc3b66cd79a99d79ff376aaacc9b628a3c497646fddab","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"d3c8b73132efa48e9399d63e8946a57ed4a7176e2f26d2f144bb14c89fcdefc1","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"8c030e515014c10a2b98f9f48408e3ba18023dfd3f56e3312c6c2f3ae1f55a16","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"d2aa1580a899bcec04c29b1c37f2a60f62e2f03acb731534d4e210307c982da8","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"68ab1530f0ddf7475425917b0e04068afdc1aee2db033bed9aa9b60a914c512e","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"88e9caa9c5d2ba629240b5913842e7c57c5c0315383b8dc9d436ef2b60f1c391","impliedFormat":1},{"version":"ddf68b3b62e49cf6fd93ba2351ad0fbbcf62ca2d5d7afc9f186114e4b481c3cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"1b239954e46191b95913d20771cf4283f63c3ebac79d7e30736a8d40b094fdaf","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"b5189fd031ef3232ec66817df5a8e7b23b079fdf3cd29a0c100eff1e98b2ce8e","impliedFormat":1},{"version":"00d3b80428c646edbd62379ea531606ee94eed51c4759cbab5a454e92b379690","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"946a709579b7868a92a70ad70906444f32803fa6e6ce3739b6594c17691837ce","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"5b955caba32e3dc3c3e293e00c104e255f0868848796e5bd5763f990c36d2798","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"4162ae9d4c1b8a7ab7f9ef287d98e9000b57062db1eb1ae735c4814845c2cb5d","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d0af5b1b8d6262ef94fee7f8a39d12db1e21762a048ae33d4a5941a5b9fc2e1d","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"54d320df89710586fddb799b1b4f5b3364773a510dc5d507f3fbf52d8a734ae4","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"f9ceb394e029da0392ebd49564002b01fb4517cef0d14b238f2a8e7362a833e1","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"be0b429c5364a8ae0c08bb6e7ab868c162553c3e8f8608fca486f86635ff7fdf","affectsGlobalScope":true},"7ad303e40d4fddf44f156129e397511953a71481c5cfd86b1862649aaaf240cc",{"version":"cefec11a35be7f2dd521c400a963de23b2306cd8de8f3422a77bddc83dcb99d2","signature":"fed3dc9e2de5f6cc2acbf65a5a208c7051ea63f6f4e41a18311b5b6f520d17c7"},{"version":"287cc0e8ee175a599588a66fa9589691f7111fb14c79df8a29c86bf836b5b544","signature":"aabebf555b5e8b45280907230815b2bcdd04fa35b033581cd20747cee75edaa9"},{"version":"2039bc146cc1f4b6320cae079b3c6b6de2166b9cdb859d83277b1bb0ea9ed1ce","signature":"571f3c4193b7109dd25377621615d311a5b881d6c1e74ae88985c789d0e324b4"},{"version":"86d4ff8ba66b5ea1df375fe6092d2b167682ccd5dd0d9b003a7d30d95a0cda32","impliedFormat":99},{"version":"37e97c64b890352421ccb29cd8ede863774df8f03763416f6a572093f6058284","impliedFormat":1},{"version":"2948774a5104c8ee235318dfdd3c8e2402c053b8fabc59e0cad1de8302d91cbd","impliedFormat":99},{"version":"014ba72e2add59d6d2d2e82166647982c824639e2902ccd7b3103cf720a0cb65","impliedFormat":99},{"version":"e22273698b7aad4352f0eb3c981d510b5cf6b17fde2eeaa5c018bb065d15558f","impliedFormat":99},{"version":"b78c801c3c21015ee487f6494448bcff55bb6b61f41172dfc2c26f2218d99138","impliedFormat":99},{"version":"de97e016d8dd4869febd5bccce02eb96957089d04b74ea5d1dc0e66112493b64","impliedFormat":99},{"version":"671ccab2e6a253d2516c0e4699b3077fc30cdb70b4436d8c79d76c91266a1a94","impliedFormat":99},{"version":"9b40cdceea5bb43a6e998cc6f8d47480741de5f336d9147653a5d9004175f6c1","impliedFormat":99},{"version":"e760f7860d08e9d42b6ecd7dd341602fbc0c13d60eb30beaf1153f1c7c44d66d","impliedFormat":99},{"version":"fb04e1ca667399e7302c033656cc285e6c1cff9c29f264cf229dd25e3962a762","impliedFormat":99},{"version":"8e9587d80cf4523b1655a74c5ff445313514b5de82af24bd9c2b2de764b8aa08","impliedFormat":99},{"version":"410e798cfb0d71e54d49284d16c7672db89720d017440abae05d547e9351e1cd","impliedFormat":99},{"version":"ddaf5d3ddc45282b19fb0fecec91c87fc9b4d1f45c2ee611677345c81383c5c5","impliedFormat":99},{"version":"5668033966c8247576fc316629df131d6175d24ccf22940324c19c159671e1c1","impliedFormat":99},{"version":"8db9325466c3c367e83b41ce5045757ad87a5468001b8bd3021bc406ac526bbe","impliedFormat":99},{"version":"d76df1670eeb97afbab6c87b8cd31bbd09dbf9026ff0ca533b5d7d3fc0291f79","impliedFormat":99},{"version":"13902404b0a9593a2c2f9c78ac7464820129fe7e5a660ef53a5cc8f3701f8350","impliedFormat":99},{"version":"2484f21803a2f6d8e34230c1c4354288da5d842182d7102a49a004c819c4b8b3","impliedFormat":99},{"version":"b6083b1fcead271c8902f9e5c6bdbc645d83ef3d0d8c029c92e19e094a8e1327","impliedFormat":99},{"version":"50cf14b8f0fc2722c11794ca2a06565b1f29e266491da75c745894960ebbce06","impliedFormat":99},{"version":"d14c27fbdc983de6ac10fa52844be9a4284ed70648e09b03f1dfb3e524ffe80c","impliedFormat":99},{"version":"cd8a4297d0ab56dc571dadd2845e558c9d979fe1e120a0dec537935bc8a36dd2","impliedFormat":99},{"version":"079a12cb0e0c42655d77da5185e882b4cc94bd5c6c2131171a9289fc1f4287fc","impliedFormat":99},{"version":"a018d566af32db595b5491095cf3e9d0f3773e96e8c36b3010c5773408dab9cf","impliedFormat":99},{"version":"795c2d3c3957e8d508694a547d3054188f695ab5e2e92edf12bc5fcf7a131543","impliedFormat":99},{"version":"167edfac7664bec77aa2efb2ce9d515c41b5cc4269091a946b3fa6ec4e7e8738","impliedFormat":99},{"version":"e1d65ef0ac1d0f780a061cccf6aedc70622395b0edfd8df1a3bdb92c93a98bea","impliedFormat":99},{"version":"9a7f96f9b74c582422c3ed03b58339d00a3e6b170b14ec31af615a2d30449d34","impliedFormat":99},{"version":"12d1545629648a2281099d450e26c1093ab92149b2f11a5eb820e956be31173a","impliedFormat":99},{"version":"ce8efe03de887ccd0b28ef5b6cb314af7653b7a3360dd8eb4fa47b2b743aa0a4","impliedFormat":99},{"version":"4d4551dcb3fd19a4f22aaa63c6c391d42ce44a15602a6f6a19d582709edb24d9","impliedFormat":99},{"version":"a76075b5aba8187b1fc5c8f565745daed6e4341e64b44e6ec41412a16d575d62","impliedFormat":99},{"version":"f836bf3653e31c3bba120071196c95d416b83c5d860ce27549975f8785cd670a","impliedFormat":99},{"version":"3d9c8154e27774153a2806926da926337ae232ab848153487903323bb4c83dc7","impliedFormat":99},{"version":"f687f35c2206a319dc7d8f0b751e182638c912838ff54034fb782beae50f7cac","impliedFormat":99},{"version":"0ce0cd2e64075ea59432df7a5c23a05c4888e4254de449f6bd43d8af04fc33b8","impliedFormat":99},{"version":"7a81f15892b1c8d0cbfb35605038ce5c6d0cf93542946aa0b8c415dbefdea1cd","impliedFormat":99},{"version":"d6fc46b15a18da0aaf99dba1fc1109b1b4ade3f978c55772d99f6b8cc47f4753","impliedFormat":99},{"version":"f96fb5e3197e37ed63f7787885a869aba941c94a234a62f74fa10f8a389c3c35","impliedFormat":99},{"version":"063141047bd26a30b156a2e2ebb6924a3427ba6195f7a11ba9472490eac82022","impliedFormat":99},{"version":"c48fbe1599fcef71d380c71e75a9a4895839f0baf3666d46dbc20be1edaab5d6","impliedFormat":99},{"version":"c0144b49b5c752301d037d9334986903fbb9f14de8263b93cd702ff2218f083e","impliedFormat":99},{"version":"647e1d0a723a7caa54487d50dbfd952f184a110899ce3f331f3c451f6fbd083f","impliedFormat":99},{"version":"0ef423f75b832126ecc0966a396b68c4a2afdecf8783f4e9e10a439ea0e81b8a","impliedFormat":99},{"version":"137049cab609b1bb2de696f1652d400bfd2942d58fe6cb43712e1b29d05139fc","impliedFormat":99},{"version":"562640a0449842e1fc2663d2d731740114629a156366a46d26c561811d879600","impliedFormat":99},{"version":"4f3461507f56af2aa22d6895c3e8a4ce75d92ab40661bd8ae38cd7ece410d892","signature":"a5cf9cd0b0950a26801bfb911f725817cef8ee2d464845ce894979bb4364589b"},{"version":"e57141822b6996b6bef551a64cd475ff90b63b0b32b5b52490c6efa7a0b50d2a","signature":"0133a679821f4e96d1fc5021fd31050576419896440c1165eace0a4eb9da5186"},{"version":"322ae5c4d073ffc8fff091f71005ed01dd49396d8bbbad213b4fa72183884c48","signature":"32d97e928866ebee1b80975a347b879f2c10789c80fe39e8a41dd8d9293113d7"},{"version":"25d57b94b0300bc2133b3dbcaefe1891598af5a75c6564a5d8d0609e14c05f04","signature":"6aa7265ae38634679e93e75237044c298a65ae7b9d70f597f441aaf95d461348"},{"version":"ad44450a1dcfaf4813d29616c07988157117324b3d46c174579acba16e1bd863","signature":"748474563bb55ea2c8f4c8e79e81de1128a197c789293d34a0b80264b7458f4e"},{"version":"0075193b9aed3009cf211391adcda2bc96d163b10fd38523f3cd24acb5537125","signature":"6f27af661e7d69470edf9f97ae7ea0d71b38af5ba3975e342622cadc741af772"},{"version":"a207bf7872c2342b7eec4c8c1aac6272da9c24cbcbcbd9f8ee1f686cab0cb2b8","signature":"5e766bc5793fb768365707850105153ce53e7714805c7e074509eae1a3fdaa5b"},{"version":"970628968c1a35f6442953c850285c9a8805753fd6a3317caee426c46a493fcc","signature":"b2441dcb1c8abff8802fc6c82dfc66cc7a6e84944efc0a65516f920b5aff1a0b"},{"version":"807f98f9160a13e3d695fa67bbe763b8843a42cdf7b085b39cd64c5432415532","signature":"4cf2561c4b5c7c1ca015e8fbf5829c2cb1ce4deb45ba6963040475d0737ab672"},{"version":"16c8dbe30a172430bf8a91ebb47387c6efd4bbcc49e6a6d2765312b30da114f6","signature":"53bf5df332806da38f29edb3c345a6ce833a966529b52f554484734e3ae260da"},{"version":"d969a2d674bf1fcec55ec6ca62ad823db5285d6e7e674082faac38c930f569b9","signature":"55f5524451e4b2708f8c321d8eeff473d0481ed5539d588534c65951f4210212"},{"version":"c3f00c0a325c460f92092aaaa0a5a9282ffce2aa6617c413da0a4cfef89656f5","signature":"7d16cf5565efce938e0ce9afcc9e6c6846c57d98cbcd62fb43736f3ae53bd767"},{"version":"5320c02ce8d865ae01ee011abe79f3a5427100a91295bf59332f290d391e018c","signature":"8987e841af0f363073baa7d586570ba3cb4c4077d0e0df78102ceb52feca1e1c"},{"version":"d7297d15897fa3d179b09c65dc13713c6fddec4117e98d4c187ba4aee9ecd56d","signature":"9585be7e3272ce1640ed24b82e36d6567c2197693f71c2464329f53f1af1344b"},{"version":"477291f93fb53a4414a8d2243f63c4976fb8b7c76872d1c7beaa17e3ae30573d","signature":"2cb202257e26db2b5c29597f716231700940c6790c9cabf0ca9a8ebebf556957"},{"version":"a3df3943a2f169b6c8cd2ddf3128a2d98e7f00039cae772724ac80e353821dce","signature":"101fb768015ba4e0dcbe53cf9cd99cbc68210115138def648eb9de116a486fd6"},{"version":"1b8e77b65d4cff18fedc6f288006c892e9faeec96c1a8bbeae83551c39b85f7d","signature":"871fe90c9d8f35c04239cb13de4bb181fd1a84f5fa9e77e52c01e53b61876703"},{"version":"4228f38769a73017d7cbfee77ab2d6dfc721c2a713d0edc50cc1f10d3294458e","signature":"3ea23c776f096ab7d2d096fa9e11e3a1bb02b82f53bee772865801cb8e9d067f"},{"version":"bb44762c7f85e70bd0ba3033dc46e93c26944cee0a5920300050f8f0988ba6d2","signature":"805bab7cf726fe2ac98787f9b609e4ac2d3785936f4567320d27a15688f72cbe"},{"version":"dc149b873c0b6a36e16df71ea05cc7e75a9364f024186188dc2b97744a26a4a5","signature":"09ed482962dfaaa64394c370b5a49f7c06c651c3bd1013713205fe61fb40f795"},{"version":"dda8c143a1f0bc968dbf16f070b60f4d58a88f0b40a71526439c49203eddeb48","signature":"4d0dc2fbdbc626a4418e3357bb48a5a2073a5ad1e5b434569a03eff28e08812b"},{"version":"9dddd1981aac42a726dde486c30695a9a5611c978eb22f7d5b4fa289e2a55bcb","signature":"1f9aa9c8b83b489bd1f8d5278c60890e5f13b819ec2fea292051496af8bbc9d1"},{"version":"0cd7574b663b11ffbccf4573aeb7389ace4e6449eedde4fc09ee95a9d65a0bd5","signature":"db80b763221e051fc8fb1a29cfeb5b6813a7c6fb04834957972f4be88d77d674"},{"version":"ef0644561633f1796572966b7ec23c71c2541d292eaa0fb394f4cd64ae85984d","signature":"e8c517bdb16daeb9d6e7a3abb9d4124cf296b93b97e151631179d4589358c8ad","affectsGlobalScope":true},{"version":"cf6b7fb0ea50561c84374b4e591683a6c20d80be76cdf5c086ee79f50234a78d","signature":"5361b81d021f6cdbf6f979aa3b22dcbe19224a85dec5cf9c15fa089ff0d2003e"},{"version":"4856459fe6dd3ea772c7f9d540744e644826f60df90f9e28c5a027004fc64f0c","signature":"1d1c45eb33310de28e96a0ebbeefd6d26cd87c17c7d2fd61c670594d66588416"},{"version":"17b984c41c9e0b545b69feef91f89eb1cc7fa71315bc603b1f0b0691c04a0b83","signature":"1d1c45eb33310de28e96a0ebbeefd6d26cd87c17c7d2fd61c670594d66588416"},{"version":"033b0eb307e900c2ab1672b44095812848cf474a083362325e789962f4c3ef48","signature":"d63724d38f8df4a597ac65e36cdb8f2545f85282cf235a94c0f6af02238d3c30"},{"version":"0113d42796a2e754931f2722d56e000afe8345fcef8770a013b7013737896cb8","affectsGlobalScope":true},{"version":"6e33223b4de404a63f431d223ce05f7c6afbeff873199b608773bdd9ad70f9cc","affectsGlobalScope":true,"impliedFormat":99},{"version":"771f159efd2b17c72a98ed78177162397b93e8ceb2446b5fb57960e054468aae","signature":"1fe151362f90fc7501926dd9e8ad981918b031b79ae242174845c46797e986ef"},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"49a8a704be8c2a8f5d645a404051db4a0a0fa4fa7b6ca71207cf9344bb413abc","impliedFormat":1},{"version":"e46429536f43f5910f5b2b0c50bb2769b510a4558bb4b5d20a3b0a9091dbf7c3","signature":"400b40fe5d5f4140993b0ac871686d2b7611ab791e8810b2e14f2d89701fc49e"},{"version":"aadf0f498b5ea8d78b28d2736229068ce805e27288548d614f13da9e02b3cf8c","signature":"618683504bb0c2d59481629a31cf3d5cab9d29fbe91f68c2f288dcc2d1dcf5db"},{"version":"25f92f980c5f0f8b0e3b1160e9ae434ce95b83ce04074b0d786ca109145c1e4e","signature":"3309423a2837bf899df1568eaa9c41430753bf2957451b4b0494c7e4f829ada1"},{"version":"a80b7bc4eda856374c26a56f6f25297f4c393309d4c4548002a5238cd57b2b66","impliedFormat":99},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"7b9fef47bc76c31bf42f9a4e6a38fbd8776b70b899d25c8b152b47b5c3e767cf","signature":"22b0ed29e99e02e157048711d20d33c46510e6f32d764ebc613cf282d43f6f07"},{"version":"a26d74bc8768e134734fa049d5a89fb674a560292f4bf1b39392416dc04cf49e","impliedFormat":99},{"version":"ea7f3d87bb25b8cf26c1b440de31b628c53b5e72e8f1ab1726356bf58acf5946","impliedFormat":99},{"version":"260f551168be7a50e7f1d4588574894683709dad712e60cd31282f5ee31c1fa2","impliedFormat":99},{"version":"9eb24c2e0ce91668b36892be1ab3d29c600cb5e51b1f94e5a7199b95fbfd358c","signature":"351f7cb5f3ce63374db1c4a065fa52fb1395e525c7a7a9dcaade8db57dae36a7"},{"version":"8512cce0256f2fcad4dc4d72a978ef64fefab78c16a1141b31f2f2eba48823d1","impliedFormat":1},{"version":"2cef84bf00cbdb452fdc5d8ecfe7b8c0aa3fa788bdc4ad8961e2e636530dbb60","impliedFormat":99},{"version":"24104650185414f379d5cc35c0e2c19f06684a73de5b472bae79e0d855771ecf","impliedFormat":99},{"version":"799003c0ab928582fca04977f47b8d85b43a8de610f4eef0ad2d069fbb9f9399","impliedFormat":99},{"version":"b13dd41c344a23e085f81b2f5cd96792e6b35ae814f32b25e39d9841844ad240","impliedFormat":99},{"version":"17d8b4e6416e48b6e23b73d05fd2fde407e2af8fddbe9da2a98ede14949c3489","impliedFormat":99},{"version":"6d17b2b41f874ab4369b8e04bdbe660163ea5c8239785c850f767370604959e3","impliedFormat":99},{"version":"04b4c044c8fe6af77b6c196a16c41e0f7d76b285d036d79dcaa6d92e24b4982b","impliedFormat":99},{"version":"30bdeead5293c1ddfaea4097d3e9dd5a6b0bc59a1e07ff4714ea1bbe7c5b2318","impliedFormat":99},{"version":"e7df226dcc1b0ce76b32f160556f3d1550124c894aae2d5f73cefaaf28df7779","impliedFormat":99},{"version":"f2b7eef5c46c61e6e72fba9afd7cc612a08c0c48ed44c3c5518559d8508146a2","impliedFormat":99},{"version":"00f0ba57e829398d10168b7db1e16217f87933e61bd8612b53a894bd7d6371da","impliedFormat":99},{"version":"126b20947d9fa74a88bb4e9281462bda05e529f90e22d08ee9f116a224291e84","impliedFormat":99},{"version":"40d9e43acee39702745eb5c641993978ac40f227475eacc99a83ba893ad995db","impliedFormat":99},{"version":"8a66b69b21c8de9cb88b4b6d12f655d5b7636e692a014c5aa1bd81745c8c51d5","impliedFormat":99},{"version":"ebbb846bdd5a78fdacff59ae04cea7a097912aeb1a2b34f8d88f4ebb84643069","impliedFormat":99},{"version":"7321adb29ffd637acb33ee67ea035f1a97d0aa0b14173291cc2fd58e93296e04","impliedFormat":99},{"version":"320816f1a4211188f07a782bdb6c1a44555b3e716ce13018f528ad7387108d5f","impliedFormat":99},{"version":"b2cc8a474b7657f4a03c67baf6bff75e26635fd4b5850675e8cad524a09ddd0c","impliedFormat":99},{"version":"0d081e9dc251063cc69611041c17d25847e8bdbe18164baaa89b7f1f1633c0ab","impliedFormat":99},{"version":"a64c25d8f4ec16339db49867ea2324e77060782993432a875d6e5e8608b0de1e","impliedFormat":99},{"version":"0739310b6b777f3e2baaf908c0fbc622c71160e6310eb93e0d820d86a52e2e23","impliedFormat":99},{"version":"37b32e4eadd8cd3c263e7ac1681c58b2ac54f3f77bb34c5e4326cc78516d55a9","impliedFormat":99},{"version":"9b7a8974e028c4ed6f7f9abb969e3eb224c069fd7f226e26fcc3a5b0e2a1eba8","impliedFormat":99},{"version":"e8100b569926a5592146ed68a0418109d625a045a94ed878a8c5152b1379237c","impliedFormat":99},{"version":"594201c616c318b7f3149a912abd8d6bdf338d765b7bcbde86bca2e66b144606","impliedFormat":99},{"version":"03e380975e047c5c6ded532cf8589e6cc85abb7be3629e1e4b0c9e703f2fd36f","impliedFormat":99},{"version":"fae14b53b7f52a8eb3274c67c11f261a58530969885599efe3df0277b48909e1","impliedFormat":99},{"version":"c41206757c428186f2e0d1fd373915c823504c249336bdc9a9c9bbdf9da95fef","impliedFormat":99},{"version":"e961f853b7b0111c42b763a6aa46fc70d06a697db3d8ed69b38f7ba0ae42a62b","impliedFormat":99},{"version":"3db90f79e36bcb60b3f8de1bc60321026800979c150e5615047d598c787a64b7","impliedFormat":99},{"version":"639b6fb3afbb8f6067c1564af2bd284c3e883f0f1556d59bd5eb87cdbbdd8486","impliedFormat":99},{"version":"49795f5478cb607fd5965aa337135a8e7fd1c58bc40c0b6db726adf186dd403f","impliedFormat":99},{"version":"7d8890e6e2e4e215959e71d5b5bd49482cf7a23be68d48ea446601a4c99bd511","impliedFormat":99},{"version":"d56f72c4bb518de5702b8b6ae3d3c3045c99e0fd48b3d3b54c653693a8378017","impliedFormat":99},{"version":"4c9ac40163e4265b5750510d6d2933fb7b39023eed69f7b7c68b540ad960826e","impliedFormat":99},{"version":"8dfab17cf48e7be6e023c438a9cdf6d15a9b4d2fa976c26e223ba40c53eb8da8","impliedFormat":99},{"version":"38bdf7ccacfd8e418de3a7b1e3cecc29b5625f90abc2fa4ac7843a290f3bf555","impliedFormat":99},{"version":"9819e46a914735211fbc04b8dc6ba65152c62e3a329ca0601a46ba6e05b2c897","impliedFormat":99},{"version":"50f0dc9a42931fb5d65cdd64ba0f7b378aedd36e0cfca988aa4109aad5e714cb","impliedFormat":99},{"version":"894f23066f9fafccc6e2dd006ed5bd85f3b913de90f17cf1fe15a2eb677fd603","impliedFormat":99},{"version":"abdf39173867e6c2d6045f120a316de451bbb6351a6929546b8470ddf2e4b3b9","impliedFormat":99},{"version":"aa2cb4053f948fbd606228195bbe44d78733861b6f7204558bbee603202ee440","impliedFormat":99},{"version":"6911b41bfe9942ac59c2da1bbcbe5c3c1f4e510bf65cae89ed00f434cc588860","impliedFormat":99},{"version":"7b81bc4d4e2c764e85d869a8dd9fe3652b34b45c065482ac94ffaacc642b2507","impliedFormat":99},{"version":"895df4edb46ccdcbce2ec982f5eed292cf7ea3f7168f1efea738ee346feab273","impliedFormat":99},{"version":"8692bb1a4799eda7b2e3288a6646519d4cebb9a0bddf800085fc1bd8076997a0","impliedFormat":99},{"version":"239c9e98547fe99711b01a0293f8a1a776fc10330094aa261f3970aaba957c82","impliedFormat":99},{"version":"34833ec50360a32efdc12780ae624e9a710dd1fd7013b58c540abf856b54285a","impliedFormat":99},{"version":"647538e4007dcc351a8882067310a0835b5bb8559d1cfa5f378e929bceb2e64d","impliedFormat":99},{"version":"992d6b1abcc9b6092e5a574d51d441238566b6461ade5de53cb9718e4f27da46","impliedFormat":99},{"version":"938702305649bf1050bd79f3803cf5cc2904596fc1edd4e3b91033184eae5c54","impliedFormat":99},{"version":"1e931d3c367d4b96fe043e792196d9c2cf74f672ff9c0b894be54e000280a79d","impliedFormat":99},{"version":"05bec322ea9f6eb9efcd6458bb47087e55bd688afdd232b78379eb5d526816ed","impliedFormat":99},{"version":"4c449a874c2d2e5e5bc508e6aa98f3140218e78c585597a21a508a647acd780a","impliedFormat":99},{"version":"dae15e326140a633d7693e92b1af63274f7295ea94fb7c322d5cbe3f5e48be88","impliedFormat":99},{"version":"c2b0a869713bca307e58d81d1d1f4b99ebfc7ec8b8f17e80dde40739aa8a2bc6","impliedFormat":99},{"version":"6e4b4ff6c7c54fa9c6022e88f2f3e675eac3c6923143eb8b9139150f09074049","impliedFormat":99},{"version":"69559172a9a97bbe34a32bff8c24ef1d8c8063feb5f16a6d3407833b7ee504cf","impliedFormat":99},{"version":"86b94a2a3edcb78d9bfcdb3b382547d47cb017e71abe770c9ee8721e9c84857f","impliedFormat":99},{"version":"e3fafafda82853c45c0afc075fea1eaf0df373a06daf6e6c7f382f9f61b2deb3","impliedFormat":99},{"version":"a4ba4b31de9e9140bc49c0addddbfaf96b943a7956a46d45f894822e12bf5560","impliedFormat":99},{"version":"d8a7926fc75f2ed887f17bae732ee31a4064b8a95a406c87e430c58578ee1f67","impliedFormat":99},{"version":"9886ffbb134b0a0059fd82219eba2a75f8af341d98bc6331b6ef8a921e10ec68","impliedFormat":99},{"version":"c2ead057b70d0ae7b87a771461a6222ebdb187ba6f300c974768b0ae5966d10e","impliedFormat":99},{"version":"46687d985aed8485ab2c71085f82fafb11e69e82e8552cf5d3849c00e64a00a5","impliedFormat":99},{"version":"999ca66d4b5e2790b656e0a7ce42267737577fc7a52b891e97644ec418eff7ec","impliedFormat":99},{"version":"ec948ee7e92d0888f92d4a490fdd0afb27fbf6d7aabebe2347a3e8ac82c36db9","impliedFormat":99},{"version":"03ef2386c683707ce741a1c30cb126e8c51a908aa0acc01c3471fafb9baaacd5","impliedFormat":99},{"version":"66a372e03c41d2d5e920df5282dadcec2acae4c629cb51cab850825d2a144cea","impliedFormat":99},{"version":"ddf9b157bd4c06c2e4646c9f034f36267a0fbd028bd4738214709de7ea7c548b","impliedFormat":99},{"version":"3e795aac9be23d4ad9781c00b153e7603be580602e40e5228e2dafe8a8e3aba1","impliedFormat":99},{"version":"98c461ec5953dfb1b5d5bca5fee0833c8a932383b9e651ca6548e55f1e2c71c3","impliedFormat":99},{"version":"5c42107b46cb1d36b6f1dee268df125e930b81f9b47b5fa0b7a5f2a42d556c10","impliedFormat":99},{"version":"7e32f1251d1e986e9dd98b6ff25f62c06445301b94aeebdf1f4296dbd2b8652f","impliedFormat":99},{"version":"2f7e328dda700dcb2b72db0f58c652ae926913de27391bd11505fc5e9aae6c33","impliedFormat":99},{"version":"3de7190e4d37da0c316db53a8a60096dbcd06d1a50677ccf11d182fa26882080","impliedFormat":99},{"version":"a9d6f87e59b32b02c861aade3f4477d7277c30d43939462b93f48644fa548c58","impliedFormat":99},{"version":"2bce8fd2d16a9432110bbe0ba1e663fd02f7d8b8968cd10178ea7bc306c4a5df","impliedFormat":99},{"version":"798bedbf45a8f1e55594e6879cd46023e8767757ecce1d3feaa78d16ad728703","impliedFormat":99},{"version":"62723d5ac66f7ed6885a3931dd5cfa017797e73000d590492988a944832e8bc2","impliedFormat":99},{"version":"03db8e7df7514bf17fc729c87fff56ca99567b9aa50821f544587a666537c233","impliedFormat":99},{"version":"9b1f311ba4409968b68bf20b5d892dbd3c5b1d65c673d5841c7dbde351bc0d0b","impliedFormat":99},{"version":"2d1e8b5431502739fe335ceec0aaded030b0f918e758a5d76f61effa0965b189","impliedFormat":99},{"version":"e725839b8f884dab141b42e9d7ff5659212f6e1d7b4054caa23bc719a4629071","impliedFormat":99},{"version":"4fa38a0b8ae02507f966675d0a7d230ed67c92ab8b5736d99a16c5fbe2b42036","impliedFormat":99},{"version":"50ec1e8c23bad160ddedf8debeebc722becbddda127b8fdce06c23eacd3fe689","impliedFormat":99},{"version":"9a0aea3a113064fd607f41375ade308c035911d3c8af5ae9db89593b5ca9f1f9","impliedFormat":99},{"version":"8d643903b58a0bf739ce4e6a8b0e5fb3fbdfaacbae50581b90803934b27d5b89","impliedFormat":99},{"version":"19de2915ccebc0a1482c2337b34cb178d446def2493bf775c4018a4ea355adb8","impliedFormat":99},{"version":"9be8fc03c8b5392cd17d40fd61063d73f08d0ee3457ecf075dcb3768ae1427bd","impliedFormat":99},{"version":"a2d89a8dc5a993514ca79585039eea083a56822b1d9b9d9d85b14232e4782cbe","impliedFormat":99},{"version":"f526f20cae73f17e8f38905de4c3765287575c9c4d9ecacee41cfda8c887da5b","impliedFormat":99},{"version":"d9ec0978b7023612b9b83a71fee8972e290d02f8ff894e95cdd732cd0213b070","impliedFormat":99},{"version":"7ab10c473a058ec8ac4790b05cae6f3a86c56be9b0c0a897771d428a2a48a9f9","impliedFormat":99},{"version":"451d7a93f8249d2e1453b495b13805e58f47784ef2131061821b0e456a9fd0e1","impliedFormat":99},{"version":"21c56fe515d227ed4943f275a8b242d884046001722a4ba81f342a08dbe74ae2","impliedFormat":99},{"version":"d8311f0c39381aa1825081c921efde36e618c5cf46258c351633342a11601208","impliedFormat":99},{"version":"6b50c3bcc92dc417047740810596fcb2df2502aa3f280c9e7827e87896da168a","impliedFormat":99},{"version":"18a6b318d1e7b31e5749a52be0cf9bbce1b275f63190ef32e2c79db0579328ca","impliedFormat":99},{"version":"6a2d0af2c27b993aa85414f3759898502aa198301bc58b0d410948fe908b07b0","impliedFormat":99},{"version":"2da11b6f5c374300e5e66a6b01c3c78ec21b5d3fec0748a28cc28e00be73e006","impliedFormat":99},{"version":"0729691b39c24d222f0b854776b00530877217bfc30aac1dc7fa2f4b1795c536","impliedFormat":99},{"version":"ca45bb5c98c474d669f0e47615e4a5ae65d90a2e78531fda7862ee43e687a059","impliedFormat":99},{"version":"c1c058b91d5b9a24c95a51aea814b0ad4185f411c38ac1d5eef0bf3cebec17dc","impliedFormat":99},{"version":"3ab0ed4060b8e5b5e594138aab3e7f0262d68ad671d6678bcda51568d4fc4ccc","impliedFormat":99},{"version":"e2bf1faba4ff10a6020c41df276411f641d3fdce5c6bae1db0ec84a0bf042106","impliedFormat":99},{"version":"80b0a8fe14d47a71e23d7c3d4dcee9584d4282ef1d843b70cab1a42a4ea1588c","impliedFormat":99},{"version":"a0f02a73f6e3de48168d14abe33bf5970fdacdb52d7c574e908e75ad571e78f7","impliedFormat":99},{"version":"c728002a759d8ec6bccb10eed56184e86aeff0a762c1555b62b5d0fa9d1f7d64","impliedFormat":99},{"version":"586f94e07a295f3d02f847f9e0e47dbf14c16e04ccc172b011b3f4774a28aaea","impliedFormat":99},{"version":"cfe1a0f4ed2df36a2c65ea6bc235dbb8cf6e6c25feb6629989f1fa51210b32e7","impliedFormat":99},{"version":"8ba69c9bf6de79c177329451ffde48ddab7ec495410b86972ded226552f664df","impliedFormat":99},{"version":"15111cbe020f8802ad1d150524f974a5251f53d2fe10eb55675f9df1e82dbb62","impliedFormat":99},{"version":"782dc153c56a99c9ed07b2f6f497d8ad2747764966876dbfef32f3e27ce11421","impliedFormat":99},{"version":"cc2db30c3d8bb7feb53a9c9ff9b0b859dd5e04c83d678680930b5594b2bf99cb","impliedFormat":99},{"version":"46909b8c85a6fd52e0807d18045da0991e3bdc7373435794a6ba425bc23cc6be","impliedFormat":99},{"version":"e4e511ff63bb6bd69a2a51e472c6044298bca2c27835a34a20827bc3ef9b7d13","impliedFormat":99},{"version":"2c86f279d7db3c024de0f21cd9c8c2c972972f842357016bfbbd86955723b223","impliedFormat":99},{"version":"112c895cff9554cf754f928477c7d58a21191c8089bffbf6905c87fe2dc6054f","impliedFormat":99},{"version":"8cfc293b33082003cacbf7856b8b5e2d6dd3bde46abbd575b0c935dc83af4844","impliedFormat":99},{"version":"d2c5c53f85ce0474b3a876d76c4fc44ff7bb766b14ed1bf495f9abac181d7f5f","impliedFormat":99},{"version":"3c523f27926905fcbe20b8301a0cc2da317f3f9aea2273f8fc8d9ae88b524819","impliedFormat":99},{"version":"9ca0d706f6b039cc52552323aeccb4db72e600b67ddc7a54cebc095fc6f35539","impliedFormat":99},{"version":"a64909a9f75081342ddd061f8c6b49decf0d28051bc78e698d347bdcb9746577","impliedFormat":99},{"version":"7d8d55ae58766d0d52033eae73084c4db6a93c4630a3e17f419dd8a0b2a4dcd8","impliedFormat":99},{"version":"b8b5c8ba972d9ffff313b3c8a3321e7c14523fc58173862187e8d1cb814168ac","impliedFormat":99},{"version":"9c42c0fa76ee36cf9cc7cc34b1389fbb4bd49033ec124b93674ec635fabf7ffe","impliedFormat":99},{"version":"6184c8da9d8107e3e67c0b99dedb5d2dfe5ccf6dfea55c2a71d4037caf8ca196","impliedFormat":99},{"version":"4030ceea7bf41449c1b86478b786e3b7eadd13dfe5a4f8f5fe2eb359260e08b3","impliedFormat":99},{"version":"7bf516ec5dfc60e97a5bde32a6b73d772bd9de24a2e0ec91d83138d39ac83d04","impliedFormat":99},{"version":"e6a6fb3e6525f84edf42ba92e261240d4efead3093aca3d6eb1799d5942ba393","impliedFormat":99},{"version":"45df74648934f97d26800262e9b2af2f77ef7191d4a5c2eb1df0062f55e77891","impliedFormat":99},{"version":"3fe361e4e567f32a53af1f2c67ad62d958e3d264e974b0a8763d174102fe3b29","impliedFormat":99},{"version":"28b520acee4bc6911bfe458d1ad3ebc455fa23678463f59946ad97a327c9ab2b","impliedFormat":99},{"version":"121b39b1a9ad5d23ed1076b0db2fe326025150ef476dccb8bf87778fcc4f6dd7","impliedFormat":99},{"version":"f791f92a060b52aa043dde44eb60307938f18d4c7ac13df1b52c82a1e658953f","impliedFormat":99},{"version":"df09443e7743fd6adc7eb108e760084bacdf5914403b7aac5fbd4dc4e24e0c2c","impliedFormat":99},{"version":"eeb4ff4aa06956083eaa2aad59070361c20254b865d986bc997ee345dbd44cbb","impliedFormat":99},{"version":"ed84d5043444d51e1e5908f664addc4472c227b9da8401f13daa565f23624b6e","impliedFormat":99},{"version":"146bf888b703d8baa825f3f2fb1b7b31bda5dff803e15973d9636cdda33f4af3","impliedFormat":99},{"version":"b4ec8b7a8d23bdf7e1c31e43e5beac3209deb7571d2ccf2a9572865bf242da7c","impliedFormat":99},{"version":"3fba0d61d172091638e56fba651aa1f8a8500aac02147d29bd5a9cc0bc8f9ec2","impliedFormat":99},{"version":"a5a57deb0351b03041e0a1448d3a0cc5558c48e0ed9b79b69c99163cdca64ad8","impliedFormat":99},{"version":"9bcecf0cbc2bfc17e33199864c19549905309a0f9ecc37871146107aac6e05ae","impliedFormat":99},{"version":"d6a211db4b4a821e93c978add57e484f2a003142a6aef9dbfa1fe990c66f337b","impliedFormat":99},{"version":"bd4d10bd44ce3f630dd9ce44f102422cb2814ead5711955aa537a52c8d2cae14","impliedFormat":99},{"version":"08e4c39ab1e52eea1e528ee597170480405716bae92ebe7a7c529f490afff1e0","impliedFormat":99},{"version":"625bb2bc3867557ea7912bd4581288a9fca4f3423b8dffa1d9ed57fafc8610e3","impliedFormat":99},{"version":"d1992164ecc334257e0bef56b1fd7e3e1cea649c70c64ffc39999bb480c0ecdf","impliedFormat":99},{"version":"a53ff2c4037481eb357e33b85e0d78e8236e285b6428b93aa286ceea1db2f5dc","impliedFormat":99},{"version":"4fe608d524954b6857d78857efce623852fcb0c155f010710656f9db86e973a5","impliedFormat":99},{"version":"b53b62a9838d3f57b70cc456093662302abb9962e5555f5def046172a4fe0d4e","impliedFormat":99},{"version":"9866369eb72b6e77be2a92589c9df9be1232a1a66e96736170819e8a1297b61f","impliedFormat":99},{"version":"43abfbdf4e297868d780b8f4cfdd8b781b90ecd9f588b05e845192146a86df34","impliedFormat":99},{"version":"582419791241fb851403ae4a08d0712a63d4c94787524a7419c2bc8e0eb1b031","impliedFormat":99},{"version":"18437eeb932fe48590b15f404090db0ab3b32d58f831d5ffc157f63b04885ee5","impliedFormat":99},{"version":"0c5eaedf622d7a8150f5c2ec1f79ac3d51eea1966b0b3e61bfdea35e8ca213a7","impliedFormat":99},{"version":"fac39fc7a9367c0246de3543a6ee866a0cf2e4c3a8f64641461c9f2dac0d8aae","impliedFormat":99},{"version":"3b9f559d0200134f3c196168630997caedeadc6733523c8b6076a09615d5dec8","impliedFormat":99},{"version":"932af64286d9723da5ef7b77a0c4229829ce8e085e6bcc5f874cb0b83e8310d4","impliedFormat":99},{"version":"adeb9278f11f5561157feee565171c72fd48f5fe34ed06f71abf24e561fcaa1e","impliedFormat":99},{"version":"2269fef79b4900fc6b08c840260622ca33524771ff24fda5b9101ad98ea551f3","impliedFormat":99},{"version":"73d47498a1b73d5392d40fb42a3e7b009ae900c8423f4088c4faa663cc508886","impliedFormat":99},{"version":"7efc34cdc4da0968c3ba687bc780d5cacde561915577d8d1c1e46c7ac931d023","impliedFormat":99},{"version":"3c20a3bb0c50c819419f44aa55acc58476dad4754a16884cef06012d02b0722f","impliedFormat":99},{"version":"4569abf6bc7d51a455503670f3f1c0e9b4f8632a3b030e0794c61bfbba2d13be","impliedFormat":99},{"version":"98b2297b4dc1404078a54b61758d8643e4c1d7830af724f3ed2445d77a7a2d57","impliedFormat":99},{"version":"952ba89d75f1b589e07070fea2d8174332e3028752e76fd46e1c16cc51e6e2af","impliedFormat":99},{"version":"b6c9a2deefb6a57ff68d2a38d33c34407b9939487fc9ee9f32ba3ecf2987a88a","impliedFormat":99},{"version":"f6b371377bab3018dac2bca63e27502ecbd5d06f708ad7e312658d3b5315d948","impliedFormat":99},{"version":"31947dd8f1c8eeb7841e1f139a493a73bd520f90e59a6415375d0d8e6a031f01","impliedFormat":99},{"version":"95cd83b807e10b1af408e62caf5fea98562221e8ddca9d7ccc053d482283ddda","impliedFormat":99},{"version":"19287d6b76288c2814f1633bdd68d2b76748757ffd355e73e41151644e4773d6","impliedFormat":99},{"version":"fc4e6ec7dade5f9d422b153c5d8f6ad074bd9cc4e280415b7dc58fb5c52b5df1","impliedFormat":99},{"version":"3aea973106e1184db82d8880f0ca134388b6cbc420f7309d1c8947b842886349","impliedFormat":99},{"version":"765e278c464923da94dda7c2b281ece92f58981642421ae097862effe2bd30fa","impliedFormat":99},{"version":"de260bed7f7d25593f59e859bd7c7f8c6e6bb87e8686a0fcafa3774cb5ca02d8","impliedFormat":99},{"version":"b5c341ce978f5777fbe05bc86f65e9906a492fa6b327bda3c6aae900c22e76c6","impliedFormat":99},{"version":"686ddbfaf88f06b02c6324005042f85317187866ca0f8f4c9584dd9479653344","impliedFormat":99},{"version":"7f789c0c1db29dd3aab6e159d1ba82894a046bf8df595ac48385931ae6ad83e0","impliedFormat":99},{"version":"8eb3057d4fe9b59b2492921b73a795a2455ebe94ccb3d01027a7866612ead137","impliedFormat":99},{"version":"1e43c5d7aee1c5ec20611e28b5417f5840c75d048de9d7f1800d6808499236f8","impliedFormat":99},{"version":"d42610a5a2bee4b71769968a24878885c9910cd049569daa2d2ee94208b3a7a5","impliedFormat":99},{"version":"f6ed95506a6ed2d40ed5425747529befaa4c35fcbbc1e0d793813f6d725690fa","impliedFormat":99},{"version":"a6fcc1cd6583939506c906dff1276e7ebdc38fbe12d3e108ba38ad231bd18d97","impliedFormat":99},{"version":"ed13354f0d96fb6d5878655b1fead51722b54875e91d5e53ef16de5b71a0e278","impliedFormat":99},{"version":"1193b4872c1fb65769d8b164ca48124c7ebacc33eae03abf52087c2b29e8c46c","impliedFormat":99},{"version":"af682dfabe85688289b420d939020a10eb61f0120e393d53c127f1968b3e9f66","impliedFormat":99},{"version":"0dca04006bf13f72240c6a6a502df9c0b49c41c3cab2be75e81e9b592dcd4ea8","impliedFormat":99},{"version":"79d6ac4a2a229047259116688f9cd62fda25422dee3ad304f77d7e9af53a41ef","impliedFormat":99},{"version":"64534c17173990dc4c3d9388d16675a059aac407031cfce8f7fdffa4ee2de988","impliedFormat":99},{"version":"ba46d160a192639f3ca9e5b640b870b1263f24ac77b6895ab42960937b42dcbb","impliedFormat":99},{"version":"5e5ddd6fc5b590190dde881974ab969455e7fad61012e32423415ae3d085b037","impliedFormat":99},{"version":"1c16fd00c42b60b96fe0fa62113a953af58ddf0d93b0a49cb4919cf5644616f0","impliedFormat":99},{"version":"eb240c0e6b412c57f7d9a9f1c6cd933642a929837c807b179a818f6e8d3a4e44","impliedFormat":99},{"version":"4a7bde5a1155107fc7d9483b8830099f1a6072b6afda5b78d91eb5d6549b3956","impliedFormat":99},{"version":"3c1baaffa9a24cc7ef9eea6b64742394498e0616b127ca630aca0e11e3298006","impliedFormat":99},{"version":"87ca1c31a326c898fa3feb99ec10750d775e1c84dbb7c4b37252bcf3742c7b21","impliedFormat":99},{"version":"d7bd26af1f5457f037225602035c2d7e876b80d02663ab4ca644099ad3a55888","impliedFormat":99},{"version":"2ad0a6b93e84a56b64f92f36a07de7ebcb910822f9a72ad22df5f5d642aff6f3","impliedFormat":99},{"version":"523d1775135260f53f672264937ee0f3dc42a92a39de8bee6c48c7ea60b50b5a","impliedFormat":99},{"version":"e441b9eebbc1284e5d995d99b53ed520b76a87cab512286651c4612d86cd408e","impliedFormat":99},{"version":"76f853ee21425c339a79d28e0859d74f2e53dee2e4919edafff6883dd7b7a80f","impliedFormat":99},{"version":"00cf042cd6ba1915648c8d6d2aa00e63bbbc300ea54d28ed087185f0f662e080","impliedFormat":99},{"version":"f57e6707d035ab89a03797d34faef37deefd3dd90aa17d90de2f33dce46a2c56","impliedFormat":99},{"version":"cc8b559b2cf9380ca72922c64576a43f000275c72042b2af2415ce0fb88d7077","impliedFormat":99},{"version":"1a337ca294c428ba8f2eb01e887b28d080ee4a4307ae87e02e468b1d26af4a74","impliedFormat":99},{"version":"5a15362fc2e72765a908c0d4dd89e3ab3b763e8bc8c23f19234a709ecfd202fe","impliedFormat":99},{"version":"2dffdfe62ac8af0943853234519616db6fd8958fc7ff631149fd8364e663f361","impliedFormat":99},{"version":"5dbdb2b2229b5547d8177c34705272da5a10b8d0033c49efbc9f6efba5e617f2","impliedFormat":99},{"version":"6fc0498cd8823d139004baff830343c9a0d210c687b2402c1384fb40f0aa461c","impliedFormat":99},{"version":"8492306a4864a1dc6fc7e0cc0de0ae9279cbd37f3aae3e9dc1065afcdc83dddc","impliedFormat":99},{"version":"c011b378127497d6337a93f020a05f726db2c30d55dc56d20e6a5090f05919a6","impliedFormat":99},{"version":"f4556979e95a274687ae206bbab2bb9a71c3ad923b92df241d9ab88c184b3f40","impliedFormat":99},{"version":"50e82bb6e238db008b5beba16d733b77e8b2a933c9152d1019cf8096845171a4","impliedFormat":99},{"version":"d6011f8b8bbf5163ef1e73588e64a53e8bf1f13533c375ec53e631aad95f1375","impliedFormat":99},{"version":"693cd7936ac7acfa026d4bcb5801fce71cec49835ba45c67af1ef90dbfd30af7","impliedFormat":99},{"version":"195e2cf684ecddfc1f6420564535d7c469f9611ce7a380d6e191811f84556cd2","impliedFormat":99},{"version":"1dc6b6e7b2a7f2962f31c77f4713f3a5a132bbe14c00db75d557568fe82e4311","impliedFormat":99},{"version":"add93b1180e9aaac2dae4ef3b16f7655893e2ecbe62bd9e48366c305f0063d89","impliedFormat":99},{"version":"594bd896fe37c970aafb7a376ebeec4c0d636b62a5f611e2e27d30fb839ad8a5","impliedFormat":99},{"version":"b1c6a6faf60542ba4b4271db045d7faea56e143b326ef507d2797815250f3afc","impliedFormat":99},{"version":"8c8b165beb794260f462679329b131419e9f5f35212de11c4d53e6d4d9cbedf6","impliedFormat":99},{"version":"ee5a4cf57d49fcf977249ab73c690a59995997c4672bb73fcaaf2eed65dbd1b2","impliedFormat":99},{"version":"f9f36051f138ab1c40b76b230c2a12b3ce6e1271179f4508da06a959f8bee4c1","impliedFormat":99},{"version":"9dc2011a3573d271a45c12656326530c0930f92539accbec3531d65131a14a14","impliedFormat":99},{"version":"091521ce3ede6747f784ae6f68ad2ea86bbda76b59d2bf678bcad2f9d141f629","impliedFormat":99},{"version":"202c2be951f53bafe943fb2c8d1245e35ed0e4dfed89f48c9a948e4d186dd6d4","impliedFormat":99},{"version":"c618aead1d799dbf4f5b28df5a6b9ce13d72722000a0ec3fe90a8115b1ea9226","impliedFormat":99},{"version":"9b0bf59708549c3e77fddd36530b95b55419414f88bbe5893f7bc8b534617973","impliedFormat":99},{"version":"7e216f67c4886f1bde564fb4eebdd6b185f262fe85ad1d6128cad9b229b10354","impliedFormat":99},{"version":"cd51e60b96b4d43698df74a665aa7a16604488193de86aa60ec0c44d9f114951","impliedFormat":99},{"version":"b63341fb6c7ba6f2aeabd9fc46b43e6cc2d2b9eec06534cfd583d9709f310ec2","impliedFormat":99},{"version":"be2af50c81b15bcfe54ad60f53eb1c72dae681c72d0a9dce1967825e1b5830a3","impliedFormat":99},{"version":"be5366845dfb9726f05005331b9b9645f237f1ddc594c0def851208e8b7d297b","impliedFormat":99},{"version":"5ddd536aaeadd4bf0f020492b3788ed209a7050ce27abec4e01c7563ff65da81","impliedFormat":99},{"version":"e243b24da119c1ef0d79af2a45217e50682b139cb48e7607efd66cc01bd9dcda","impliedFormat":99},{"version":"5b1398c8257fd180d0bf62e999fe0a89751c641e87089a83b24392efda720476","impliedFormat":99},{"version":"1588b1359f8507a16dbef67cd2759965fc2e8d305e5b3eb71be5aa9506277dff","impliedFormat":99},{"version":"4c99f2524eee1ec81356e2b4f67047a4b7efaf145f1c4eb530cd358c36784423","impliedFormat":99},{"version":"b30c6b9f6f30c35d6ef84daed1c3781e367f4360171b90598c02468b0db2fc3d","impliedFormat":99},{"version":"79c0d32274ccfd45fae74ac61d17a2be27aea74c70806d22c43fc625b7e9f12a","impliedFormat":99},{"version":"1b7e3958f668063c9d24ac75279f3e610755b0f49b1c02bb3b1c232deb958f54","impliedFormat":99},{"version":"779d4022c3d0a4df070f94858a33d9ebf54af3664754536c4ce9fd37c6f4a8db","impliedFormat":99},{"version":"e662f063d46aa8c088edffdf1d96cb13d9a2cbf06bc38dc6fc62b4d125fb7b49","impliedFormat":99},{"version":"d1d612df1e41c90d9678b07740d13d4f8e6acec2f17390d4ff4be5c889a6d37d","impliedFormat":99},{"version":"c95933fe140918892d569186f17b70ef6b1162f851a0f13f6a89e8f4d599c5a1","impliedFormat":99},{"version":"1d8d30677f87c13c2786980a80750ac1e281bdb65aa013ea193766fe9f0edd74","impliedFormat":99},{"version":"4661673cbc984b8a6ee5e14875a71ed529b64e7f8e347e12c0db4cecc25ad67d","impliedFormat":99},{"version":"7f980a414274f0f23658baa9a16e21d828535f9eac538e2eab2bb965325841db","impliedFormat":99},{"version":"20fb747a339d3c1d4a032a31881d0c65695f8167575e01f222df98791a65da9b","impliedFormat":99},{"version":"dd4e7ebd3f205a11becf1157422f98db675a626243d2fbd123b8b93efe5fb505","impliedFormat":99},{"version":"43ec6b74c8d31e88bb6947bb256ad78e5c6c435cbbbad991c3ff39315b1a3dba","impliedFormat":99},{"version":"b27242dd3af2a5548d0c7231db7da63d6373636d6c4e72d9b616adaa2acef7e1","impliedFormat":99},{"version":"e0ee7ba0571b83c53a3d6ec761cf391e7128d8f8f590f8832c28661b73c21b68","impliedFormat":99},{"version":"072bfd97fc61c894ef260723f43a416d49ebd8b703696f647c8322671c598873","impliedFormat":99},{"version":"e70875232f5d5528f1650dd6f5c94a5bed344ecf04bdbb998f7f78a3c1317d02","impliedFormat":99},{"version":"8e495129cb6cd8008de6f4ff8ce34fe1302a9e0dcff8d13714bd5593be3f7898","impliedFormat":99},{"version":"418a98fd7dc017fc0bc714e4388015b64a7f45ee22a42ca1544edda611f9c215","signature":"46ffb83f1da0b20b82a4e724d4613d279549dac9762bf6b293a2f64da3ac7fb9"},{"version":"b9b85a68b5f9dad8a40c544f1e043217819d27f78b85b8253ef2b201b0cc1537","signature":"02206236174c891ecdf9bebf737d33c3ed1a994d0b7b8d29935bab15a2bbef25"},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"2540a81fc4127527aa85f3ae75e7e50f006b42d5745130a4de8911c6f881f042","signature":"bb0dfbd93a35b232bb2b36042266c565e235afd18be59f6568c76ce998c22234"},{"version":"a819987422b352c826c0140d0d14ad43dad9a730f8f2e12a91f6767c289941e7","signature":"d5e59c996b40dc9c1c7118299a6f9b395e136bb6bf103f945476d478b0896a64"},{"version":"2b9c1bf9fd5c0f4e357c58e872143f2dab3f56905336cc64f55e7bf794fbd7cb","signature":"f3395d0ee087666e598fac578c718cb2e3e6256930de1dce6a1b5f668048eb73"},{"version":"b725009c2704e5564aa115bb7a17ddb5a7238e51cec43cb13a59796537033c8c","signature":"d53102ee8f9dde481924fff31932d4e6e9dc88a6eb7de6fc9169144aac6c0045"},{"version":"e5beb5a284ec7a63debb18e55e0656227b5a100ae40c0dd7a39e2d8ba759dfd3","signature":"9d7ca13208db755a4127916edcdea4289dc3703282c1ab41647c1675d8bc2af4"},{"version":"149450e8942fbf2288867fe91719931f0aa33bbbbaf382beaaa2486d562a791e","signature":"b82d20e741db1b8aa501ad9c0c5771c8d79e92a9ff342543e7a56970fce5d051"},{"version":"a78fd7c0e1da6b06c86b4861502afe097e03cdbba5c54a5347484ead7d934a74","signature":"771a12fa01413532c912aaf29185ea8b6b19da1377411dc82dc0d8428099edd4"},{"version":"4998ee1eb122f4f43b2444a16ae9951992d56cef923965266854c23ad8bf1afc","signature":"2558f1b3d92e2ed74c72ff1c36ababedfd53d971235ab3cc0039e5c3d7805535"},{"version":"b871d83bbbff7b4fae762784fa9ca6f3cfd878ea6926dad6d4cd4f5fc9c1e3cd","signature":"610bf24bed3f13cf7c87dd6acd500825e6db22f10f3ac1fd3bb031f0c5b6a756"},{"version":"02b3b77a8d29c9ac409edc1c7a4efa339e2a07e3c5b5e6ea16f108c6eef9e20e","impliedFormat":99},{"version":"ad2019bdab0ec396959c19dbfcb838f53fb47065488aeb83d7adccf36db75554","impliedFormat":99},{"version":"d5602055e69da5aaf7dafa987dbf645f608f8c66536c7965680fe65420fed2fe","impliedFormat":99},{"version":"41a5ae482e864a6128e6054e88f1c0e06884793f92aff5c67144fb02d2373079","impliedFormat":1},{"version":"b8f01261ee1417ef9ca6e0e55e4b66ce3eaf79e711f8d165b27f4d211dc9fb24","impliedFormat":99},{"version":"b06f68391bbdb8d64498b6510bb4211519049ae526d0026e84d5afd0dca9043f","impliedFormat":99},{"version":"fe6b53077c7fe54f4d5fa980454f29443441c6187f9aede54913211c3f9ae35d","signature":"7d70a28a148c5af9142e1f023e432720496c19a2dc018143c5f78e289253d239"},{"version":"a2be484586eefae384f39b584ad74ad6faaaf66e2e10f8347f6e7146fa267e8c","signature":"af624c72b28ea8c3ee0255b4af1ddabbe40f7d4c8cd6539c5e4e4356f39e0b27"},{"version":"b006a72204a91eeb31f00e99b5edb8822c07527bd1f01eab38b4b3c339cb8bc3","signature":"0f8c10b10a120c51e7df066f7c08bc60edbf9545fbd1ba411ef87f914b6527a8"},{"version":"e21b87998c4d8f5d797a877e9697d73122da5d6e0c5efe27e1eb69409d520b01","signature":"233bf868506e6fb7576da957ddead506efb374fe8b70a1b56e0114f231fdadbb"},{"version":"a250988882bec3727c5eaa0db350c0e991cb7c3ac7cb1fa3d91e25bdc2e65f17","signature":"a2e3213c37e776988abf406671f65fa417a62130ee3306dbd72cf5ef3e3a0add"},{"version":"d5679c70e2e7c23aed053e4e9dbca8ecfa4525a63f01287a7535a514bf9d6ec2","signature":"3a2b94b8d6b92049dd79d645451939beaaeebf2be8cb77d93df721ebc346dc4e"},{"version":"648121f492237c22f218e1ed70df8dca4cb70613eb006acd5ef01a9487ef6ab0","signature":"5290014c476c8f6ad526b7cd998607934ab68084c6e5fed468ee72decc7e72bd"},{"version":"e284e1e255ee0e2a0f4460fc3d96592a80a9c1b10b21d34e86e79b3b7b26ff08","signature":"72b0baebadf8eb1b7a2ccda8243046425c0cbcb5089a91bcd71c5a6d6be0a05b","affectsGlobalScope":true},{"version":"968477d488b4aff44c6c907618762357549923f44cfc7e2c09dde3bad0fa8364","signature":"065c6f1242fa9f1625a2390c5012297b298ae2ab5c731ebf46d86bdc532e71cc"},{"version":"c5654c33eae2ce81756908262351bf7a519ec33b4e832a12c26051c9e3e88397","signature":"d1f66dca664230719454dc8753943731716c9ae953fb9bdbd8db20c2d94b11d4"},{"version":"8ebf26c5f329d94e418d5553f740c7caf22bceff93a1ce4ca6869fde265b4ec7","signature":"ddbbe35c9202b52463c3106ce335e89cfa0917db04e869ca464e7fcaff1cca40"},{"version":"a5a3c3723869145e7590e1be322356252c0e2c655fb2c08c5be0887bfbd57c89","signature":"7b87720aae5dbfb749d597c437531239e4019502dc0e78633561735db617b6f3"}],"root":[494,495,561,562,[570,573],575,877],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":2},"referencedMap":[[494,1],[561,2],[562,3],[570,4],[571,4],[572,5],[575,6],[877,7],[495,8],[543,9],[508,10],[509,11],[514,12],[503,13],[512,14],[518,15],[544,16],[521,17],[507,18],[504,19],[502,20],[511,21],[500,22],[510,23],[505,24],[517,25],[519,26],[525,27],[534,28],[537,29],[536,30],[535,31],[533,32],[539,33],[515,34],[532,35],[527,36],[528,37],[538,38],[516,39],[531,40],[530,41],[529,34],[540,42],[542,43],[524,44],[522,45],[523,46],[526,47],[541,39],[585,48],[850,49],[586,48],[587,50],[581,51],[92,52],[93,52],[132,53],[133,54],[134,55],[135,56],[136,57],[137,58],[138,59],[139,60],[140,61],[141,62],[142,62],[144,63],[143,64],[145,65],[146,66],[147,67],[131,68],[148,69],[149,70],[150,71],[183,72],[151,73],[152,74],[153,75],[154,76],[155,77],[156,78],[157,79],[158,80],[159,81],[160,82],[161,82],[162,83],[164,84],[166,85],[165,86],[167,20],[168,87],[169,88],[170,89],[171,90],[172,91],[173,92],[174,93],[175,94],[176,95],[177,96],[178,97],[179,98],[180,99],[181,100],[187,101],[399,48],[188,102],[186,48],[400,103],[184,104],[185,105],[85,106],[396,48],[269,48],[583,107],[582,108],[678,109],[657,110],[658,111],[594,109],[595,109],[596,109],[597,109],[598,109],[599,109],[600,109],[601,109],[602,109],[603,109],[604,109],[605,109],[606,109],[607,109],[608,109],[609,109],[610,109],[611,109],[612,109],[613,109],[615,109],[616,109],[618,109],[617,109],[619,109],[620,109],[621,109],[622,109],[623,109],[624,109],[625,109],[626,109],[627,109],[628,109],[629,109],[630,109],[631,109],[632,109],[633,109],[634,109],[635,109],[636,109],[637,109],[639,109],[640,109],[641,109],[638,109],[642,109],[643,109],[644,109],[645,109],[646,109],[647,109],[648,109],[649,109],[650,109],[651,109],[652,109],[653,109],[654,109],[655,109],[656,109],[659,112],[660,109],[661,109],[662,113],[663,114],[664,109],[665,109],[666,109],[667,109],[670,109],[668,109],[669,109],[671,109],[672,109],[673,109],[674,109],[675,109],[676,109],[677,109],[679,115],[680,109],[681,109],[682,109],[684,109],[683,109],[685,109],[686,109],[687,109],[688,109],[689,109],[690,109],[691,109],[692,109],[693,109],[694,109],[696,109],[695,109],[697,109],[847,116],[701,109],[702,109],[703,109],[704,109],[705,109],[706,109],[708,109],[710,109],[711,109],[712,109],[713,109],[714,109],[715,109],[716,109],[717,109],[718,109],[719,109],[720,109],[721,109],[722,109],[723,109],[724,109],[725,109],[726,109],[727,109],[728,109],[729,109],[730,109],[731,109],[732,109],[733,109],[734,109],[735,109],[736,109],[737,109],[738,109],[739,109],[740,109],[741,109],[743,109],[744,109],[745,109],[746,109],[747,109],[748,109],[749,109],[750,109],[751,109],[752,109],[753,109],[755,117],[591,109],[756,109],[757,109],[761,109],[767,109],[768,109],[769,109],[770,109],[771,109],[772,109],[773,109],[774,109],[779,118],[777,119],[778,120],[776,121],[775,109],[780,109],[781,109],[782,109],[783,109],[784,109],[785,109],[786,109],[787,109],[788,109],[789,109],[792,109],[793,109],[797,109],[798,109],[799,109],[800,109],[801,115],[802,109],[803,109],[804,109],[805,109],[806,109],[807,109],[808,109],[809,109],[810,109],[811,109],[812,109],[813,109],[814,109],[815,109],[816,109],[817,109],[818,109],[819,109],[820,109],[821,109],[822,109],[823,109],[824,109],[825,109],[826,109],[827,109],[828,109],[829,109],[830,109],[831,109],[832,109],[833,109],[834,109],[835,109],[836,109],[837,109],[838,109],[839,109],[840,109],[841,109],[842,109],[593,122],[589,48],[441,123],[446,124],[436,125],[218,126],[256,127],[423,128],[251,129],[413,130],[282,131],[210,132],[259,133],[260,134],[395,135],[410,136],[306,137],[417,138],[418,139],[416,140],[414,141],[258,142],[219,143],[350,144],[242,145],[220,146],[287,145],[284,145],[197,145],[254,147],[422,148],[371,149],[372,150],[366,48],[375,51],[367,151],[474,152],[473,153],[409,154],[467,155],[368,48],[208,156],[205,157],[472,158],[206,159],[460,160],[463,161],[294,162],[293,163],[292,164],[477,48],[291,165],[482,48],[484,166],[419,167],[420,168],[421,169],[202,170],[387,48],[195,171],[386,172],[385,173],[382,174],[380,175],[383,176],[381,175],[201,145],[270,177],[271,178],[268,179],[266,180],[267,181],[393,51],[309,51],[440,182],[447,183],[451,184],[426,185],[485,186],[435,187],[369,188],[370,189],[364,190],[392,191],[356,192],[394,193],[389,194],[348,195],[427,196],[428,197],[358,198],[362,199],[353,200],[405,201],[434,202],[286,203],[325,204],[198,205],[433,206],[194,207],[272,208],[273,209],[337,210],[336,211],[330,212],[351,213],[334,214],[274,215],[360,216],[424,217],[339,218],[340,219],[342,220],[344,221],[343,222],[332,205],[346,223],[331,224],[338,225],[232,226],[318,227],[323,228],[319,229],[322,230],[321,230],[324,228],[320,229],[241,231],[310,232],[431,233],[455,234],[457,235],[357,236],[456,237],[429,196],[373,196],[311,238],[238,239],[239,240],[240,241],[236,242],[404,242],[288,242],[312,243],[289,243],[235,244],[316,245],[315,246],[314,247],[313,248],[430,249],[403,250],[402,251],[365,252],[398,253],[401,254],[412,255],[411,256],[407,257],[305,258],[307,259],[304,260],[345,261],[347,262],[275,263],[354,167],[352,264],[277,265],[280,266],[278,267],[281,267],[283,268],[302,269],[209,270],[193,271],[449,48],[459,272],[301,48],[453,51],[300,273],[438,274],[299,272],[461,275],[297,48],[298,48],[296,276],[295,277],[245,278],[363,81],[285,81],[328,279],[391,159],[303,48],[439,280],[86,48],[89,281],[90,282],[87,48],[255,283],[250,284],[248,285],[437,286],[448,287],[450,288],[452,289],[454,290],[458,291],[492,292],[462,292],[491,293],[464,294],[475,295],[476,296],[478,297],[487,298],[490,170],[488,299],[499,300],[329,301],[864,302],[861,303],[865,304],[110,305],[119,306],[109,305],[128,307],[101,308],[100,309],[127,299],[121,310],[126,311],[103,312],[102,313],[124,314],[98,315],[97,316],[125,317],[99,318],[104,319],[108,319],[130,300],[129,319],[112,320],[113,321],[115,322],[111,323],[114,324],[122,299],[106,325],[107,326],[116,327],[96,328],[118,329],[117,319],[123,330],[549,331],[547,332],[545,333],[546,334],[548,335],[569,336],[568,333],[874,333],[875,337],[873,333],[876,338],[496,333],[497,333],[559,339],[558,340],[871,341],[872,342],[563,333],[564,333],[565,343],[567,344],[566,333],[556,345],[554,346],[553,333],[552,347],[557,348],[555,349],[551,333],[560,350],[550,333],[857,351],[848,352],[855,353],[849,354],[852,355],[856,353],[854,356],[853,356],[859,357],[858,358],[866,359],[867,51],[868,360],[870,361],[584,361],[580,362],[851,363],[588,364],[869,362],[578,365],[579,366]],"semanticDiagnosticsPerFile":[[560,[{"start":1472,"length":3,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"messageText":"Overload 1 of 4, '(algorithm: CipherGCMTypes, key: CipherKey, iv: BinaryLike, options?: CipherGCMOptions | undefined): DecipherGCM', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]},{"messageText":"Overload 2 of 4, '(algorithm: string, key: CipherKey, iv: BinaryLike | null, options?: TransformOptions | undefined): Decipher', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]}]},"relatedInformation":[]},{"start":1505,"length":7,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":1555,"length":9,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":1570,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Buffer & string'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'string'.","category":1,"code":2322}]}},{"start":1597,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'."}}]}]}},{"start":1608,"length":16,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}}]],[562,[{"start":1071,"length":3,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'string | ArrayBufferView | Iterable | AsyncIterable | Stream'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | Iterable | AsyncIterable<...> | Stream'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":1361,"length":3,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"messageText":"Overload 1 of 4, '(algorithm: CipherGCMTypes, key: CipherKey, iv: BinaryLike, options?: CipherGCMOptions | undefined): CipherGCM', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]},{"messageText":"Overload 2 of 4, '(algorithm: string, key: CipherKey, iv: BinaryLike | null, options?: TransformOptions | undefined): Cipher', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]}]},"relatedInformation":[]},{"start":1450,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}},{"start":1461,"length":14,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}},{"start":2196,"length":3,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"messageText":"Overload 1 of 4, '(algorithm: CipherGCMTypes, key: CipherKey, iv: BinaryLike, options?: CipherGCMOptions | undefined): DecipherGCM', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]},{"messageText":"Overload 2 of 4, '(algorithm: string, key: CipherKey, iv: BinaryLike | null, options?: TransformOptions | undefined): Decipher', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]}]},"relatedInformation":[]},{"start":2229,"length":7,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":2279,"length":9,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":2294,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Buffer & string'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'string'.","category":1,"code":2322}]}},{"start":2321,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'."}}]}]}},{"start":2332,"length":16,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}}]],[873,[{"start":117,"length":7,"messageText":"Subsequent property declarations must have the same type. Property 'desktop' must be of type 'DesktopAPI | undefined', but here has type '{ getPrimaryScreenSource?: (() => Promise) | undefined; } | undefined'.","category":1,"code":2717,"relatedInformation":[{"file":"./src/types/desktop.d.ts","start":1203,"length":7,"messageText":"'desktop' was also declared here.","category":3,"code":6203}]}]]],"affectedFilesPendingEmit":[561,562,570,571,572,575,877,495,549,547,545,546,548,569,568,874,875,873,876,496,497,559,558,871,872,563,564,565,567,566,556,554,553,552,557,555,551,560,550,857,848,855,849,852,856,854,853,859,858,866,867,868,870,584,580,851,588,869,578,579],"version":"5.9.3"} \ No newline at end of file +{"fileNames":["../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2024.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.float16.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.error.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/css.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/macro.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/style.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/global.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/styled-jsx/types/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/get-page-files.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/assert.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/assert/strict.d.ts","../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/header.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/readable.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/file.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/fetch.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/formdata.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/connector.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/client.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/errors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/dispatcher.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/global-origin.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/pool-stats.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/handlers.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/balanced-pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-client.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-pool.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/mock-errors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/proxy-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/retry-handler.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/retry-agent.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/api.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/util.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/cookies.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/patch.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/websocket.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/eventsource.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/filereader.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/content-type.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/cache.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/interceptors.d.ts","../../node_modules/.pnpm/undici-types@6.11.1/node_modules/undici-types/index.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/globals.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/async_hooks.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/buffer.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/child_process.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/cluster.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/console.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/constants.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/crypto.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dgram.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dns.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dns/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/domain.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/dom-events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/fs.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/fs/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/http.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/http2.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/https.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/inspector.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/module.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/net.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/os.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/path.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/perf_hooks.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/process.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/punycode.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/querystring.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/readline.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/readline/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/repl.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/sea.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/consumers.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/stream/web.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/string_decoder.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/test.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/timers.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/timers/promises.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/tls.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/trace_events.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/tty.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/url.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/util.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/v8.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/vm.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/wasi.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/worker_threads.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/zlib.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/globals.global.d.ts","../../node_modules/.pnpm/@types+node@22.0.0/node_modules/@types/node/index.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/canary.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/experimental.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/index.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/canary.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/experimental.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/fallback.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/webpack/webpack.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/entry-constants.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/constants.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/load-custom-routes.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/body-streams.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/cache-control.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/setup-exception-listeners.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/worker.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/constants.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/bundler.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/experimental/ppr.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/page-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/analysis/get-page-static-info.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/require-hook.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-polyfill-crypto.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-baseline.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/random.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/date.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/node-environment.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/page-extensions-type.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-kind.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/cache-handlers/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/response-cache/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/app-router-headers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/render-result.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/instrumentation/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/coalesced-function.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/trace.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/shared.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/trace/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/load-jsconfig.d.ts","../../node_modules/.pnpm/@next+env@16.1.5/node_modules/@next/env/dist/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/telemetry/storage.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/build-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/bloom-filter.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack-config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/swc/generated-native.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/swc/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/parse-version-info.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/shared/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/parse-stack.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/server/shared.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/jsx-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/debug-channel.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/hot-reloader-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/i18n-provider.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/next-url.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/cookies.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/request.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/builtin-request-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/response.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/deep-readonly.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/render.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/mitt.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/with-router.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/router.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/route-loader.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/page-loader.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/router.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/readonly-url-search-params.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/app-router-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/flight-data-helpers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/router-reducer/ppr-navigations.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/segment-cache/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/segment-cache/navigation.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/pages.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/module.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/load-default-error-components.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-http/node.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/response-cache/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matchers/route-matcher.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/normalizer.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/suffix.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/rsc.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/next-data.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/static-paths/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/async-callback-set.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","../../node_modules/.pnpm/sharp@0.34.5/node_modules/sharp/lib/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/image-optimizer.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/next-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/lru-cache.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/dev-bundler-service.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/use-cache/cache-life.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/static-paths-worker.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/dev/next-dev-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/next.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/render-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/route-module.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/load-components.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/adapter.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/app-dir-module.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/cache-signal.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/fallback-params.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/lazy-result.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/implicit-tags.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/staged-rendering.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/app-render.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/error-boundary.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/layout-router.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/render-from-template-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/client-page.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/client-segment.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/search-params.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/hooks-server-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/extra-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/resolvers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/types/icons.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/metadata/metadata.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/lib/framework/boundary-components.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/preloads.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/postpone.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/rsc/taint.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/collect-segment-data.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/entry-base.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/app-page.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/rendering-mode.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/jsx-dev-runtime.d.ts","../../node_modules/.pnpm/@types+react@19.0.0/node_modules/@types/react/compiler-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/client.d.ts","../../node_modules/.pnpm/@types+react-dom@19.0.0/node_modules/@types/react-dom/server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/module.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/async-storage/work-store.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/http.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect-status-code.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect-error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/templates/app-route.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/module.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/segment-config/app/app-segments.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/utils.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/result.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/turborepo-access-trace/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/routes/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/export/worker.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/worker.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/lib/incremental-cache/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/after.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/after-context.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/create-error-handler.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/params.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/route-matches/route-match.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request-meta.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/cli/next-test.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/size-limit.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/config-shared.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/base-http/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/api-utils/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/build/adapter/build-complete.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/utils.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_app.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/app.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/use-cache/cache-tag.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/cache.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_document.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/document.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/dynamic.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dynamic.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/pages/_error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/head.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/head.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/cookies.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/headers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/draft-mode.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/headers.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/get-img-props.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/image-component.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/shared/lib/image-external.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/image.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/link.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/link.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unrecognized-action-error.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/redirect.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/not-found.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/forbidden.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unauthorized.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/unstable-rethrow.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/navigation.react-server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/components/navigation.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/navigation.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/router.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/client/script.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/script.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/web/spec-extension/image-response.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/@vercel/og/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/after/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/server/request/connection.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/server.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types/global.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types/compiled.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/types.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/index.d.ts","../../node_modules/.pnpm/next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/image-types/global.d.ts","./.next/types/routes.d.ts","./next-env.d.ts","./src/middleware.ts","../../packages/pipeline/note-core/src/clinical-models/clinical-note.ts","../../packages/pipeline/note-core/src/clinical-models/markdown-note.ts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/builtin-types.d.mts","../../node_modules/.pnpm/node_modules/undici-types/index.d.ts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/types.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/headers.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/shim-types.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/streaming.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/request-options.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/utils/log.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/error.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/parse.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/api-promise.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/pagination.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/uploads.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/to-file.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/uploads.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/shared.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/core/resource.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/files.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/models.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/beta-parser.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/error.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/betamessagestream.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/decoders/line.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/batches.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/messagestream.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/messages/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/versions.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/skills.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/skills/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/betarunnabletool.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/compactioncontrol.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/lib/tools/betatoolrunner.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/beta/beta.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/completions.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/models.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/resources/index.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/client.d.mts","../../node_modules/.pnpm/@anthropic-ai+sdk@0.71.2_zod@3.25.76/node_modules/@anthropic-ai/sdk/index.d.mts","../../packages/llm/src/prompts/clinical-note/templates/index.ts","../../packages/llm/src/prompts/clinical-note/v1.ts","../../packages/llm/src/prompts/clinical-note/index.ts","../../packages/llm/src/prompts/index.ts","../../packages/llm/src/index.ts","../../packages/pipeline/shared/src/error.ts","../../packages/storage/src/types.ts","../../packages/storage/src/secure-storage.ts","../../packages/storage/src/encounters.ts","../../packages/storage/src/debug-logger.ts","../../packages/storage/src/audit-log.ts","../../packages/storage/src/preferences.ts","../../packages/storage/src/api-keys.ts","../../packages/storage/src/index.ts","../../packages/pipeline/note-core/src/note-generator.ts","../../packages/pipeline/note-core/src/index.ts","../../packages/storage/src/server-api-keys.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/vendored/cookie.d.ts","../../node_modules/.pnpm/oauth4webapi@3.8.5/node_modules/oauth4webapi/build/index.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/utils/cookie.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/warnings.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/symbols.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/index.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/utils/env.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/jwt.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/utils/actions.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/index.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/utils/logger.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/webauthn.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/lib/utils/webauthn-utils.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/types.d.ts","../../node_modules/.pnpm/preact@10.24.3/node_modules/preact/src/jsx.d.ts","../../node_modules/.pnpm/preact@10.24.3/node_modules/preact/src/index.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/credentials.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/provider-types.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/nodemailer.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/email.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/oauth.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/providers/index.d.ts","../../node_modules/.pnpm/@auth+core@0.41.1/node_modules/@auth/core/adapters.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/adapters.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/types.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/general/decrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/general/encrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/compact/verify.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/flattened/verify.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/general/verify.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/verify.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/decrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/produce.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/compact/sign.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/flattened/sign.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jws/general/sign.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/sign.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/encrypt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwk/thumbprint.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwk/embedded.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwks/local.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwks/remote.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/jwt/unsecured.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/key/export.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/key/import.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/util/decode_protected_header.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/util/decode_jwt.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/util/errors.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/key/generate_key_pair.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/key/generate_secret.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/util/base64url.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/util/runtime.d.ts","../../node_modules/.pnpm/jose@4.15.9/node_modules/jose/dist/types/index.d.ts","../../node_modules/.pnpm/openid-client@5.7.1/node_modules/openid-client/types/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/oauth-types.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/oauth.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/email.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/core/lib/cookie.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/core/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/credentials.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/jwt/types.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/jwt/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/utils/logger.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/core/types.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/next/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/index.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/providers/google.d.ts","../../node_modules/.pnpm/@auth+pg-adapter@1.11.1_pg@8.20.0/node_modules/@auth/pg-adapter/index.d.ts","./src/lib/db.ts","./src/lib/auth.ts","./src/lib/compliance.ts","./src/app/actions.ts","./src/app/api/auth/[...nextauth]/route.ts","./src/lib/hipaa-config.ts","./src/lib/auth-guard.ts","./src/app/api/compliance/session/route.ts","./src/app/api/compliance/terms/route.ts","./src/lib/openemr-client.ts","./src/lib/openemr-push-handler.ts","./src/app/api/integrations/openemr/push/route.ts","./src/app/api/settings/api-keys/route.ts","./src/app/api/settings/mixed-auth-status/route.ts","../../packages/pipeline/shared/src/final-upload-error.ts","../../packages/pipeline/shared/src/index.ts","../../packages/pipeline/transcribe/src/core/wav.ts","../../packages/pipeline/transcribe/src/hooks/segment-upload-controller.ts","../../packages/pipeline/transcribe/src/hooks/use-segment-upload.ts","../../packages/pipeline/transcribe/src/providers/whisper-transcriber.ts","../../packages/pipeline/transcribe/src/providers/whisper-local-transcriber.ts","../../packages/pipeline/transcribe/src/providers/medasr-transcriber.ts","../../packages/pipeline/transcribe/src/providers/provider-resolver.ts","../../packages/pipeline/transcribe/src/index.ts","../../packages/pipeline/assemble/src/session-store.ts","../../packages/pipeline/assemble/src/index.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/types.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/command.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/scanstream.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/utils/rediscommander.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/transaction.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/utils/commander.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/abstractconnector.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/connectorconstructor.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/sentinelconnector/types.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/sentinelconnector/sentineliterator.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/sentinelconnector/index.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/connectors/standaloneconnector.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/redis/redisoptions.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/cluster/util.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/cluster/clusteroptions.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/cluster/index.d.ts","../../node_modules/.pnpm/denque@2.1.0/node_modules/denque/index.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/subscriptionset.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/datahandler.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/redis.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/pipeline.d.ts","../../node_modules/.pnpm/ioredis@5.10.0/node_modules/ioredis/built/index.d.ts","./src/lib/redis.ts","./src/lib/transcription-store.ts","./src/lib/server-logger.ts","./src/app/api/transcription/final/route.ts","./src/app/api/transcription/segment/route.ts","./src/app/api/transcription/stream/[sessionid]/route.ts","./src/lib/__tests__/openemr-client.test.ts","./src/lib/__tests__/openemr-push-handler.test.ts","./src/types/desktop.d.ts","./src/types/next-auth.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/client/_utils.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/react/types.d.ts","../../node_modules/.pnpm/next-auth@4.24.13_next@16.1.5_@opentelemetry+api@1.9.0_react-dom@19.2.0_react@19.2.0__r_4bb335da71ac294ff35e20f2a2a99573/node_modules/next-auth/react/index.d.ts","./src/app/providers.tsx","./src/app/layout.tsx","../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/clsx.d.mts","../../node_modules/.pnpm/tailwind-merge@2.5.5/node_modules/tailwind-merge/dist/types.d.ts","../../packages/ui/src/lib/utils/cn.ts","../../packages/ui/src/lib/utils/index.ts","../../packages/ui/src/lib/ui/input.tsx","../../node_modules/.pnpm/@radix-ui+react-slot@1.1.1_@types+react@19.0.0_react@19.2.0/node_modules/@radix-ui/react-slot/dist/index.d.mts","../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/types.d.ts","../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.d.ts","../../packages/ui/src/lib/ui/button.tsx","../../node_modules/.pnpm/@radix-ui+react-context@1.1.1_@types+react@19.0.0_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.d.mts","../../node_modules/.pnpm/@radix-ui+react-primitive@2.0.1_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@radix-ui/react-primitive/dist/index.d.mts","../../node_modules/.pnpm/@radix-ui+react-scroll-area@1.2.2_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom_d8f8bb762f9ee8d27d701c95d38a5f99/node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","../../packages/ui/src/lib/ui/scroll-area.tsx","../../node_modules/.pnpm/lucide-react@0.454.0_react@19.2.0/node_modules/lucide-react/dist/lucide-react.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constants.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/locale/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/fp/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/add.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/adddays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/addyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/areintervalsoverlapping.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/clamp.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/closestindexto.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/closestto.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/compareasc.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/comparedesc.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constructfrom.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constructnow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/daystoweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendardays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarisoweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendarweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceincalendaryears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceindays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinmonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/differenceinyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachdayofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachhourofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachminuteofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachmonthofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachquarterofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachweekendofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/eachyearofinterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofhour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofsecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endoftoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endoftomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/endofyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/formatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/longformatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/format.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistance.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancestrict.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancetonow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatdistancetonowstrict.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatiso.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatiso9075.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatisoduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrfc3339.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrfc7231.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/formatrelative.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/fromunixtime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdaysinmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdaysinyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/defaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getdefaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/gethours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getisoweeksinyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getoverlappingdaysinintervals.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/gettime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getunixtime.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweekofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getweeksinmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/getyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/hourstoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/interval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intervaltoduration.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intlformat.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/intlformatdistance.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isafter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isbefore.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isequal.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isexists.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfirstdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isfuture.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/islastdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isleapyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ismatch.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ismonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/ispast.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamehour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamemonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamequarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issamesecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issameyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/issunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthishour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthismonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthissecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthisyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/istuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isvalid.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/iswednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isweekend.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/iswithininterval.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/isyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lastdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/_lib/format/lightformatters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/lightformat.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/max.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/milliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/millisecondstoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/min.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/minutestoseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/monthstoquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/monthstoyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextmonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextsaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextsunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nexttuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/nextwednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/types.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/setter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parser.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse/_lib/parsers.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parse.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parseiso.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/parsejson.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousfriday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousmonday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoussaturday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoussunday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previousthursday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previoustuesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/previouswednesday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/quarterstomonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/quarterstoyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/roundtonearesthours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/roundtonearestminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstohours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstomilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/secondstominutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/set.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdayofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setdefaultoptions.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/sethours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setmilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/setyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofdecade.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofhour.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofisoweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofisoweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofminute.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofmonth.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofquarter.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofsecond.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startoftoday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startoftomorrow.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofweek.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofweekyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofyear.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/startofyesterday.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/sub.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subbusinessdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subdays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subhours.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subisoweekyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/submilliseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subminutes.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/submonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subseconds.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subweeks.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/subyears.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/todate.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/transpose.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/weekstodays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstodays.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstomonths.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/yearstoquarters.d.ts","../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/index.d.ts","../../packages/ui/src/components/encounter-list.tsx","../../packages/ui/src/components/idle-view.tsx","../../node_modules/.pnpm/@radix-ui+react-label@2.1.1_@types+react-dom@19.0.0_@types+react@19.0.0_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@radix-ui/react-label/dist/index.d.mts","../../packages/ui/src/lib/ui/label.tsx","../../packages/ui/src/components/new-encounter-form.tsx","../../packages/ui/src/components/recording-view.tsx","../../packages/ui/src/components/processing-view.tsx","../../packages/ui/src/components/error-boundary.tsx","../../packages/ui/src/components/permissions-dialog.tsx","../../packages/ui/src/components/audit-log-viewer.tsx","../../packages/ui/src/components/settings-dialog.tsx","../../packages/ui/src/components/settings-bar.tsx","../../packages/ui/src/components/model-indicator.tsx","../../packages/ui/src/components/local-setup-wizard.tsx","../../node_modules/.pnpm/swr@2.4.0_react@19.2.0/node_modules/swr/dist/_internal/events.d.mts","../../node_modules/.pnpm/swr@2.4.0_react@19.2.0/node_modules/swr/dist/_internal/types.d.mts","../../node_modules/.pnpm/swr@2.4.0_react@19.2.0/node_modules/swr/dist/_internal/constants.d.mts","../../node_modules/.pnpm/dequal@2.0.3/node_modules/dequal/index.d.ts","../../node_modules/.pnpm/swr@2.4.0_react@19.2.0/node_modules/swr/dist/_internal/index.d.mts","../../node_modules/.pnpm/swr@2.4.0_react@19.2.0/node_modules/swr/dist/index/index.d.mts","../../packages/ui/src/hooks/use-encounters.ts","../../packages/ui/src/hooks/use-https-warning.ts","../../packages/ui/src/index.ts","../../packages/ui/src/lib/ui/textarea.tsx","../../packages/ui/src/lib/ui/badge.tsx","../../packages/pipeline/render/src/components/note-editor.tsx","../../packages/pipeline/render/src/index.ts","../../packages/pipeline/audio-ingest/src/devices/system-audio.ts","../../packages/pipeline/audio-ingest/src/errors.ts","../../packages/pipeline/audio-ingest/src/capture/audio-processing.ts","../../packages/pipeline/audio-ingest/src/capture/use-audio-recorder.ts","../../packages/pipeline/audio-ingest/src/index.ts","./src/app/workflow-error-display.tsx","./src/app/page.tsx"],"fileIdsList":[[499,500,501],[261,563,568,569,640,644,645,700],[261,644],[261,495,645,649],[261,495,649,652,653],[138,146,155,261,495,563,648,649],[261,495,569,649],[261,495,563,649,658,666,692,693],[261,495,649,692],[85,261,499,704],[85,261,559,566,646,658,666,703,1000,1004,1009,1010],[85,261,703],[261,658,714],[93,169,261,652],[93,169,261,652,653],[261,495,640,644,645,648,700],[261,640,641,642,643,700],[138,261,495,643],[261],[261,652],[261,648,690],[261,648,658,668,691],[261,495],[640,700],[506,508,509,512,513,514,516,517,520,534,547,548,549,550],[508,515,551],[512,515,516,551],[551],[510,551],[518,519],[514],[514,516,517,520,551],[528],[512,517,551],[506,508,509,511],[167],[506],[130],[506,512,551],[512,551],[546,551],[512,525,526,546,551],[512,526,532],[541],[512,527,541,542,544,552],[543],[550],[540],[522,523,524,538,546],[512,516,517,520,522,547],[523,524,536,539,547],[512,516,517,522,529,534,546,547],[535,546],[511,512,516,522,525,527,534,535,545,546,547],[512,516,517,522,547],[537,538],[512,516,517,520,522,537,547],[511,512,516,522,534,547,548],[521,534,547,548,549],[531],[512,516,517,521,522,529,534],[530,534],[511,512,516,522,530,533,534],[583,591,593],[574,575,576,577,578,580,583,591,592],[580,583],[574],[583],[579,583],[573,579],[572,581,583,592],[583,585,591],[583,587,588,591],[581,583,586,589,590],[583,589],[571,574,579,583,587,591],[583,591],[570,571,572,573,579,580,582,591],[592],[85],[85,716],[85,715,716],[85,261],[92],[132],[133,138,167],[134,139,145,146,153,164,175],[134,135,145,153],[136,176],[137,138,146,154],[138,164,172],[139,141,145,153],[132,140],[141,142],[145],[143,145],[132,145],[145,146,147,164,175],[145,146,147,160,164,167],[130,133,180],[141,145,148,153,164,175],[145,146,148,149,153,164,172,175],[148,150,164,172,175],[92,93,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182],[145,151],[152,175,180],[141,145,153,164],[154],[155],[132,156],[153,154,157,174,180],[158],[159],[145,160,161],[160,162,176,178],[133,145,164,165,166,167],[133,164,166],[164,165],[168],[132,164],[145,170,171],[170,171],[138,153,164,172],[173],[153,174],[133,148,159,175],[138,176],[164,177],[152,178],[179],[133,138,145,147,156,164,175,178,180],[164,181],[85,186,188],[85,186,187],[85,404],[85,89,185,446,492],[85,89,184,446,492],[83,84],[706,712],[706],[723],[721,723],[721],[723,787,788],[723,790],[723,791],[808],[723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976],[723,884],[723,788,908],[721,905,906],[907],[723,905],[720,721,722],[141,183,674,681,682],[145,183,669,670,671,673,674,682,683,688],[141,183],[183,669],[669],[675],[145,172,183,669,675,677,678,683],[677],[681],[153,172,183,669,675],[145,183,669,685,686],[669,670,671,672,675,679,680,681,682,683,684,688,689],[670,674,684,688],[145,183,669,670,671,673,674,681,684,685,687],[674,676,679,680],[164,183],[670],[672],[153,172,183],[669,670,672],[594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625],[594],[594,604],[592,640,700],[148,183,640,700],[631,638],[495,499,638,640,700],[592,593,627,634,636,637],[632,638,639],[495,499,635,640,700],[183,640,700],[632,634,640,700],[634,638,640,700],[634],[629,630,633],[626,627,628,634,640,700],[85,634,640,700,701,702],[85,634,640,700],[449],[451,452,453,454],[193,195,199,210,400,429,442],[195,205,206,207,209,442],[195,242,244,246,247,250,442,444],[195,199,201,202,203,233,328,400,419,420,428,442,444],[442],[206,298,408,417,437],[195],[189,298,437],[252],[251,442],[148,398,408,497],[148,366,378,417,436],[148,309],[422],[421,422,423],[421],[91,148,189,195,199,202,204,206,210,211,224,225,252,328,339,418,429,442,446],[193,195,208,242,243,248,249,442,497],[208,497],[193,225,353,442,497],[497],[195,208,209,497],[245,497],[211,419,427],[159,261,437],[261,437],[85,370],[296,306,307,437,474,481],[295,414,475,476,477,478,480],[413],[413,414],[233,298,299,303],[298],[298,302,304],[298,299,300,301],[479],[85,196,468],[85,175],[85,208,288],[85,208,429],[286,290],[85,287,448],[85,89,148,183,184,185,446,490,491],[148],[148,199,232,284,329,350,352,424,425,429,442,443],[224,426],[446],[194],[85,355,368,377,387,389,436],[159,355,368,386,387,388,436,496],[380,381,382,383,384,385],[382],[386],[259,260,261,263],[85,253,254,255,256,262],[259,262],[257],[258],[85,261,287,448],[85,261,447,448],[85,261,448],[329,431],[431],[148,443,448],[374],[132,373],[234,298,315,352,361,364,366,367,407,436,439,443],[280,298,395],[366,436],[85,366,371,372,374,375,376,377,378,379,390,391,392,393,394,396,397,436,437,497],[360],[148,159,196,232,235,256,281,282,329,339,350,351,407,430,442,443,444,446,497],[436],[132,206,282,339,363,430,432,433,434,435,443],[366],[132,232,269,315,356,357,358,359,360,361,362,364,365,436,437],[148,269,270,356,443,444],[206,329,339,352,430,436,443],[148,442,444],[148,164,439,443,444],[148,159,175,189,199,208,234,235,237,266,271,276,280,281,282,284,313,315,317,320,322,325,326,327,328,350,352,429,430,437,439,442,443,444],[148,164],[195,196,197,204,439,440,441,446,448,497],[193,442],[265],[148,164,175,227,250,252,253,254,255,256,263,264,497],[159,175,189,227,242,275,276,277,313,314,315,320,328,329,335,338,340,350,352,430,437,439,442],[204,211,224,328,339,430,442],[148,175,196,199,315,333,439,442],[354],[148,265,336,337,347],[439,442],[361,363],[282,315,429,448],[148,159,238,242,314,320,335,338,342,439],[148,211,224,242,343],[195,237,345,429,442],[148,175,256,442],[148,208,236,237,238,247,265,344,346,429,442],[91,148,282,349,446,448],[312,350],[148,159,175,199,210,211,224,234,235,271,275,276,277,281,313,314,315,317,329,330,332,334,350,352,429,430,437,438,439,448],[148,164,211,335,341,347,439],[214,215,216,217,218,219,220,221,222,223],[266,321],[323],[321],[323,324],[148,199,202,232,233,443],[148,159,194,196,234,280,281,282,283,311,350,439,444,446,448],[148,159,175,198,233,283,315,361,430,438,443],[356],[357],[298,328,407],[358],[226,230],[148,199,226,234],[229,230],[231],[226,227],[226,278],[226],[266,319,438],[318],[227,437,438],[316,438],[227,437],[407],[199,228,234,282,298,315,349,352,355,361,368,369,399,400,403,406,429,439,443],[291,294,296,297,306,307],[85,186,188,261,401,402],[85,186,188,261,401,402,405],[416],[206,270,282,349,352,366,374,378,409,410,411,412,414,415,418,429,436,442],[306],[148,311],[311],[148,234,279,284,308,310,349,439,446,448],[291,292,293,294,296,297,306,307,447],[91,148,159,175,226,227,235,281,282,315,347,348,350,429,430,439,442,443,446],[270,272,275,430],[148,266,442],[269,366],[268],[270,271],[267,269,442],[148,198,270,272,273,274,442,443],[85,298,305,437],[191,192],[85,196],[85,295,437],[85,91,281,282,446,448],[196,468,469],[85,290],[85,159,175,194,249,285,287,289,448],[208,437,443],[331,437],[85,146,148,159,193,194,244,290,446,447],[85,184,185,446,492],[85,86,87,88,89],[138],[239,240,241],[239],[85,89,148,150,159,183,184,185,186,188,189,194,235,342,386,444,445,448,492],[456],[458],[460],[462],[464,465,466],[470],[90,450,455,457,459,461,463,467,471,473,483,484,486,495,496,497,498],[472],[482],[287],[485],[132,270,272,273,275,487,488,489,492,493,494],[183],[97,98,99,100,101,102,103,104,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,129],[138,148,149,150,175,176,183,626],[584],[585],[85,992,993,994,995],[992,997],[996],[103,107,175],[103,164,175],[98],[100,103,172,175],[153,172],[98,183],[100,103,153,175],[95,96,99,102,133,145,164,175],[95,101],[122,123],[99,103,133,167,175,183],[133,183],[122,133,183],[97,98,183],[103],[103,110,111],[101,103,111,112],[102],[95,98,103],[103,107,111,112],[107],[101,103,106,175],[95,100,103,110],[133,164],[95,100,103,110,117],[98,103,122,133,180,183],[261,552,556],[261,554],[261,553],[261,555],[261,667],[261,558],[85,261,558,1005,1006,1007],[261,1005,1006,1008],[261,504,505,567],[261,505,557,558,566],[85,261,559,709,714,718,719,977,1001,1002],[261,1003],[261,558,657],[85,261,660],[261,659,661,662,663,664,665],[261,558,662,663,664],[261,560],[261,559,560,562],[261,559,560],[261,559,560,561,562,563,564,565],[261,563],[138,146,155,261],[85,261,559,562,563,714,981],[85,261,559,709,710,714,718,719,977],[85,261,714,719],[261,719],[261,714],[261,564,719],[85,261,710,714,719,981],[261,709,714,719],[261,714,719],[85,261,563,564,714,719,981,987],[261,559,561,563,997],[261,978,979,982,983,984,985,986,988,989,990,991,998,999],[85,261,709,711,713],[85,261,709],[85,261,709,980],[85,261,709,717],[261,706,707],[261,708]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"a305ee2f90e34e9e70aba9a9e9a154ce20c4d5cd1499cd21b8dc3617e1e5c810","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"e142fda89ed689ea53d6f2c93693898464c7d29a0ae71c6dc8cdfe5a1d76c775","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"80da4eb8151b94ac3b7997e513a54c3cf105b0d7d0456a172d43809b30cfefc6","impliedFormat":1},{"version":"3e4825171442666d31c845aeb47fcd34b62e14041bb353ae2b874285d78482aa","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"e9775e97ac4877aebf963a0289c81abe76d1ec9a2a7778dbe637e5151f25c5f3","impliedFormat":1},{"version":"ed4af8c2d6cd8869aca311076fe78dd841c4ab316a24170fc61171de5eb9b51f","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"3a84b7cb891141824bd00ef8a50b6a44596aded4075da937f180c90e362fe5f6","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"8b9bf58d580d9b36ab2f23178c88757ce7cc6830ccbdd09e8a76f4cb1bc0fcf7","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"7782678102bd835ef2c54330ee16c31388e51dfd9ca535b47f6fd8f3d6e07993","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","impliedFormat":1},{"version":"24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","impliedFormat":1},{"version":"1a42891defae8cec268a4f8903140dbf0d214c0cf9ed8fdc1eb6c25e5b3e9a5c","impliedFormat":1},{"version":"339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"d32275be3546f252e3ad33976caf8c5e842c09cb87d468cb40d5f4cf092d1acc","impliedFormat":1},{"version":"37e97c64b890352421ccb29cd8ede863774df8f03763416f6a572093f6058284","impliedFormat":1},{"version":"e7be367719c613d580d4b27fdf8fe64c9736f48217f4b322c0d63b2971460918","affectsGlobalScope":true,"impliedFormat":1},{"version":"db3ec8993b7596a4ef47f309c7b25ee2505b519c13050424d9c34701e5973315","impliedFormat":1},{"version":"e7f13a977b01cc54adb4408a9265cda9ddf11db878d70f4f3cac64bef00062e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"af49b066a76ce26673fe49d1885cc6b44153f1071ed2d952f2a90fccba1095c9","impliedFormat":1},{"version":"f22fd1dc2df53eaf5ce0ff9e0a3326fc66f880d6a652210d50563ae72625455f","impliedFormat":1},{"version":"3ddbdb519e87a7827c4f0c4007013f3628ca0ebb9e2b018cf31e5b2f61c593f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"6d498d4fd8036ea02a4edcae10375854a0eb1df0496cf0b9d692577d3c0fd603","affectsGlobalScope":true,"impliedFormat":1},{"version":"24642567d3729bcc545bacb65ee7c0db423400c7f1ef757cab25d05650064f98","impliedFormat":1},{"version":"fd09b892597ab93e7f79745ce725a3aaf6dd005e8db20f0c63a5d10984cba328","impliedFormat":1},{"version":"6b053e5c7523625a3a3363e0a7979de0f8c455ded2a1c63bf76d7b40530c36d9","impliedFormat":1},{"version":"5433f7f77cd1fd53f45bd82445a4e437b2f6a72a32070e907530a4fea56c30c8","impliedFormat":1},{"version":"9be74296ee565af0c12d7071541fdd23260f53c3da7731fb6361f61150a791f6","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"f501a53b94ba382d9ba396a5c486969a3abc68309828fa67f916035f5d37fe2b","affectsGlobalScope":true,"impliedFormat":1},{"version":"2908b517c61155bcbeb3f14dcb8f26fa52fb7bbdcc34837125ecce7d75934df3","impliedFormat":1},{"version":"81e3cba7568a2c9b0603e684e28eaf81c5ff0edc9bc0bfb7ec74b6c80809b625","impliedFormat":1},{"version":"bcfcff784a59db3f323c25cea5ae99a903ca9292c060f2c7e470ea73aaf71b44","impliedFormat":1},{"version":"672ad3045f329e94002256f8ed460cfd06173a50c92cde41edaadfacffd16808","impliedFormat":1},{"version":"64da4965d1e0559e134d9c1621ae400279a216f87ed00c4cce4f2c7c78021712","impliedFormat":1},{"version":"ddbf3aac94f85dbb8e4d0360782e60020da75a0becfc0d3c69e437c645feb30f","impliedFormat":1},{"version":"0166fce1204d520fdfd6b5febb3cda3deee438bcbf8ce9ffeb2b1bcde7155346","affectsGlobalScope":true,"impliedFormat":1},{"version":"d8b13eab85b532285031b06a971fa051bf0175d8fff68065a24a6da9c1c986cf","impliedFormat":1},{"version":"50c382ba1827988c59aa9cc9d046e386d55d70f762e9e352e95ee8cb7337cdb8","impliedFormat":1},{"version":"2178ab4b68402d1de2dda199d3e4a55f7200e3334f5a9727fbd9d16975cdf75f","impliedFormat":1},{"version":"e686bec498fbde620cc6069cc60c968981edd7591db7ca7e4614e77417eb41f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e523e73ee7dd119d99072fd855404efc33938c168063771528bd1deb6df56d2","affectsGlobalScope":true,"impliedFormat":1},{"version":"a215554477f7629e3dcbc8cde104bec036b78673650272f5ffdc5a2cee399a0a","impliedFormat":1},{"version":"c3497fc242aabfedcd430b5932412f94f157b5906568e737f6a18cc77b36a954","impliedFormat":1},{"version":"cdc1de3b672f9ef03ff15c443aa1b631edca35b6ae6970a7da6400647ff74d95","impliedFormat":1},{"version":"139ad1dc93a503da85b7a0d5f615bddbae61ad796bc68fedd049150db67a1e26","impliedFormat":1},{"version":"bf01fdd3b93cf633b3f7420718457af19c57ab8cbfea49268df60bae2e84d627","impliedFormat":1},{"version":"15c5e91b5f08be34a78e3d976179bf5b7a9cc28dc0ef1ffebffeb3c7812a2dca","impliedFormat":1},{"version":"65b39cc6b610a4a4aecc321f6efb436f10c0509d686124795b4c36a5e915b89e","impliedFormat":1},{"version":"269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","impliedFormat":1},{"version":"93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","impliedFormat":1},{"version":"3c1f19c7abcda6b3a4cf9438a15c7307a080bd3b51dfd56b198d9f86baf19447","impliedFormat":1},{"version":"d3edb86744e2c19f2c1503849ac7594a5e06024f2451bacae032390f2e20314a","impliedFormat":1},{"version":"a289e90dfa7a494f8b6276573d8641fa1aa2b2e92c6874ac842782d63ee3b852","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a3e61347b8f80aa5af532094498bceb0c0b257b25a6aa8ab4880fd6ed57c95a","affectsGlobalScope":true,"impliedFormat":1},{"version":"98e00f3613402504bc2a2c9a621800ab48e0a463d1eed062208a4ae98ad8f84c","impliedFormat":1},{"version":"4301becc26a79eb5f4552f7bee356c2534466d3b5cd68b71523e1929d543de89","impliedFormat":1},{"version":"5475df7cfc493a08483c9d7aa61cc04791aecba9d0a2efc213f23c4006d4d3cd","impliedFormat":1},{"version":"000720870b275764c65e9f28ac97cc9e4d9e4a36942d4750ca8603e416e9c57c","impliedFormat":1},{"version":"d9d9c04fd280b0c364a18ff058a68eee451a3b860f9f8b6cb44cb027a59d24e5","affectsGlobalScope":true,"impliedFormat":1},{"version":"1d274b8bb8ca011148f87e128392bfcd17a12713b6a4e843f0fa9f3f6b45e2b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"4c48e931a72f6971b5add7fdb1136be1d617f124594e94595f7114af749395e0","impliedFormat":1},{"version":"478eb5c32250678a906d91e0529c70243fc4d75477a08f3da408e2615396f558","impliedFormat":1},{"version":"e686a88c9ee004c8ba12ffc9d674ca3192a4c50ed0ca6bd5b2825c289e2b2bfe","impliedFormat":1},{"version":"98d547613610452ac9323fb9ec4eafc89acab77644d6e23105b3c94913f712b3","affectsGlobalScope":true,"impliedFormat":1},{"version":"3c1fa648ff7a62e4054bc057f7d392cb96dd019130c71d13894337add491d9f3","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a42be67ed1ddaec743582f41fc219db96a1b69719fccac6d1464321178d610fc","impliedFormat":1},{"version":"865a2612f5ec073dd48d454307ccabb04c48f8b96fda9940c5ebfe6b4b451f51","impliedFormat":1},{"version":"89e7fd23f6e6ced38596054161f5fb88737018909c6529c946cb349b74b95275","impliedFormat":1},{"version":"115b2ad73fa7d175cd71a5873d984c21593b2a022f1a2036cc39d9f53629e5dc","impliedFormat":1},{"version":"1be330b3a0b00590633f04c3b35db7fa618c9ee079258e2b24c137eb4ffcd728","impliedFormat":1},{"version":"bb7a61dd55dc4b9422d13da3a6bb9cc5e89be888ef23bbcf6558aa9726b89a1c","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"5c9b31919ea1cb350a7ae5e71c9ced8f11723e4fa258a8cc8d16ae46edd623c7","impliedFormat":1},{"version":"4aa42ce8383b45823b3a1d3811c0fdd5f939f90254bc4874124393febbaf89f6","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"3677988e03b749874eb9c1aa8dc88cd77b6005e5c4c39d821cda7b80d5388619","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"f4625edcb57b37b84506e8b276eb59ca30d31f88c6656d29d4e90e3bc58e69df","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"e2a37ac938c4bede5bb284b9d2d042da299528f1e61f6f57538f1bd37d760869","impliedFormat":1},{"version":"76def37aff8e3a051cf406e10340ffba0f28b6991c5d987474cc11137796e1eb","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"594fe24fc54645ab6ccb9dba15d3a35963a73a395b2ef0375ea34bf181ccfd63","impliedFormat":1},{"version":"7cb0ee103671d1e201cd53dda12bc1cd0a35f1c63d6102720c6eeb322cb8e17e","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"ad37fb4be61c1035b68f532b7220f4e8236cf245381ce3b90ac15449ecfe7305","impliedFormat":1},{"version":"93436bd74c66baba229bfefe1314d122c01f0d4c1d9e35081a0c4f0470ac1a6c","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"304b44b1e97dd4c94697c3313df89a578dca4930a104454c99863f1784a54357","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"97e5ccc7bb88419005cbdf812243a5b3186cdef81b608540acabe1be163fc3e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"6b3453eebd474cc8acf6d759f1668e6ce7425a565e2996a20b644c72916ecf75","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"89cd3444e389e42c56fd0d072afef31387e7f4107651afd2c03950f22dc36f77","impliedFormat":1},{"version":"7f2aa4d4989a82530aaac3f72b3dceca90e9c25bee0b1a327e8a08a1262435ad","impliedFormat":1},{"version":"e39a304f882598138a8022106cb8de332abbbb87f3fee71c5ca6b525c11c51fc","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"fcdf3e40e4a01b9a4b70931b8b51476b210c511924fcfe3f0dae19c4d52f1a54","impliedFormat":1},{"version":"345c4327b637d34a15aba4b7091eb068d6ab40a3dedaab9f00986253c9704e53","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"2b5b70d7782fe028487a80a1c214e67bd610532b9f978b78fa60f5b4a359f77e","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"162e071992b34bc36ca257d629547f93cb43728d6fe073ad18a237e4f7c52d7d","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"7e6ac205dcb9714f708354fd863bffa45cee90740706cc64b3b39b23ebb84744","impliedFormat":1},{"version":"61dc6e3ac78d64aa864eedd0a208b97b5887cc99c5ba65c03287bf57d83b1eb9","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"f730b468deecf26188ad62ee8950dc29aa2aea9543bb08ed714c3db019359fd9","impliedFormat":1},{"version":"933aee906d42ea2c53b6892192a8127745f2ec81a90695df4024308ba35a8ff4","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"985153f0deb9b4391110331a2f0c114019dbea90cba5ca68a4107700796e0d75","impliedFormat":1},{"version":"a3e3f0efcae272ab8ee3298e4e819f7d9dd9ff411101f45444877e77cfeca9a4","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"71d9eb4c4e99456b78ae182fb20a5dfc20eb1667f091dbb9335b3c017dd1c783","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"30e6520444df1a004f46fdc8096f3fe06f7bbd93d09c53ada9dcdde59919ccca","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"a58beefce74db00dbb60eb5a4bb0c6726fb94c7797c721f629142c0ae9c94306","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"502fa5863df08b806dbf33c54bee8c19f7e2ad466785c0fc35465d7c5ff80995","impliedFormat":1},{"version":"c91a2d08601a1547ffef326201be26db94356f38693bb18db622ae5e9b3d7c92","impliedFormat":1},{"version":"888cda0fa66d7f74e985a3f7b1af1f64b8ff03eb3d5e80d051c3cbdeb7f32ab7","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"9586918b63f24124a5ca1d0cc2979821a8a57f514781f09fc5aa9cae6d7c0138","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"55095860901097726220b6923e35a812afdd49242a1246d7b0942ee7eb34c6e4","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"1a6e6ba8a07b74e3ad237717c0299d453f9ceb795dbc2f697d1f2dd07cb782d2","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"190da5eac6478d61ab9731ab2146fbc0164af2117a363013249b7e7992f1cccb","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"88e9caa9c5d2ba629240b5913842e7c57c5c0315383b8dc9d436ef2b60f1c391","impliedFormat":1},{"version":"ddf68b3b62e49cf6fd93ba2351ad0fbbcf62ca2d5d7afc9f186114e4b481c3cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"a46dba563f70f32f9e45ae015f3de979225f668075d7a427f874e0f6db584991","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"622694a8522b46f6310c2a9b5d2530dde1e2854cb5829354e6d1ff8f371cf469","impliedFormat":1},{"version":"d24ff95760ea2dfcc7c57d0e269356984e7046b7e0b745c80fea71559f15bdd8","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"13c1b657932e827a7ed510395d94fc8b743b9d053ab95b7cd829b2bc46fb06db","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"078131f3a722a8ad3fc0b724cd3497176513cdcb41c80f96a3acbda2a143b58e","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"9e155d2255348d950b1f65643fb26c0f14f5109daf8bd9ee24a866ad0a743648","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"7a883e9c84e720810f86ef4388f54938a65caa0f4d181a64e9255e847a7c9f51","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d408d6f32de8d1aba2ff4a20f1aa6a6edd7d92c997f63b90f8ad3f9017cf5e46","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"9d622ea608d43eb463c0c4538fd5baa794bc18ea0bb8e96cd2ab6fd483d55fe2","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"58c753bde1f54451fe15e17186509faaf6b4733261e82686cd39c8f8d34f48e3","affectsGlobalScope":true},"7b550dda9686c16f36a17bf9051d5dbf31e98555b30d114ac49fc49a1e712651",{"version":"bc7712a8d1038cf8dd56f652d19ff183eeaa5465ffc9e56de8d56af1e1d20708","signature":"fed3dc9e2de5f6cc2acbf65a5a208c7051ea63f6f4e41a18311b5b6f520d17c7"},{"version":"287cc0e8ee175a599588a66fa9589691f7111fb14c79df8a29c86bf836b5b544","signature":"aabebf555b5e8b45280907230815b2bcdd04fa35b033581cd20747cee75edaa9"},{"version":"2039bc146cc1f4b6320cae079b3c6b6de2166b9cdb859d83277b1bb0ea9ed1ce","signature":"571f3c4193b7109dd25377621615d311a5b881d6c1e74ae88985c789d0e324b4"},{"version":"86d4ff8ba66b5ea1df375fe6092d2b167682ccd5dd0d9b003a7d30d95a0cda32","impliedFormat":99},{"version":"37e97c64b890352421ccb29cd8ede863774df8f03763416f6a572093f6058284","impliedFormat":1},{"version":"2948774a5104c8ee235318dfdd3c8e2402c053b8fabc59e0cad1de8302d91cbd","impliedFormat":99},{"version":"014ba72e2add59d6d2d2e82166647982c824639e2902ccd7b3103cf720a0cb65","impliedFormat":99},{"version":"e22273698b7aad4352f0eb3c981d510b5cf6b17fde2eeaa5c018bb065d15558f","impliedFormat":99},{"version":"b78c801c3c21015ee487f6494448bcff55bb6b61f41172dfc2c26f2218d99138","impliedFormat":99},{"version":"de97e016d8dd4869febd5bccce02eb96957089d04b74ea5d1dc0e66112493b64","impliedFormat":99},{"version":"671ccab2e6a253d2516c0e4699b3077fc30cdb70b4436d8c79d76c91266a1a94","impliedFormat":99},{"version":"9b40cdceea5bb43a6e998cc6f8d47480741de5f336d9147653a5d9004175f6c1","impliedFormat":99},{"version":"e760f7860d08e9d42b6ecd7dd341602fbc0c13d60eb30beaf1153f1c7c44d66d","impliedFormat":99},{"version":"fb04e1ca667399e7302c033656cc285e6c1cff9c29f264cf229dd25e3962a762","impliedFormat":99},{"version":"8e9587d80cf4523b1655a74c5ff445313514b5de82af24bd9c2b2de764b8aa08","impliedFormat":99},{"version":"410e798cfb0d71e54d49284d16c7672db89720d017440abae05d547e9351e1cd","impliedFormat":99},{"version":"ddaf5d3ddc45282b19fb0fecec91c87fc9b4d1f45c2ee611677345c81383c5c5","impliedFormat":99},{"version":"5668033966c8247576fc316629df131d6175d24ccf22940324c19c159671e1c1","impliedFormat":99},{"version":"8db9325466c3c367e83b41ce5045757ad87a5468001b8bd3021bc406ac526bbe","impliedFormat":99},{"version":"d76df1670eeb97afbab6c87b8cd31bbd09dbf9026ff0ca533b5d7d3fc0291f79","impliedFormat":99},{"version":"13902404b0a9593a2c2f9c78ac7464820129fe7e5a660ef53a5cc8f3701f8350","impliedFormat":99},{"version":"2484f21803a2f6d8e34230c1c4354288da5d842182d7102a49a004c819c4b8b3","impliedFormat":99},{"version":"b6083b1fcead271c8902f9e5c6bdbc645d83ef3d0d8c029c92e19e094a8e1327","impliedFormat":99},{"version":"50cf14b8f0fc2722c11794ca2a06565b1f29e266491da75c745894960ebbce06","impliedFormat":99},{"version":"d14c27fbdc983de6ac10fa52844be9a4284ed70648e09b03f1dfb3e524ffe80c","impliedFormat":99},{"version":"cd8a4297d0ab56dc571dadd2845e558c9d979fe1e120a0dec537935bc8a36dd2","impliedFormat":99},{"version":"079a12cb0e0c42655d77da5185e882b4cc94bd5c6c2131171a9289fc1f4287fc","impliedFormat":99},{"version":"a018d566af32db595b5491095cf3e9d0f3773e96e8c36b3010c5773408dab9cf","impliedFormat":99},{"version":"795c2d3c3957e8d508694a547d3054188f695ab5e2e92edf12bc5fcf7a131543","impliedFormat":99},{"version":"167edfac7664bec77aa2efb2ce9d515c41b5cc4269091a946b3fa6ec4e7e8738","impliedFormat":99},{"version":"e1d65ef0ac1d0f780a061cccf6aedc70622395b0edfd8df1a3bdb92c93a98bea","impliedFormat":99},{"version":"9a7f96f9b74c582422c3ed03b58339d00a3e6b170b14ec31af615a2d30449d34","impliedFormat":99},{"version":"12d1545629648a2281099d450e26c1093ab92149b2f11a5eb820e956be31173a","impliedFormat":99},{"version":"ce8efe03de887ccd0b28ef5b6cb314af7653b7a3360dd8eb4fa47b2b743aa0a4","impliedFormat":99},{"version":"4d4551dcb3fd19a4f22aaa63c6c391d42ce44a15602a6f6a19d582709edb24d9","impliedFormat":99},{"version":"a76075b5aba8187b1fc5c8f565745daed6e4341e64b44e6ec41412a16d575d62","impliedFormat":99},{"version":"f836bf3653e31c3bba120071196c95d416b83c5d860ce27549975f8785cd670a","impliedFormat":99},{"version":"3d9c8154e27774153a2806926da926337ae232ab848153487903323bb4c83dc7","impliedFormat":99},{"version":"f687f35c2206a319dc7d8f0b751e182638c912838ff54034fb782beae50f7cac","impliedFormat":99},{"version":"0ce0cd2e64075ea59432df7a5c23a05c4888e4254de449f6bd43d8af04fc33b8","impliedFormat":99},{"version":"7a81f15892b1c8d0cbfb35605038ce5c6d0cf93542946aa0b8c415dbefdea1cd","impliedFormat":99},{"version":"d6fc46b15a18da0aaf99dba1fc1109b1b4ade3f978c55772d99f6b8cc47f4753","impliedFormat":99},{"version":"f96fb5e3197e37ed63f7787885a869aba941c94a234a62f74fa10f8a389c3c35","impliedFormat":99},{"version":"063141047bd26a30b156a2e2ebb6924a3427ba6195f7a11ba9472490eac82022","impliedFormat":99},{"version":"c48fbe1599fcef71d380c71e75a9a4895839f0baf3666d46dbc20be1edaab5d6","impliedFormat":99},{"version":"c0144b49b5c752301d037d9334986903fbb9f14de8263b93cd702ff2218f083e","impliedFormat":99},{"version":"647e1d0a723a7caa54487d50dbfd952f184a110899ce3f331f3c451f6fbd083f","impliedFormat":99},{"version":"0ef423f75b832126ecc0966a396b68c4a2afdecf8783f4e9e10a439ea0e81b8a","impliedFormat":99},{"version":"137049cab609b1bb2de696f1652d400bfd2942d58fe6cb43712e1b29d05139fc","impliedFormat":99},{"version":"562640a0449842e1fc2663d2d731740114629a156366a46d26c561811d879600","impliedFormat":99},{"version":"ce7e1ca44943397e6329e47c78922620a159d94798faee193377286123fdd37f","signature":"a5cf9cd0b0950a26801bfb911f725817cef8ee2d464845ce894979bb4364589b"},{"version":"f0dfc92d6ec36a01767780bc772fabe59c53601df40870ff0711b6109e4cf181","signature":"0133a679821f4e96d1fc5021fd31050576419896440c1165eace0a4eb9da5186"},{"version":"322ae5c4d073ffc8fff091f71005ed01dd49396d8bbbad213b4fa72183884c48","signature":"32d97e928866ebee1b80975a347b879f2c10789c80fe39e8a41dd8d9293113d7"},{"version":"25d57b94b0300bc2133b3dbcaefe1891598af5a75c6564a5d8d0609e14c05f04","signature":"6aa7265ae38634679e93e75237044c298a65ae7b9d70f597f441aaf95d461348"},{"version":"cc7e4e239251fc4f5edea819297e40f924e6be5d1c7e8f0f0a23a44bd866459f","signature":"748474563bb55ea2c8f4c8e79e81de1128a197c789293d34a0b80264b7458f4e"},{"version":"61ee7d6c65c1a690dd97d73d6ef8ee50532461dea81498c1b302c103ea996f7d","signature":"6689c0aebdb83d02bbad0a08e0aea4abb8fcde09b7b55830c80938776c4aa3d3"},{"version":"05f09f25cb7e6ceba355199c538ea15877db2adecf106399db562266a6cb9649","signature":"5571c49b19960c098606db2b1090888da23c445193313a127fea8e1916f70845","affectsGlobalScope":true},{"version":"5a0ae53a50ca6edd8b6ca62fc24e229c749743bb4ca065e7fdc0c6f27dde9971","signature":"5e766bc5793fb768365707850105153ce53e7714805c7e074509eae1a3fdaa5b"},{"version":"970628968c1a35f6442953c850285c9a8805753fd6a3317caee426c46a493fcc","signature":"b2441dcb1c8abff8802fc6c82dfc66cc7a6e84944efc0a65516f920b5aff1a0b"},{"version":"807f98f9160a13e3d695fa67bbe763b8843a42cdf7b085b39cd64c5432415532","signature":"4cf2561c4b5c7c1ca015e8fbf5829c2cb1ce4deb45ba6963040475d0737ab672"},{"version":"16c8dbe30a172430bf8a91ebb47387c6efd4bbcc49e6a6d2765312b30da114f6","signature":"53bf5df332806da38f29edb3c345a6ce833a966529b52f554484734e3ae260da"},{"version":"c5af6fc7a2c27849ea30ed66baae77d91db7d3c021b6337697411a0eef394f59","signature":"a5e15013c9ee241b7c202076cb33abe8812bfc4830265163f1e215ec304cc0f0"},{"version":"9c37fe1aecc398a1ec850fe328cc3941f07bbd844bce5726a01937a3c5e04c84","signature":"282898bab136d38eb9ce058c333ecec9abbdb85e8236b01a7b3d3cc228ba6667"},{"version":"5320c02ce8d865ae01ee011abe79f3a5427100a91295bf59332f290d391e018c","signature":"8987e841af0f363073baa7d586570ba3cb4c4077d0e0df78102ceb52feca1e1c"},{"version":"4f1afedce16f5aefe78da762e2f454b03b6e971104877d627623ad9853893b90","signature":"9585be7e3272ce1640ed24b82e36d6567c2197693f71c2464329f53f1af1344b"},{"version":"477291f93fb53a4414a8d2243f63c4976fb8b7c76872d1c7beaa17e3ae30573d","signature":"2cb202257e26db2b5c29597f716231700940c6790c9cabf0ca9a8ebebf556957"},{"version":"ce9871b651c2f6bdffe8aebc0bd88820231a0ecdf9c034c3515b21ec77944ac8","signature":"e433d566dd44157efaa2240f71b2f19d3554daf57f691614c9724e56a455ec6a"},{"version":"fa2c48fd724dd8f0e11dfb04f20d727a2595890bfa95419c83b21ed575ed77d1","impliedFormat":99},{"version":"6d23ffe7f1b73f16b08f5baeca430e6655b46fdc5862fd7bff1483b71fc6b28d","impliedFormat":99},{"version":"20be44c04e883d5fe7840d630a8d0656e95b00c2d6eebab9ab253275e7170534","impliedFormat":99},{"version":"3b674288fbdc0ff0ed2b7fc2839014c2ff209c84999fd06b6339347d0f976a85","impliedFormat":99},{"version":"cc2958d8abd86edcdf05542bb1b40ba659db5bc5a2560720cde08e8950e63bc1","impliedFormat":99},{"version":"e44e0ea195d68c0aea951809bda325322085008c0622fc4ee44db5359f37b747","impliedFormat":99},{"version":"21053659ad72fe51b9dfbde4fa14dbbac0912359fa37c9a5aa75f188782b2ee8","impliedFormat":99},{"version":"e297bdcb7db008d8d7d0481f2c935a9f7f0a338f41b7e5d1cec6a7744140a4ff","impliedFormat":99},{"version":"ef816ad6735a271c4c8035a1914c3a9beaaa90b3c174da312d26bce8736e56ec","impliedFormat":99},{"version":"7202026e24c5e5b7b6e5fe6b99455a91058ef82e74a5cdf6a3a4136b7ae9c080","impliedFormat":99},{"version":"87561cc8a2d7444adf4eed4b3f15bef8c6098cceb0e7617fba1cc45d187ac8c8","impliedFormat":99},{"version":"b52f7568bb9b00bcee6c4929938226541c09d86b849b8ba8db2fe2a8bba46f49","impliedFormat":99},{"version":"d42e1872d53ebb213e7bbe15e5fecdcaa9a490d2f2a2b035ee9cf4a6d3f1e44e","impliedFormat":99},{"version":"2262d96c02073dcb17a31ae8c738651ebff75f102522eae686f5462658b687a8","impliedFormat":99},{"version":"fd40c454d56e1d14e60ce13f3bc60c7fdb9bc70c6ef9c7bfafec1f0eb5d8075b","impliedFormat":1},{"version":"155ced96d70533d95c481061e2691802fae7cfb96869d7c85ac8622f53b51cb7","impliedFormat":1},{"version":"3689b6f599705380d2ceaccb4e58eec5c9439a7a5635d6e37c1ba66ed7c34b35","impliedFormat":99},{"version":"6cf0d3cc668cdbb01358ef7c2e41bbcc14d8d8e4ca424a1b6d2838d9a1cae8ce","impliedFormat":99},{"version":"b7bd70307671536c735389e0a1748555c438c392dfceb6f2ac3aa0a50ca82530","impliedFormat":99},{"version":"661c403f4c5bbf259e03f4fdc3a9e3f51ad562684f702e1b842e6c5336de0752","impliedFormat":99},{"version":"415dd92247ca21db682f75ba7e6289ab2d093cd34c6f471c6c789afd047ad4f3","impliedFormat":99},{"version":"4fc633107330ab389f07f86af80192ac697a68a586ad76dcf43304410e7cfb6a","impliedFormat":99},{"version":"828f8b38dff4e5c47b0112cb437da379c720f0360d40d392457c9775f30c8ae8","impliedFormat":99},{"version":"b7ca2f47522d4ea41e65ff92c4c6dd9c4c8260da7c456a7631a9c88dc056b4d0","impliedFormat":1},{"version":"4f01e4d0959f9125b89e5737eb1ca2bfa69fd6b7d6126eba22feb8b505b00cde","impliedFormat":1},{"version":"4363a1adb9c77f2ed1ca383a41fbab1afadd35d485c018b2f84e834edde6a2c7","impliedFormat":1},{"version":"1d6458533adb99938d041a93e73c51d6c00e65f84724e9585e3cc8940b25523f","impliedFormat":1},{"version":"b0878fbd194bdc4d49fc9c42bfeeb25650842fe1412c88e283dc80854b019768","impliedFormat":1},{"version":"a892ea0b88d9d19281e99d61baba3155200acced679b8af290f86f695b589b16","impliedFormat":1},{"version":"03b42e83b3bcdf5973d28641d72b81979e3ce200318e4b46feb8347a1828cd5d","impliedFormat":1},{"version":"8a3d57426cd8fb0d59f6ca86f62e05dde8bfd769de3ba45a1a4b2265d84bac5a","impliedFormat":1},{"version":"afc6e1f323b476fdf274e61dab70f26550a1be2353e061ab34e6eed180d349b6","impliedFormat":1},{"version":"7c14483430d839976481fe42e26207f5092f797e1a4190823086f02cd09c113c","impliedFormat":1},{"version":"828a3bea78921789cbd015e968b5b09b671f19b1c14c4bbf3490b58fbf7d6841","impliedFormat":1},{"version":"69759c42e48938a714ee2f002fe5679a7ab56f0b5f29d571e4c31a5398d038fe","impliedFormat":1},{"version":"6e5e666fa6adeb60774b576084eeff65181a40443166f0a46ae9ba0829300fcb","impliedFormat":1},{"version":"1a4d43bdc0f2e240395fd204e597349411c1141dd08f5114c37d6268c3c9d577","impliedFormat":1},{"version":"874e58f8d945c7ac25599128a40ec9615aa67546e91ca12cbf12f97f6baf54ff","impliedFormat":1},{"version":"da2627da8d01662eb137ccd84af7ffa8c94cf2b2547d4970f17802324e54defc","impliedFormat":1},{"version":"07af06b740c01ed0473ebdd3f2911c8e4f5ebf4094291d31db7c1ab24ff559aa","impliedFormat":1},{"version":"ba1450574b1962fcf595fc53362b4d684c76603da5f45b44bc4c7eeed5de045b","impliedFormat":1},{"version":"b7903668ee9558d758c64c15d66a89ed328fee5ac629b2077415f0b6ca2f41bc","impliedFormat":1},{"version":"c7628425ee3076c4530b4074f7d48f012577a59f5ddade39cea236d6405c36ba","impliedFormat":1},{"version":"28c8aff998cc623ab0864a26e2eb1a31da8eb04e59f31fa80f02ec78eb225bcd","impliedFormat":1},{"version":"78d542989bdf7b6ba5410d5a884c0ab5ec54aa9ce46916d34267f885fcf65270","impliedFormat":1},{"version":"4d95060af2775a3a86db5ab47ca7a0ed146d1f6f13e71d96f7ac3b321718a832","impliedFormat":1},{"version":"6708cd298541a89c2abf66cceffc6c661f8ee31c013f98ddb58d2ec4407d0876","impliedFormat":1},{"version":"2e90928c29c445563409d89a834662c2ba6a660204fb3d4dc181914e77f8e29d","impliedFormat":1},{"version":"84be1b8b8011c2aab613901b83309d017d57f6e1c2450dfda11f7b107953286a","impliedFormat":1},{"version":"d7af890ef486b4734d206a66b215ebc09f6743b7fb2f3c79f2fb8716d1912d27","impliedFormat":1},{"version":"7e82c1d070c866eaf448ac7f820403d4e1b86112de582901178906317efc35ad","impliedFormat":1},{"version":"c5c4f547338457f4e8e2bec09f661af14ee6e157c7dc711ccca321ab476dbc6d","impliedFormat":1},{"version":"223e233cb645b44fa058320425293e68c5c00744920fc31f55f7df37b32f11ad","impliedFormat":1},{"version":"1394fe4da1ab8ab3ea2f2b0fcbfd7ccbb8f65f5581f98d10b037c91194141b03","impliedFormat":1},{"version":"086d9e59a579981bdf4f3bfa6e8e893570e5005f7219292bf7d90c153066cdfc","impliedFormat":1},{"version":"1ea59d0d71022de8ea1c98a3f88d452ad5701c7f85e74ddaa0b3b9a34ed0e81c","impliedFormat":1},{"version":"cd66a32437a555f7eb63490509a038d1122467f77fe7a114986186d156363215","impliedFormat":1},{"version":"f53d243499acfacc46e882bbf0bf1ae93ecea350e6c22066a062520b94055e47","impliedFormat":1},{"version":"65522e30a02d2720811b11b658c976bff99b553436d99bafd80944acba5b33b4","impliedFormat":1},{"version":"76b3244ec0b2f5b09b4ebf0c7419260813820f128d2b592b07ea59622038e45c","impliedFormat":1},{"version":"66eb7e876b49beff61e33f746f87b6e586382b49f3de21d54d41313aadb27ee6","impliedFormat":1},{"version":"69e8dc4b276b4d431f5517cd6507f209669691c9fb2f97933e7dbd5619fd07b7","impliedFormat":1},{"version":"361a647c06cec2e7437fa5d7cdf07a0dcce3247d93fbf3b6de1dc75139ff5700","impliedFormat":1},{"version":"fe5726291be816d0c89213057cd0c411bb9e39e315ed7e1987adc873f0e26856","impliedFormat":1},{"version":"1b76990de23762eb038e8d80b3f9c810974a7ed2335caa97262c5b752760f11a","impliedFormat":1},{"version":"5e050e05fe99cd06f2d4ad70e73aa4a72961d0df99525e9cad4a78fa588f387b","impliedFormat":1},{"version":"4ff327e8b16da9d54347b548f85675e35a1dc1076f2c22b2858e276771010dd2","impliedFormat":1},{"version":"f767787945b5c51c0c488f50b3b3aeb2804dfd2ddafcb61125d8d8857c339f5a","impliedFormat":1},{"version":"14ab21a9aeff5710d1d1262459a6d49fb42bed835aa0f4cfc36b75aa36faddcd","impliedFormat":1},{"version":"ba3c4682491b477c63716864a035b2cfdd727e64ec3a61f2ca0c9af3c0116cfd","affectsGlobalScope":true,"impliedFormat":1},{"version":"b222d32836d745e1e021bb10f6a0f4a562dd42206203060a8539a6b9f16523f0","impliedFormat":1},{"version":"651df11341eff0b769fb83af75b1872e6cedf406674c5eaa2650551aceb5a816","impliedFormat":1},{"version":"52356d570cc4f2b3c1252b3580796e8ad95b8c425a9ad62e6c3d1eb41578278c","impliedFormat":99},{"version":"dd120fce87e162e49560f520150c8c603a84d238dc7a8b95b8bc9a033b56a2a6","signature":"51a7690ae234b805395e5d39f094fee1b19d8284f32cdc2cdf66315a99dc0f40"},{"version":"7344c764b40a19e7f667bc28b3903a681a98cf575b17df3f75bb19500d90f53e","signature":"e47b98733abf7032c7b1366acd316afe980ea46606ea826e5a1879ca9ed592e2"},{"version":"6d40c235f18beb47b0b800f953a2d702c0a175cb80bbf710e16fd93a0b84810c","signature":"178218bb5b4a840d502140054dc45848eb0c875524d4c54c3fa88cc1951859e4"},{"version":"53c4ed5316eef3af783453670ecd0cec36d3f7806082a4e110c6f67ee18adfa4","signature":"871fe90c9d8f35c04239cb13de4bb181fd1a84f5fa9e77e52c01e53b61876703"},{"version":"3fe415ca3efcdd19a5876d39693c7efcc13ad62d1b1f9353b8afcd15f2ec5a90","signature":"7fe560c025aa7e5b81b5d137edc33c66adec7acdc13bfbcb638f9c023e0bc6b4"},{"version":"5f1f0e188097681747b3d66ae6cd95b5c067855fccb5d96e81c26cfdf9ddaf9c","signature":"33e97a51d244d4e9456ea0e16079a8428897cda93b8dc8373f95af0953ca823d"},{"version":"59b9fa0812151f2f9fae130eb3b03501bad8c0490cc12867b619ab361b41df9e","signature":"341e2a872a74dd14b032a05f33863c027848a976d87100c1607834b76be177a5"},{"version":"d58ecacec0fb7715d943ceeb8cbd193f8ed57321b212187275c06af3e02f7f4f","signature":"9357fcfdff1bf1aa3cd4db5c9f27756ad15a2af3dbbe1bea127957109b0c482b"},{"version":"e89646af6d2baf672b498a30e6df6b3755a1ce9b174934dab012b8ea45fd2cb0","signature":"95d3ed16a8763b87364657999839ea23825015370c4c4a7ec3d4b4ce97adafd0"},{"version":"ec483d2ee6f2ca7d0126bf1193acc39029dbca9517f391586cbcf630ff2fb496","signature":"0961b1b67316368ed3b29eb9c29613590dd712b872d05b02ae91e551eb700eb6"},{"version":"5428df14e8393af08d0d1ad219b2cdec9735ff415abe7fa338f457d9d26cd6f0","signature":"55eefbd6b1b85e7ecae06c26af2c8295074fa92282d998fec7d805ce15b3f979"},{"version":"986a751418b7b3550432ec303c22fae429874f3b203991347e2b9f5e5ac39d0d","signature":"0496465619573adbc43b826e4924355af03bcca6b17d5114009f293fdabb3f1a"},{"version":"d3d4038ff9f22597d2200b6a483a0429189422d30b406a31a1505a2730dc9247","signature":"3425d941679b1d5ac5c98906a1ff172e8e9a4276cf1314600d5137f0db106f5a"},{"version":"bd85bb1d5278063001e7f98d46ccec3f1a95c77d305a5fa5b7019455a97f8279","signature":"193f3698143959625b77bab03ef64fae1876dda0ed7438f9da236b49a3b9b826"},{"version":"73ea2e5fed5c4a9985b7e467542f5450fa7a548d82029ca5d79ba10ac98dff57","signature":"fa7d5d52641f30569943c6500e32160831e8554b5ac0ac00b7be626ce765c5c1"},{"version":"033e9e28d2e96b0ed10241d4ab8c421d37be3adf7fcf71ebcbe8ae16d787bca0","signature":"6c369ab76d728d67cb299b2dee2a0557235550ad50e4380eade77293985a01cc"},{"version":"61c3cba4b82ab0cfe074c7fd8e2d22fae6b900c6cb8865241ca7977cb98f589b","signature":"805bab7cf726fe2ac98787f9b609e4ac2d3785936f4567320d27a15688f72cbe"},{"version":"26f31441234f3a5b8a65cf6f36f2ab2b17089a4b45ddfc130da19875e9d96bbd","signature":"6c620be1339c2decea311034a85b0110f74b87e2fba27e8084702a2ea3d249e8"},{"version":"919c57562e30908a1557afaa7939370d8e367a949f93de83a76d9ea2293326e8","signature":"4d0dc2fbdbc626a4418e3357bb48a5a2073a5ad1e5b434569a03eff28e08812b"},{"version":"fecd96d4339fc88fd945714a6f72b5a87f618c06a42134b69563171dd34895e0","signature":"1f9aa9c8b83b489bd1f8d5278c60890e5f13b819ec2fea292051496af8bbc9d1"},{"version":"27d9d82983337784f1e6823acf4832f10fd26d9ef226c1e613c7715978f83922","signature":"5cd1fb7a819213bd963625805bfefcdd95aa3a70662d43ead949180e70b7a691"},{"version":"0c78071a0c2b75d2cda4f7616c99552cb10b67735d0be359c382fd7e3466e8c5","signature":"873e8efa1e79227beb67512dd0a2090f8207d50047af7f3a8028028318aa4772"},{"version":"601618b6dd01624225c88ab71ec762bfe4528824b2fb4992703d86e7ea261da6","signature":"4cd6e66157f2b05e76700ee9c44cabcae5e086a3ea7e8a8da86d0e475c68fb93"},{"version":"69adaae49147cac5f3e24cc32acbbf857ee61bfa5b599a5b86f9234fd7fdffa5","signature":"8285226968000b6d288163fd47ccfa85d314aa4b371230154b750acb5ff3e989"},{"version":"c9551f07c9ba17d004434c0d241fbf411d8123957e58798566d5dcc723a41653","signature":"e23a2562158381d83d170da5fb79b7b3026ebd2bc94085953b6f8cf4d6b19053","affectsGlobalScope":true},{"version":"cf6b7fb0ea50561c84374b4e591683a6c20d80be76cdf5c086ee79f50234a78d","signature":"5361b81d021f6cdbf6f979aa3b22dcbe19224a85dec5cf9c15fa089ff0d2003e"},{"version":"332680a9475bd631519399f9796c59502aa499aa6f6771734eec82fa40c6d654","impliedFormat":1},{"version":"191bee6605de2b5210f29f22df04f5b5e6bdcc1f6e21fb07091d40eeeb75fd72","impliedFormat":1},{"version":"d83f3c0362467589b3a65d3a83088c068099c665a39061bf9b477f16708fa0f9","impliedFormat":1},{"version":"180e527dbc1f5ae2bbb79d0a3db1ada49258783d7e6299559e0f2ed663b4afec","impliedFormat":1},{"version":"29994a97447d10d003957bcc0c9355c272d8cf0f97143eb1ade331676e860945","impliedFormat":1},{"version":"f4260022f7af38e533d364ea62eb7ae01b0a32050033d7f6772073e1dc908025","impliedFormat":1},{"version":"9cddf06f2bc6753a8628670a737754b5c7e93e2cfe982a300a0b43cf98a7d032","impliedFormat":1},{"version":"3f8e68bd94e82fe4362553aa03030fcf94c381716ce3599d242535b0d9953e49","impliedFormat":1},{"version":"63e628515ec7017458620e1624c594c9bd76382f606890c8eebf2532bcab3b7c","impliedFormat":1},{"version":"355d5e2ba58012bc059e347a70aa8b72d18d82f0c3491e9660adaf852648f032","impliedFormat":1},{"version":"311cc121259b3e0c3c08304fc25b525aa02ba0f9bf55b3e7c60b0dbb7422014e","impliedFormat":1},{"version":"74c269b43d39e5ece20b2cca49c14e64c05b01e46407200d7558301d0fcaabf4","impliedFormat":1},{"version":"ec09bd95866efe38cd00ebb79dfa7a26563d600fa4a30db0f7c6d68f8f6d2b06","impliedFormat":1},{"version":"482d0ac70d56aa79941be30da6df28e926a007f835eed70cf7b5f3135368d1f6","impliedFormat":1},{"version":"7dd19397d5a090c9f8cd762bae67bd0ad6f782abe422594fb71168fb578673b0","impliedFormat":1},{"version":"84cbf6204ada0ee2f80493e55e45befa079954788718efd6dcc103183104e3c0","impliedFormat":1},{"version":"ed849d616865076f44a41c87f27698f7cdf230290c44bafc71d7c2bc6919b202","impliedFormat":1},{"version":"9a0a0af04065ddfecc29d2b090659fce57f46f64c7a04a9ba63835ef2b2d0efa","impliedFormat":1},{"version":"10297d22a9209a718b9883a384db19249b206a0897e95f2b9afeed3144601cb0","impliedFormat":1},{"version":"034b8b5912823744c986986f24432bf3fa7bfa671e69316b672f3f2db5166ce4","impliedFormat":1},{"version":"34d206f6ba993e601dade2791944bdf742ab0f7a8caccc661106c87438f4f904","impliedFormat":1},{"version":"05ca49cc7ba9111f6c816ecfadb9305fffeb579840961ee8286cc89749f06ebd","impliedFormat":1},{"version":"3d41a856a705624aa1eae155f1bb17611e507d09dca5ab6fdf33df3636bffd46","signature":"3a80a5a89402628ef48baa039e4f7a7102431450d13806fe8c6759f8c39a41aa"},{"version":"6357f46f7a8826098e91ff43f213699e45c748854fa3015543e75d8b8c017fa2","signature":"59a01f47a6b16b0b2cd033dad0c1e7ee29134d0fcdb20780c6cb75589de34620"},{"version":"f42673210a5cd115246938af8a039938c323e2578f532319cb5262b2ae07c1b2","signature":"c3b27e9d72d552b61ad76abf7a0158cf2e30dd317a3c4cda50a6c1e546e48a2c"},{"version":"f68cb60d2c0b8990fb5686100c4d8714099c68cb7cbbdbd7bf343710049b59fa","signature":"9d3f8a3b7a25cba2702e29fa9ab936ee36d89e864c57c8f0e82a52fffa214533"},{"version":"d6ec81f11229906a98b42a59aa01f4400ac6c6aafd95c8fcbf4f9b57264b5671","signature":"9d3f8a3b7a25cba2702e29fa9ab936ee36d89e864c57c8f0e82a52fffa214533"},{"version":"278abbdebc4f4312fcb825f9a0e917dc8405345e72b34325119ae41f3b0bf7b9","signature":"25df3d018fac4b4e95c4ba4e58e0b85efc1ed99ac61b70e2118d9d794d1d0184"},{"version":"729be6b12614415820653d26a2b60461a82b1f4028e32c14f96b8d4e85c13c54","signature":"ac566bc27970db0ea8666d3f7d0a9e01f35bd9c8b5ea4f8a66da7aee9eec31b1"},{"version":"ce8de3131bed6b9e597e2c01979b6b6049cf7d34931136443f9846c378c0ddb1","signature":"e7e63f959ae878cf311607f9f3837350b27be8822f983db0b09b64f1fa37c3f9"},{"version":"37c6f53e68f07a3fc95d7f9b42a816ce677d33c4f0ae3545ce39b415f1b32a5d","affectsGlobalScope":true},"89aef9779e040e8fb8ffcd924b5001a7525c50142cab92baeca8cfe67a706df7",{"version":"c3d577953f04c0188d8b9c63b2748b814efda6440336fa49557f0079f5cf748a","impliedFormat":1},{"version":"787fe950e18951b7970ec98cb05b3d0b11fcdfeb2091a7ea481ac9e52bf6c086","impliedFormat":1},{"version":"13ceda04874f09091da1994ba5f58bf1e9439af93336616257691863560b3f13","impliedFormat":1},{"version":"4c20dd218d27171323281e3ab9509eaa5aad1159c260238a139afe4e32ce7b72","signature":"11ec656c71cf64147c36964b7bc9c741a7c2b3e3838cb1926295acb992b73b14"},{"version":"e95eb95917814bb338b212b58b05addb2884fb4ecc449dfc33bfb18dc6ccda49","signature":"1fe151362f90fc7501926dd9e8ad981918b031b79ae242174845c46797e986ef"},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"49a8a704be8c2a8f5d645a404051db4a0a0fa4fa7b6ca71207cf9344bb413abc","impliedFormat":1},{"version":"e46429536f43f5910f5b2b0c50bb2769b510a4558bb4b5d20a3b0a9091dbf7c3","signature":"400b40fe5d5f4140993b0ac871686d2b7611ab791e8810b2e14f2d89701fc49e"},{"version":"aadf0f498b5ea8d78b28d2736229068ce805e27288548d614f13da9e02b3cf8c","signature":"618683504bb0c2d59481629a31cf3d5cab9d29fbe91f68c2f288dcc2d1dcf5db"},{"version":"25f92f980c5f0f8b0e3b1160e9ae434ce95b83ce04074b0d786ca109145c1e4e","signature":"3309423a2837bf899df1568eaa9c41430753bf2957451b4b0494c7e4f829ada1"},{"version":"a80b7bc4eda856374c26a56f6f25297f4c393309d4c4548002a5238cd57b2b66","impliedFormat":99},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"7b9fef47bc76c31bf42f9a4e6a38fbd8776b70b899d25c8b152b47b5c3e767cf","signature":"22b0ed29e99e02e157048711d20d33c46510e6f32d764ebc613cf282d43f6f07"},{"version":"a26d74bc8768e134734fa049d5a89fb674a560292f4bf1b39392416dc04cf49e","impliedFormat":99},{"version":"ea7f3d87bb25b8cf26c1b440de31b628c53b5e72e8f1ab1726356bf58acf5946","impliedFormat":99},{"version":"260f551168be7a50e7f1d4588574894683709dad712e60cd31282f5ee31c1fa2","impliedFormat":99},{"version":"9eb24c2e0ce91668b36892be1ab3d29c600cb5e51b1f94e5a7199b95fbfd358c","signature":"351f7cb5f3ce63374db1c4a065fa52fb1395e525c7a7a9dcaade8db57dae36a7"},{"version":"8512cce0256f2fcad4dc4d72a978ef64fefab78c16a1141b31f2f2eba48823d1","impliedFormat":1},{"version":"2cef84bf00cbdb452fdc5d8ecfe7b8c0aa3fa788bdc4ad8961e2e636530dbb60","impliedFormat":99},{"version":"24104650185414f379d5cc35c0e2c19f06684a73de5b472bae79e0d855771ecf","impliedFormat":99},{"version":"799003c0ab928582fca04977f47b8d85b43a8de610f4eef0ad2d069fbb9f9399","impliedFormat":99},{"version":"b13dd41c344a23e085f81b2f5cd96792e6b35ae814f32b25e39d9841844ad240","impliedFormat":99},{"version":"17d8b4e6416e48b6e23b73d05fd2fde407e2af8fddbe9da2a98ede14949c3489","impliedFormat":99},{"version":"6d17b2b41f874ab4369b8e04bdbe660163ea5c8239785c850f767370604959e3","impliedFormat":99},{"version":"04b4c044c8fe6af77b6c196a16c41e0f7d76b285d036d79dcaa6d92e24b4982b","impliedFormat":99},{"version":"30bdeead5293c1ddfaea4097d3e9dd5a6b0bc59a1e07ff4714ea1bbe7c5b2318","impliedFormat":99},{"version":"e7df226dcc1b0ce76b32f160556f3d1550124c894aae2d5f73cefaaf28df7779","impliedFormat":99},{"version":"f2b7eef5c46c61e6e72fba9afd7cc612a08c0c48ed44c3c5518559d8508146a2","impliedFormat":99},{"version":"00f0ba57e829398d10168b7db1e16217f87933e61bd8612b53a894bd7d6371da","impliedFormat":99},{"version":"126b20947d9fa74a88bb4e9281462bda05e529f90e22d08ee9f116a224291e84","impliedFormat":99},{"version":"40d9e43acee39702745eb5c641993978ac40f227475eacc99a83ba893ad995db","impliedFormat":99},{"version":"8a66b69b21c8de9cb88b4b6d12f655d5b7636e692a014c5aa1bd81745c8c51d5","impliedFormat":99},{"version":"ebbb846bdd5a78fdacff59ae04cea7a097912aeb1a2b34f8d88f4ebb84643069","impliedFormat":99},{"version":"7321adb29ffd637acb33ee67ea035f1a97d0aa0b14173291cc2fd58e93296e04","impliedFormat":99},{"version":"320816f1a4211188f07a782bdb6c1a44555b3e716ce13018f528ad7387108d5f","impliedFormat":99},{"version":"b2cc8a474b7657f4a03c67baf6bff75e26635fd4b5850675e8cad524a09ddd0c","impliedFormat":99},{"version":"0d081e9dc251063cc69611041c17d25847e8bdbe18164baaa89b7f1f1633c0ab","impliedFormat":99},{"version":"a64c25d8f4ec16339db49867ea2324e77060782993432a875d6e5e8608b0de1e","impliedFormat":99},{"version":"0739310b6b777f3e2baaf908c0fbc622c71160e6310eb93e0d820d86a52e2e23","impliedFormat":99},{"version":"37b32e4eadd8cd3c263e7ac1681c58b2ac54f3f77bb34c5e4326cc78516d55a9","impliedFormat":99},{"version":"9b7a8974e028c4ed6f7f9abb969e3eb224c069fd7f226e26fcc3a5b0e2a1eba8","impliedFormat":99},{"version":"e8100b569926a5592146ed68a0418109d625a045a94ed878a8c5152b1379237c","impliedFormat":99},{"version":"594201c616c318b7f3149a912abd8d6bdf338d765b7bcbde86bca2e66b144606","impliedFormat":99},{"version":"03e380975e047c5c6ded532cf8589e6cc85abb7be3629e1e4b0c9e703f2fd36f","impliedFormat":99},{"version":"fae14b53b7f52a8eb3274c67c11f261a58530969885599efe3df0277b48909e1","impliedFormat":99},{"version":"c41206757c428186f2e0d1fd373915c823504c249336bdc9a9c9bbdf9da95fef","impliedFormat":99},{"version":"e961f853b7b0111c42b763a6aa46fc70d06a697db3d8ed69b38f7ba0ae42a62b","impliedFormat":99},{"version":"3db90f79e36bcb60b3f8de1bc60321026800979c150e5615047d598c787a64b7","impliedFormat":99},{"version":"639b6fb3afbb8f6067c1564af2bd284c3e883f0f1556d59bd5eb87cdbbdd8486","impliedFormat":99},{"version":"49795f5478cb607fd5965aa337135a8e7fd1c58bc40c0b6db726adf186dd403f","impliedFormat":99},{"version":"7d8890e6e2e4e215959e71d5b5bd49482cf7a23be68d48ea446601a4c99bd511","impliedFormat":99},{"version":"d56f72c4bb518de5702b8b6ae3d3c3045c99e0fd48b3d3b54c653693a8378017","impliedFormat":99},{"version":"4c9ac40163e4265b5750510d6d2933fb7b39023eed69f7b7c68b540ad960826e","impliedFormat":99},{"version":"8dfab17cf48e7be6e023c438a9cdf6d15a9b4d2fa976c26e223ba40c53eb8da8","impliedFormat":99},{"version":"38bdf7ccacfd8e418de3a7b1e3cecc29b5625f90abc2fa4ac7843a290f3bf555","impliedFormat":99},{"version":"9819e46a914735211fbc04b8dc6ba65152c62e3a329ca0601a46ba6e05b2c897","impliedFormat":99},{"version":"50f0dc9a42931fb5d65cdd64ba0f7b378aedd36e0cfca988aa4109aad5e714cb","impliedFormat":99},{"version":"894f23066f9fafccc6e2dd006ed5bd85f3b913de90f17cf1fe15a2eb677fd603","impliedFormat":99},{"version":"abdf39173867e6c2d6045f120a316de451bbb6351a6929546b8470ddf2e4b3b9","impliedFormat":99},{"version":"aa2cb4053f948fbd606228195bbe44d78733861b6f7204558bbee603202ee440","impliedFormat":99},{"version":"6911b41bfe9942ac59c2da1bbcbe5c3c1f4e510bf65cae89ed00f434cc588860","impliedFormat":99},{"version":"7b81bc4d4e2c764e85d869a8dd9fe3652b34b45c065482ac94ffaacc642b2507","impliedFormat":99},{"version":"895df4edb46ccdcbce2ec982f5eed292cf7ea3f7168f1efea738ee346feab273","impliedFormat":99},{"version":"8692bb1a4799eda7b2e3288a6646519d4cebb9a0bddf800085fc1bd8076997a0","impliedFormat":99},{"version":"239c9e98547fe99711b01a0293f8a1a776fc10330094aa261f3970aaba957c82","impliedFormat":99},{"version":"34833ec50360a32efdc12780ae624e9a710dd1fd7013b58c540abf856b54285a","impliedFormat":99},{"version":"647538e4007dcc351a8882067310a0835b5bb8559d1cfa5f378e929bceb2e64d","impliedFormat":99},{"version":"992d6b1abcc9b6092e5a574d51d441238566b6461ade5de53cb9718e4f27da46","impliedFormat":99},{"version":"938702305649bf1050bd79f3803cf5cc2904596fc1edd4e3b91033184eae5c54","impliedFormat":99},{"version":"1e931d3c367d4b96fe043e792196d9c2cf74f672ff9c0b894be54e000280a79d","impliedFormat":99},{"version":"05bec322ea9f6eb9efcd6458bb47087e55bd688afdd232b78379eb5d526816ed","impliedFormat":99},{"version":"4c449a874c2d2e5e5bc508e6aa98f3140218e78c585597a21a508a647acd780a","impliedFormat":99},{"version":"dae15e326140a633d7693e92b1af63274f7295ea94fb7c322d5cbe3f5e48be88","impliedFormat":99},{"version":"c2b0a869713bca307e58d81d1d1f4b99ebfc7ec8b8f17e80dde40739aa8a2bc6","impliedFormat":99},{"version":"6e4b4ff6c7c54fa9c6022e88f2f3e675eac3c6923143eb8b9139150f09074049","impliedFormat":99},{"version":"69559172a9a97bbe34a32bff8c24ef1d8c8063feb5f16a6d3407833b7ee504cf","impliedFormat":99},{"version":"86b94a2a3edcb78d9bfcdb3b382547d47cb017e71abe770c9ee8721e9c84857f","impliedFormat":99},{"version":"e3fafafda82853c45c0afc075fea1eaf0df373a06daf6e6c7f382f9f61b2deb3","impliedFormat":99},{"version":"a4ba4b31de9e9140bc49c0addddbfaf96b943a7956a46d45f894822e12bf5560","impliedFormat":99},{"version":"d8a7926fc75f2ed887f17bae732ee31a4064b8a95a406c87e430c58578ee1f67","impliedFormat":99},{"version":"9886ffbb134b0a0059fd82219eba2a75f8af341d98bc6331b6ef8a921e10ec68","impliedFormat":99},{"version":"c2ead057b70d0ae7b87a771461a6222ebdb187ba6f300c974768b0ae5966d10e","impliedFormat":99},{"version":"46687d985aed8485ab2c71085f82fafb11e69e82e8552cf5d3849c00e64a00a5","impliedFormat":99},{"version":"999ca66d4b5e2790b656e0a7ce42267737577fc7a52b891e97644ec418eff7ec","impliedFormat":99},{"version":"ec948ee7e92d0888f92d4a490fdd0afb27fbf6d7aabebe2347a3e8ac82c36db9","impliedFormat":99},{"version":"03ef2386c683707ce741a1c30cb126e8c51a908aa0acc01c3471fafb9baaacd5","impliedFormat":99},{"version":"66a372e03c41d2d5e920df5282dadcec2acae4c629cb51cab850825d2a144cea","impliedFormat":99},{"version":"ddf9b157bd4c06c2e4646c9f034f36267a0fbd028bd4738214709de7ea7c548b","impliedFormat":99},{"version":"3e795aac9be23d4ad9781c00b153e7603be580602e40e5228e2dafe8a8e3aba1","impliedFormat":99},{"version":"98c461ec5953dfb1b5d5bca5fee0833c8a932383b9e651ca6548e55f1e2c71c3","impliedFormat":99},{"version":"5c42107b46cb1d36b6f1dee268df125e930b81f9b47b5fa0b7a5f2a42d556c10","impliedFormat":99},{"version":"7e32f1251d1e986e9dd98b6ff25f62c06445301b94aeebdf1f4296dbd2b8652f","impliedFormat":99},{"version":"2f7e328dda700dcb2b72db0f58c652ae926913de27391bd11505fc5e9aae6c33","impliedFormat":99},{"version":"3de7190e4d37da0c316db53a8a60096dbcd06d1a50677ccf11d182fa26882080","impliedFormat":99},{"version":"a9d6f87e59b32b02c861aade3f4477d7277c30d43939462b93f48644fa548c58","impliedFormat":99},{"version":"2bce8fd2d16a9432110bbe0ba1e663fd02f7d8b8968cd10178ea7bc306c4a5df","impliedFormat":99},{"version":"798bedbf45a8f1e55594e6879cd46023e8767757ecce1d3feaa78d16ad728703","impliedFormat":99},{"version":"62723d5ac66f7ed6885a3931dd5cfa017797e73000d590492988a944832e8bc2","impliedFormat":99},{"version":"03db8e7df7514bf17fc729c87fff56ca99567b9aa50821f544587a666537c233","impliedFormat":99},{"version":"9b1f311ba4409968b68bf20b5d892dbd3c5b1d65c673d5841c7dbde351bc0d0b","impliedFormat":99},{"version":"2d1e8b5431502739fe335ceec0aaded030b0f918e758a5d76f61effa0965b189","impliedFormat":99},{"version":"e725839b8f884dab141b42e9d7ff5659212f6e1d7b4054caa23bc719a4629071","impliedFormat":99},{"version":"4fa38a0b8ae02507f966675d0a7d230ed67c92ab8b5736d99a16c5fbe2b42036","impliedFormat":99},{"version":"50ec1e8c23bad160ddedf8debeebc722becbddda127b8fdce06c23eacd3fe689","impliedFormat":99},{"version":"9a0aea3a113064fd607f41375ade308c035911d3c8af5ae9db89593b5ca9f1f9","impliedFormat":99},{"version":"8d643903b58a0bf739ce4e6a8b0e5fb3fbdfaacbae50581b90803934b27d5b89","impliedFormat":99},{"version":"19de2915ccebc0a1482c2337b34cb178d446def2493bf775c4018a4ea355adb8","impliedFormat":99},{"version":"9be8fc03c8b5392cd17d40fd61063d73f08d0ee3457ecf075dcb3768ae1427bd","impliedFormat":99},{"version":"a2d89a8dc5a993514ca79585039eea083a56822b1d9b9d9d85b14232e4782cbe","impliedFormat":99},{"version":"f526f20cae73f17e8f38905de4c3765287575c9c4d9ecacee41cfda8c887da5b","impliedFormat":99},{"version":"d9ec0978b7023612b9b83a71fee8972e290d02f8ff894e95cdd732cd0213b070","impliedFormat":99},{"version":"7ab10c473a058ec8ac4790b05cae6f3a86c56be9b0c0a897771d428a2a48a9f9","impliedFormat":99},{"version":"451d7a93f8249d2e1453b495b13805e58f47784ef2131061821b0e456a9fd0e1","impliedFormat":99},{"version":"21c56fe515d227ed4943f275a8b242d884046001722a4ba81f342a08dbe74ae2","impliedFormat":99},{"version":"d8311f0c39381aa1825081c921efde36e618c5cf46258c351633342a11601208","impliedFormat":99},{"version":"6b50c3bcc92dc417047740810596fcb2df2502aa3f280c9e7827e87896da168a","impliedFormat":99},{"version":"18a6b318d1e7b31e5749a52be0cf9bbce1b275f63190ef32e2c79db0579328ca","impliedFormat":99},{"version":"6a2d0af2c27b993aa85414f3759898502aa198301bc58b0d410948fe908b07b0","impliedFormat":99},{"version":"2da11b6f5c374300e5e66a6b01c3c78ec21b5d3fec0748a28cc28e00be73e006","impliedFormat":99},{"version":"0729691b39c24d222f0b854776b00530877217bfc30aac1dc7fa2f4b1795c536","impliedFormat":99},{"version":"ca45bb5c98c474d669f0e47615e4a5ae65d90a2e78531fda7862ee43e687a059","impliedFormat":99},{"version":"c1c058b91d5b9a24c95a51aea814b0ad4185f411c38ac1d5eef0bf3cebec17dc","impliedFormat":99},{"version":"3ab0ed4060b8e5b5e594138aab3e7f0262d68ad671d6678bcda51568d4fc4ccc","impliedFormat":99},{"version":"e2bf1faba4ff10a6020c41df276411f641d3fdce5c6bae1db0ec84a0bf042106","impliedFormat":99},{"version":"80b0a8fe14d47a71e23d7c3d4dcee9584d4282ef1d843b70cab1a42a4ea1588c","impliedFormat":99},{"version":"a0f02a73f6e3de48168d14abe33bf5970fdacdb52d7c574e908e75ad571e78f7","impliedFormat":99},{"version":"c728002a759d8ec6bccb10eed56184e86aeff0a762c1555b62b5d0fa9d1f7d64","impliedFormat":99},{"version":"586f94e07a295f3d02f847f9e0e47dbf14c16e04ccc172b011b3f4774a28aaea","impliedFormat":99},{"version":"cfe1a0f4ed2df36a2c65ea6bc235dbb8cf6e6c25feb6629989f1fa51210b32e7","impliedFormat":99},{"version":"8ba69c9bf6de79c177329451ffde48ddab7ec495410b86972ded226552f664df","impliedFormat":99},{"version":"15111cbe020f8802ad1d150524f974a5251f53d2fe10eb55675f9df1e82dbb62","impliedFormat":99},{"version":"782dc153c56a99c9ed07b2f6f497d8ad2747764966876dbfef32f3e27ce11421","impliedFormat":99},{"version":"cc2db30c3d8bb7feb53a9c9ff9b0b859dd5e04c83d678680930b5594b2bf99cb","impliedFormat":99},{"version":"46909b8c85a6fd52e0807d18045da0991e3bdc7373435794a6ba425bc23cc6be","impliedFormat":99},{"version":"e4e511ff63bb6bd69a2a51e472c6044298bca2c27835a34a20827bc3ef9b7d13","impliedFormat":99},{"version":"2c86f279d7db3c024de0f21cd9c8c2c972972f842357016bfbbd86955723b223","impliedFormat":99},{"version":"112c895cff9554cf754f928477c7d58a21191c8089bffbf6905c87fe2dc6054f","impliedFormat":99},{"version":"8cfc293b33082003cacbf7856b8b5e2d6dd3bde46abbd575b0c935dc83af4844","impliedFormat":99},{"version":"d2c5c53f85ce0474b3a876d76c4fc44ff7bb766b14ed1bf495f9abac181d7f5f","impliedFormat":99},{"version":"3c523f27926905fcbe20b8301a0cc2da317f3f9aea2273f8fc8d9ae88b524819","impliedFormat":99},{"version":"9ca0d706f6b039cc52552323aeccb4db72e600b67ddc7a54cebc095fc6f35539","impliedFormat":99},{"version":"a64909a9f75081342ddd061f8c6b49decf0d28051bc78e698d347bdcb9746577","impliedFormat":99},{"version":"7d8d55ae58766d0d52033eae73084c4db6a93c4630a3e17f419dd8a0b2a4dcd8","impliedFormat":99},{"version":"b8b5c8ba972d9ffff313b3c8a3321e7c14523fc58173862187e8d1cb814168ac","impliedFormat":99},{"version":"9c42c0fa76ee36cf9cc7cc34b1389fbb4bd49033ec124b93674ec635fabf7ffe","impliedFormat":99},{"version":"6184c8da9d8107e3e67c0b99dedb5d2dfe5ccf6dfea55c2a71d4037caf8ca196","impliedFormat":99},{"version":"4030ceea7bf41449c1b86478b786e3b7eadd13dfe5a4f8f5fe2eb359260e08b3","impliedFormat":99},{"version":"7bf516ec5dfc60e97a5bde32a6b73d772bd9de24a2e0ec91d83138d39ac83d04","impliedFormat":99},{"version":"e6a6fb3e6525f84edf42ba92e261240d4efead3093aca3d6eb1799d5942ba393","impliedFormat":99},{"version":"45df74648934f97d26800262e9b2af2f77ef7191d4a5c2eb1df0062f55e77891","impliedFormat":99},{"version":"3fe361e4e567f32a53af1f2c67ad62d958e3d264e974b0a8763d174102fe3b29","impliedFormat":99},{"version":"28b520acee4bc6911bfe458d1ad3ebc455fa23678463f59946ad97a327c9ab2b","impliedFormat":99},{"version":"121b39b1a9ad5d23ed1076b0db2fe326025150ef476dccb8bf87778fcc4f6dd7","impliedFormat":99},{"version":"f791f92a060b52aa043dde44eb60307938f18d4c7ac13df1b52c82a1e658953f","impliedFormat":99},{"version":"df09443e7743fd6adc7eb108e760084bacdf5914403b7aac5fbd4dc4e24e0c2c","impliedFormat":99},{"version":"eeb4ff4aa06956083eaa2aad59070361c20254b865d986bc997ee345dbd44cbb","impliedFormat":99},{"version":"ed84d5043444d51e1e5908f664addc4472c227b9da8401f13daa565f23624b6e","impliedFormat":99},{"version":"146bf888b703d8baa825f3f2fb1b7b31bda5dff803e15973d9636cdda33f4af3","impliedFormat":99},{"version":"b4ec8b7a8d23bdf7e1c31e43e5beac3209deb7571d2ccf2a9572865bf242da7c","impliedFormat":99},{"version":"3fba0d61d172091638e56fba651aa1f8a8500aac02147d29bd5a9cc0bc8f9ec2","impliedFormat":99},{"version":"a5a57deb0351b03041e0a1448d3a0cc5558c48e0ed9b79b69c99163cdca64ad8","impliedFormat":99},{"version":"9bcecf0cbc2bfc17e33199864c19549905309a0f9ecc37871146107aac6e05ae","impliedFormat":99},{"version":"d6a211db4b4a821e93c978add57e484f2a003142a6aef9dbfa1fe990c66f337b","impliedFormat":99},{"version":"bd4d10bd44ce3f630dd9ce44f102422cb2814ead5711955aa537a52c8d2cae14","impliedFormat":99},{"version":"08e4c39ab1e52eea1e528ee597170480405716bae92ebe7a7c529f490afff1e0","impliedFormat":99},{"version":"625bb2bc3867557ea7912bd4581288a9fca4f3423b8dffa1d9ed57fafc8610e3","impliedFormat":99},{"version":"d1992164ecc334257e0bef56b1fd7e3e1cea649c70c64ffc39999bb480c0ecdf","impliedFormat":99},{"version":"a53ff2c4037481eb357e33b85e0d78e8236e285b6428b93aa286ceea1db2f5dc","impliedFormat":99},{"version":"4fe608d524954b6857d78857efce623852fcb0c155f010710656f9db86e973a5","impliedFormat":99},{"version":"b53b62a9838d3f57b70cc456093662302abb9962e5555f5def046172a4fe0d4e","impliedFormat":99},{"version":"9866369eb72b6e77be2a92589c9df9be1232a1a66e96736170819e8a1297b61f","impliedFormat":99},{"version":"43abfbdf4e297868d780b8f4cfdd8b781b90ecd9f588b05e845192146a86df34","impliedFormat":99},{"version":"582419791241fb851403ae4a08d0712a63d4c94787524a7419c2bc8e0eb1b031","impliedFormat":99},{"version":"18437eeb932fe48590b15f404090db0ab3b32d58f831d5ffc157f63b04885ee5","impliedFormat":99},{"version":"0c5eaedf622d7a8150f5c2ec1f79ac3d51eea1966b0b3e61bfdea35e8ca213a7","impliedFormat":99},{"version":"fac39fc7a9367c0246de3543a6ee866a0cf2e4c3a8f64641461c9f2dac0d8aae","impliedFormat":99},{"version":"3b9f559d0200134f3c196168630997caedeadc6733523c8b6076a09615d5dec8","impliedFormat":99},{"version":"932af64286d9723da5ef7b77a0c4229829ce8e085e6bcc5f874cb0b83e8310d4","impliedFormat":99},{"version":"adeb9278f11f5561157feee565171c72fd48f5fe34ed06f71abf24e561fcaa1e","impliedFormat":99},{"version":"2269fef79b4900fc6b08c840260622ca33524771ff24fda5b9101ad98ea551f3","impliedFormat":99},{"version":"73d47498a1b73d5392d40fb42a3e7b009ae900c8423f4088c4faa663cc508886","impliedFormat":99},{"version":"7efc34cdc4da0968c3ba687bc780d5cacde561915577d8d1c1e46c7ac931d023","impliedFormat":99},{"version":"3c20a3bb0c50c819419f44aa55acc58476dad4754a16884cef06012d02b0722f","impliedFormat":99},{"version":"4569abf6bc7d51a455503670f3f1c0e9b4f8632a3b030e0794c61bfbba2d13be","impliedFormat":99},{"version":"98b2297b4dc1404078a54b61758d8643e4c1d7830af724f3ed2445d77a7a2d57","impliedFormat":99},{"version":"952ba89d75f1b589e07070fea2d8174332e3028752e76fd46e1c16cc51e6e2af","impliedFormat":99},{"version":"b6c9a2deefb6a57ff68d2a38d33c34407b9939487fc9ee9f32ba3ecf2987a88a","impliedFormat":99},{"version":"f6b371377bab3018dac2bca63e27502ecbd5d06f708ad7e312658d3b5315d948","impliedFormat":99},{"version":"31947dd8f1c8eeb7841e1f139a493a73bd520f90e59a6415375d0d8e6a031f01","impliedFormat":99},{"version":"95cd83b807e10b1af408e62caf5fea98562221e8ddca9d7ccc053d482283ddda","impliedFormat":99},{"version":"19287d6b76288c2814f1633bdd68d2b76748757ffd355e73e41151644e4773d6","impliedFormat":99},{"version":"fc4e6ec7dade5f9d422b153c5d8f6ad074bd9cc4e280415b7dc58fb5c52b5df1","impliedFormat":99},{"version":"3aea973106e1184db82d8880f0ca134388b6cbc420f7309d1c8947b842886349","impliedFormat":99},{"version":"765e278c464923da94dda7c2b281ece92f58981642421ae097862effe2bd30fa","impliedFormat":99},{"version":"de260bed7f7d25593f59e859bd7c7f8c6e6bb87e8686a0fcafa3774cb5ca02d8","impliedFormat":99},{"version":"b5c341ce978f5777fbe05bc86f65e9906a492fa6b327bda3c6aae900c22e76c6","impliedFormat":99},{"version":"686ddbfaf88f06b02c6324005042f85317187866ca0f8f4c9584dd9479653344","impliedFormat":99},{"version":"7f789c0c1db29dd3aab6e159d1ba82894a046bf8df595ac48385931ae6ad83e0","impliedFormat":99},{"version":"8eb3057d4fe9b59b2492921b73a795a2455ebe94ccb3d01027a7866612ead137","impliedFormat":99},{"version":"1e43c5d7aee1c5ec20611e28b5417f5840c75d048de9d7f1800d6808499236f8","impliedFormat":99},{"version":"d42610a5a2bee4b71769968a24878885c9910cd049569daa2d2ee94208b3a7a5","impliedFormat":99},{"version":"f6ed95506a6ed2d40ed5425747529befaa4c35fcbbc1e0d793813f6d725690fa","impliedFormat":99},{"version":"a6fcc1cd6583939506c906dff1276e7ebdc38fbe12d3e108ba38ad231bd18d97","impliedFormat":99},{"version":"ed13354f0d96fb6d5878655b1fead51722b54875e91d5e53ef16de5b71a0e278","impliedFormat":99},{"version":"1193b4872c1fb65769d8b164ca48124c7ebacc33eae03abf52087c2b29e8c46c","impliedFormat":99},{"version":"af682dfabe85688289b420d939020a10eb61f0120e393d53c127f1968b3e9f66","impliedFormat":99},{"version":"0dca04006bf13f72240c6a6a502df9c0b49c41c3cab2be75e81e9b592dcd4ea8","impliedFormat":99},{"version":"79d6ac4a2a229047259116688f9cd62fda25422dee3ad304f77d7e9af53a41ef","impliedFormat":99},{"version":"64534c17173990dc4c3d9388d16675a059aac407031cfce8f7fdffa4ee2de988","impliedFormat":99},{"version":"ba46d160a192639f3ca9e5b640b870b1263f24ac77b6895ab42960937b42dcbb","impliedFormat":99},{"version":"5e5ddd6fc5b590190dde881974ab969455e7fad61012e32423415ae3d085b037","impliedFormat":99},{"version":"1c16fd00c42b60b96fe0fa62113a953af58ddf0d93b0a49cb4919cf5644616f0","impliedFormat":99},{"version":"eb240c0e6b412c57f7d9a9f1c6cd933642a929837c807b179a818f6e8d3a4e44","impliedFormat":99},{"version":"4a7bde5a1155107fc7d9483b8830099f1a6072b6afda5b78d91eb5d6549b3956","impliedFormat":99},{"version":"3c1baaffa9a24cc7ef9eea6b64742394498e0616b127ca630aca0e11e3298006","impliedFormat":99},{"version":"87ca1c31a326c898fa3feb99ec10750d775e1c84dbb7c4b37252bcf3742c7b21","impliedFormat":99},{"version":"d7bd26af1f5457f037225602035c2d7e876b80d02663ab4ca644099ad3a55888","impliedFormat":99},{"version":"2ad0a6b93e84a56b64f92f36a07de7ebcb910822f9a72ad22df5f5d642aff6f3","impliedFormat":99},{"version":"523d1775135260f53f672264937ee0f3dc42a92a39de8bee6c48c7ea60b50b5a","impliedFormat":99},{"version":"e441b9eebbc1284e5d995d99b53ed520b76a87cab512286651c4612d86cd408e","impliedFormat":99},{"version":"76f853ee21425c339a79d28e0859d74f2e53dee2e4919edafff6883dd7b7a80f","impliedFormat":99},{"version":"00cf042cd6ba1915648c8d6d2aa00e63bbbc300ea54d28ed087185f0f662e080","impliedFormat":99},{"version":"f57e6707d035ab89a03797d34faef37deefd3dd90aa17d90de2f33dce46a2c56","impliedFormat":99},{"version":"cc8b559b2cf9380ca72922c64576a43f000275c72042b2af2415ce0fb88d7077","impliedFormat":99},{"version":"1a337ca294c428ba8f2eb01e887b28d080ee4a4307ae87e02e468b1d26af4a74","impliedFormat":99},{"version":"5a15362fc2e72765a908c0d4dd89e3ab3b763e8bc8c23f19234a709ecfd202fe","impliedFormat":99},{"version":"2dffdfe62ac8af0943853234519616db6fd8958fc7ff631149fd8364e663f361","impliedFormat":99},{"version":"5dbdb2b2229b5547d8177c34705272da5a10b8d0033c49efbc9f6efba5e617f2","impliedFormat":99},{"version":"6fc0498cd8823d139004baff830343c9a0d210c687b2402c1384fb40f0aa461c","impliedFormat":99},{"version":"8492306a4864a1dc6fc7e0cc0de0ae9279cbd37f3aae3e9dc1065afcdc83dddc","impliedFormat":99},{"version":"c011b378127497d6337a93f020a05f726db2c30d55dc56d20e6a5090f05919a6","impliedFormat":99},{"version":"f4556979e95a274687ae206bbab2bb9a71c3ad923b92df241d9ab88c184b3f40","impliedFormat":99},{"version":"50e82bb6e238db008b5beba16d733b77e8b2a933c9152d1019cf8096845171a4","impliedFormat":99},{"version":"d6011f8b8bbf5163ef1e73588e64a53e8bf1f13533c375ec53e631aad95f1375","impliedFormat":99},{"version":"693cd7936ac7acfa026d4bcb5801fce71cec49835ba45c67af1ef90dbfd30af7","impliedFormat":99},{"version":"195e2cf684ecddfc1f6420564535d7c469f9611ce7a380d6e191811f84556cd2","impliedFormat":99},{"version":"1dc6b6e7b2a7f2962f31c77f4713f3a5a132bbe14c00db75d557568fe82e4311","impliedFormat":99},{"version":"add93b1180e9aaac2dae4ef3b16f7655893e2ecbe62bd9e48366c305f0063d89","impliedFormat":99},{"version":"594bd896fe37c970aafb7a376ebeec4c0d636b62a5f611e2e27d30fb839ad8a5","impliedFormat":99},{"version":"b1c6a6faf60542ba4b4271db045d7faea56e143b326ef507d2797815250f3afc","impliedFormat":99},{"version":"8c8b165beb794260f462679329b131419e9f5f35212de11c4d53e6d4d9cbedf6","impliedFormat":99},{"version":"ee5a4cf57d49fcf977249ab73c690a59995997c4672bb73fcaaf2eed65dbd1b2","impliedFormat":99},{"version":"f9f36051f138ab1c40b76b230c2a12b3ce6e1271179f4508da06a959f8bee4c1","impliedFormat":99},{"version":"9dc2011a3573d271a45c12656326530c0930f92539accbec3531d65131a14a14","impliedFormat":99},{"version":"091521ce3ede6747f784ae6f68ad2ea86bbda76b59d2bf678bcad2f9d141f629","impliedFormat":99},{"version":"202c2be951f53bafe943fb2c8d1245e35ed0e4dfed89f48c9a948e4d186dd6d4","impliedFormat":99},{"version":"c618aead1d799dbf4f5b28df5a6b9ce13d72722000a0ec3fe90a8115b1ea9226","impliedFormat":99},{"version":"9b0bf59708549c3e77fddd36530b95b55419414f88bbe5893f7bc8b534617973","impliedFormat":99},{"version":"7e216f67c4886f1bde564fb4eebdd6b185f262fe85ad1d6128cad9b229b10354","impliedFormat":99},{"version":"cd51e60b96b4d43698df74a665aa7a16604488193de86aa60ec0c44d9f114951","impliedFormat":99},{"version":"b63341fb6c7ba6f2aeabd9fc46b43e6cc2d2b9eec06534cfd583d9709f310ec2","impliedFormat":99},{"version":"be2af50c81b15bcfe54ad60f53eb1c72dae681c72d0a9dce1967825e1b5830a3","impliedFormat":99},{"version":"be5366845dfb9726f05005331b9b9645f237f1ddc594c0def851208e8b7d297b","impliedFormat":99},{"version":"5ddd536aaeadd4bf0f020492b3788ed209a7050ce27abec4e01c7563ff65da81","impliedFormat":99},{"version":"e243b24da119c1ef0d79af2a45217e50682b139cb48e7607efd66cc01bd9dcda","impliedFormat":99},{"version":"5b1398c8257fd180d0bf62e999fe0a89751c641e87089a83b24392efda720476","impliedFormat":99},{"version":"1588b1359f8507a16dbef67cd2759965fc2e8d305e5b3eb71be5aa9506277dff","impliedFormat":99},{"version":"4c99f2524eee1ec81356e2b4f67047a4b7efaf145f1c4eb530cd358c36784423","impliedFormat":99},{"version":"b30c6b9f6f30c35d6ef84daed1c3781e367f4360171b90598c02468b0db2fc3d","impliedFormat":99},{"version":"79c0d32274ccfd45fae74ac61d17a2be27aea74c70806d22c43fc625b7e9f12a","impliedFormat":99},{"version":"1b7e3958f668063c9d24ac75279f3e610755b0f49b1c02bb3b1c232deb958f54","impliedFormat":99},{"version":"779d4022c3d0a4df070f94858a33d9ebf54af3664754536c4ce9fd37c6f4a8db","impliedFormat":99},{"version":"e662f063d46aa8c088edffdf1d96cb13d9a2cbf06bc38dc6fc62b4d125fb7b49","impliedFormat":99},{"version":"d1d612df1e41c90d9678b07740d13d4f8e6acec2f17390d4ff4be5c889a6d37d","impliedFormat":99},{"version":"c95933fe140918892d569186f17b70ef6b1162f851a0f13f6a89e8f4d599c5a1","impliedFormat":99},{"version":"1d8d30677f87c13c2786980a80750ac1e281bdb65aa013ea193766fe9f0edd74","impliedFormat":99},{"version":"4661673cbc984b8a6ee5e14875a71ed529b64e7f8e347e12c0db4cecc25ad67d","impliedFormat":99},{"version":"7f980a414274f0f23658baa9a16e21d828535f9eac538e2eab2bb965325841db","impliedFormat":99},{"version":"20fb747a339d3c1d4a032a31881d0c65695f8167575e01f222df98791a65da9b","impliedFormat":99},{"version":"dd4e7ebd3f205a11becf1157422f98db675a626243d2fbd123b8b93efe5fb505","impliedFormat":99},{"version":"43ec6b74c8d31e88bb6947bb256ad78e5c6c435cbbbad991c3ff39315b1a3dba","impliedFormat":99},{"version":"b27242dd3af2a5548d0c7231db7da63d6373636d6c4e72d9b616adaa2acef7e1","impliedFormat":99},{"version":"e0ee7ba0571b83c53a3d6ec761cf391e7128d8f8f590f8832c28661b73c21b68","impliedFormat":99},{"version":"072bfd97fc61c894ef260723f43a416d49ebd8b703696f647c8322671c598873","impliedFormat":99},{"version":"e70875232f5d5528f1650dd6f5c94a5bed344ecf04bdbb998f7f78a3c1317d02","impliedFormat":99},{"version":"8e495129cb6cd8008de6f4ff8ce34fe1302a9e0dcff8d13714bd5593be3f7898","impliedFormat":99},{"version":"418a98fd7dc017fc0bc714e4388015b64a7f45ee22a42ca1544edda611f9c215","signature":"46ffb83f1da0b20b82a4e724d4613d279549dac9762bf6b293a2f64da3ac7fb9"},{"version":"b9b85a68b5f9dad8a40c544f1e043217819d27f78b85b8253ef2b201b0cc1537","signature":"02206236174c891ecdf9bebf737d33c3ed1a994d0b7b8d29935bab15a2bbef25"},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"2540a81fc4127527aa85f3ae75e7e50f006b42d5745130a4de8911c6f881f042","signature":"bb0dfbd93a35b232bb2b36042266c565e235afd18be59f6568c76ce998c22234"},{"version":"a0ba4f7097553ed0bed9059e84ca095831aabf748dc34b79b175deb8c78cb106","signature":"d5e59c996b40dc9c1c7118299a6f9b395e136bb6bf103f945476d478b0896a64"},{"version":"2b9c1bf9fd5c0f4e357c58e872143f2dab3f56905336cc64f55e7bf794fbd7cb","signature":"f3395d0ee087666e598fac578c718cb2e3e6256930de1dce6a1b5f668048eb73"},{"version":"d2e0e355302281dd57e728a554ddb0b45d00dc8a85e66c755bf5ce7668cb5031","signature":"81c9f242ec94e15cacbf9ebade9e126b2006532e551342c1c3aa8a0be255bc51"},{"version":"e5beb5a284ec7a63debb18e55e0656227b5a100ae40c0dd7a39e2d8ba759dfd3","signature":"9d7ca13208db755a4127916edcdea4289dc3703282c1ab41647c1675d8bc2af4"},{"version":"8319876e79b66efe98ac2b5ce7ef0b375ebe371fdff6b30859ffcbaaadc1fc53","signature":"b5bf4986a3cff6b52f11323d266a07599001076bc32935c14e8f2006ecf0f838"},{"version":"a78fd7c0e1da6b06c86b4861502afe097e03cdbba5c54a5347484ead7d934a74","signature":"771a12fa01413532c912aaf29185ea8b6b19da1377411dc82dc0d8428099edd4"},{"version":"fc3e46e5814f723966fc89a6607a873d9aa6b6950800c7011bfb412f82060796","signature":"633b299b3a0399d0f4bfc1dd6bb2548ee042a3c1fdbea2951272299c9521ec16"},{"version":"b871d83bbbff7b4fae762784fa9ca6f3cfd878ea6926dad6d4cd4f5fc9c1e3cd","signature":"610bf24bed3f13cf7c87dd6acd500825e6db22f10f3ac1fd3bb031f0c5b6a756"},{"version":"a80c339c546d5e6b718a5f9ccbf4dd34ea4f982e8d08fb08cb6dccac3d37df37","signature":"a58d283a450624bb9a3f264af64bf8a45eb8090205e99b7c5fe1be22b95e623e"},{"version":"9d05491f13fcb6fe53c3b3befb6fe8d5ddd5d7264aed0d2aa706b3b14bc49d6b","signature":"4d318581bada0fae99b725a03de54912e121823279e6cd14ab6ce48f8cd2e04c"},{"version":"02b3b77a8d29c9ac409edc1c7a4efa339e2a07e3c5b5e6ea16f108c6eef9e20e","impliedFormat":99},{"version":"15027fb59928687a2eb144393237aed9ea5c503f417b877f2792801d644456e3","impliedFormat":99},{"version":"d5602055e69da5aaf7dafa987dbf645f608f8c66536c7965680fe65420fed2fe","impliedFormat":99},{"version":"41a5ae482e864a6128e6054e88f1c0e06884793f92aff5c67144fb02d2373079","impliedFormat":1},{"version":"54fbe89e29d77e1a7fedadbd85dd1a5831dcd91ead31714e390f45b066efa587","impliedFormat":99},{"version":"8b011aff1804959d75f824fb7e49808554d8cb8e9fe84c80dc581e44a5b4f85c","impliedFormat":99},{"version":"fe6b53077c7fe54f4d5fa980454f29443441c6187f9aede54913211c3f9ae35d","signature":"7d70a28a148c5af9142e1f023e432720496c19a2dc018143c5f78e289253d239"},{"version":"a2be484586eefae384f39b584ad74ad6faaaf66e2e10f8347f6e7146fa267e8c","signature":"af624c72b28ea8c3ee0255b4af1ddabbe40f7d4c8cd6539c5e4e4356f39e0b27"},{"version":"552e970fa968e395edc1d549138f1ea2f3a081aa850b6fc56cc34359966384b8","signature":"da1430e9866c1ce3fa190da65b5873bda05d82338c8863588aa136380ff19c44"},{"version":"e21b87998c4d8f5d797a877e9697d73122da5d6e0c5efe27e1eb69409d520b01","signature":"233bf868506e6fb7576da957ddead506efb374fe8b70a1b56e0114f231fdadbb"},{"version":"a250988882bec3727c5eaa0db350c0e991cb7c3ac7cb1fa3d91e25bdc2e65f17","signature":"a2e3213c37e776988abf406671f65fa417a62130ee3306dbd72cf5ef3e3a0add"},{"version":"ff43cf44bd81b8f629ad121271c8e941a2216566baed8dca43f25b14d210d969","signature":"3a2b94b8d6b92049dd79d645451939beaaeebf2be8cb77d93df721ebc346dc4e"},{"version":"648121f492237c22f218e1ed70df8dca4cb70613eb006acd5ef01a9487ef6ab0","signature":"5290014c476c8f6ad526b7cd998607934ab68084c6e5fed468ee72decc7e72bd"},{"version":"25d4c5fe4c09ee9707bd5fd8f08146b2ea3ee87be87c4aec9079cc46976d27c0","signature":"faf98e0cdbeeae9fccc1331549ad24e80994340cb6ce9fc1e4d8484bda10753c","affectsGlobalScope":true},{"version":"d168769f971b97843da7fc903b8a14d54575ed50a71d42c304016d583a29b047","signature":"74f8bfa298a5dda24ca3c49a6bc49b6a2c8dc5c0ebdcee7e750680ec6dce24c3"},{"version":"968477d488b4aff44c6c907618762357549923f44cfc7e2c09dde3bad0fa8364","signature":"065c6f1242fa9f1625a2390c5012297b298ae2ab5c731ebf46d86bdc532e71cc"},{"version":"289dc8d557fe4913f4f276968c94e9fa0d627c02cb404b2fa3473f13b567679c","signature":"13ec735c77a91666e32ca4a6bbc0ac6877dfd1dcc82cbd352104e3a3bf5d4888"},{"version":"f4e450cb33f8928c945cd73090215e2851aa0e503bea07b3b8f369e3acc02a9e","signature":"0e71961d5bdb82fa3221264c785990da76df496340c6b70683e9f07b82d5fba9"},{"version":"19b50a4a8c46dc0b803242f73b7c7c7429ec02b5102d1fdfe287bfe2cdfa8896","signature":"c4f7d87b5dbb6b168f585e6b428aa73c637a0c70adc4cc42107ffd962c5097a8"},{"version":"ed0e3e68680ce1f60d40c1be93ba820af48ed28a414f0b399322c54645064eeb","signature":"7b87720aae5dbfb749d597c437531239e4019502dc0e78633561735db617b6f3"}],"root":[502,503,[643,656],[691,700],704,705,1010,1011],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":2},"referencedMap":[[502,1],[646,2],[647,3],[650,4],[651,4],[654,5],[655,6],[656,7],[694,8],[695,8],[696,9],[705,10],[1011,11],[704,12],[1010,13],[697,14],[698,15],[649,16],[644,17],[645,18],[643,19],[648,19],[652,19],[653,20],[691,21],[693,19],[692,22],[503,23],[700,24],[551,25],[516,26],[517,27],[522,28],[511,29],[520,30],[526,31],[552,32],[529,33],[515,34],[512,35],[510,36],[519,37],[508,38],[518,39],[513,40],[525,41],[527,42],[533,43],[542,44],[545,45],[544,46],[543,47],[541,48],[547,49],[523,50],[540,51],[535,52],[536,53],[546,54],[524,55],[539,56],[538,57],[537,50],[548,58],[550,59],[532,60],[530,61],[531,62],[534,63],[549,55],[592,64],[579,65],[577,66],[575,67],[578,68],[572,68],[576,69],[580,70],[582,71],[586,72],[589,73],[591,74],[588,75],[590,76],[581,77],[583,78],[642,79],[715,80],[980,81],[716,80],[717,82],[711,83],[92,84],[93,84],[132,85],[133,86],[134,87],[135,88],[136,89],[137,90],[138,91],[139,92],[140,93],[141,94],[142,94],[144,95],[143,96],[145,97],[146,98],[147,99],[131,100],[148,101],[149,102],[150,103],[183,104],[151,105],[152,106],[153,107],[154,108],[155,109],[156,110],[157,111],[158,112],[159,113],[160,114],[161,114],[162,115],[164,116],[166,117],[165,118],[167,36],[168,119],[169,120],[170,121],[171,122],[172,123],[173,124],[174,125],[175,126],[176,127],[177,128],[178,129],[179,130],[180,131],[181,132],[187,133],[404,80],[188,134],[186,80],[405,135],[184,136],[185,137],[85,138],[401,80],[261,80],[713,139],[712,140],[808,141],[787,142],[788,143],[724,141],[725,141],[726,141],[727,141],[728,141],[729,141],[730,141],[731,141],[732,141],[733,141],[734,141],[735,141],[736,141],[737,141],[738,141],[739,141],[740,141],[741,141],[742,141],[743,141],[745,141],[746,141],[748,141],[747,141],[749,141],[750,141],[751,141],[752,141],[753,141],[754,141],[755,141],[756,141],[757,141],[758,141],[759,141],[760,141],[761,141],[762,141],[763,141],[764,141],[765,141],[766,141],[767,141],[769,141],[770,141],[771,141],[768,141],[772,141],[773,141],[774,141],[775,141],[776,141],[777,141],[778,141],[779,141],[780,141],[781,141],[782,141],[783,141],[784,141],[785,141],[786,141],[789,144],[790,141],[791,141],[792,145],[793,146],[794,141],[795,141],[796,141],[797,141],[800,141],[798,141],[799,141],[801,141],[802,141],[803,141],[804,141],[805,141],[806,141],[807,141],[809,147],[810,141],[811,141],[812,141],[814,141],[813,141],[815,141],[816,141],[817,141],[818,141],[819,141],[820,141],[821,141],[822,141],[823,141],[824,141],[826,141],[825,141],[827,141],[977,148],[831,141],[832,141],[833,141],[834,141],[835,141],[836,141],[838,141],[840,141],[841,141],[842,141],[843,141],[844,141],[845,141],[846,141],[847,141],[848,141],[849,141],[850,141],[851,141],[852,141],[853,141],[854,141],[855,141],[856,141],[857,141],[858,141],[859,141],[860,141],[861,141],[862,141],[863,141],[864,141],[865,141],[866,141],[867,141],[868,141],[869,141],[870,141],[871,141],[873,141],[874,141],[875,141],[876,141],[877,141],[878,141],[879,141],[880,141],[881,141],[882,141],[883,141],[885,149],[721,141],[886,141],[887,141],[891,141],[897,141],[898,141],[899,141],[900,141],[901,141],[902,141],[903,141],[904,141],[909,150],[907,151],[908,152],[906,153],[905,141],[910,141],[911,141],[912,141],[913,141],[914,141],[915,141],[916,141],[917,141],[918,141],[919,141],[922,141],[923,141],[927,141],[928,141],[929,141],[930,141],[931,147],[932,141],[933,141],[934,141],[935,141],[936,141],[937,141],[938,141],[939,141],[940,141],[941,141],[942,141],[943,141],[944,141],[945,141],[946,141],[947,141],[948,141],[949,141],[950,141],[951,141],[952,141],[953,141],[954,141],[955,141],[956,141],[957,141],[958,141],[959,141],[960,141],[961,141],[962,141],[963,141],[964,141],[965,141],[966,141],[967,141],[968,141],[969,141],[970,141],[971,141],[972,141],[723,154],[683,155],[684,156],[682,157],[670,158],[675,159],[676,160],[679,161],[678,162],[677,163],[680,164],[687,165],[690,166],[689,167],[688,168],[681,169],[671,170],[686,171],[673,172],[669,173],[674,174],[672,158],[626,175],[595,176],[605,176],[596,176],[606,176],[597,176],[598,176],[613,176],[612,176],[614,176],[615,176],[607,176],[599,176],[608,176],[600,176],[609,176],[601,176],[603,176],[611,177],[604,176],[610,177],[616,177],[602,176],[617,176],[622,176],[623,176],[618,176],[620,176],[619,176],[621,176],[625,176],[719,80],[593,178],[701,179],[632,180],[631,181],[638,182],[640,183],[636,184],[635,185],[639,181],[633,186],[630,187],[641,188],[634,189],[629,190],[703,191],[702,192],[450,193],[455,194],[445,195],[208,196],[248,197],[429,198],[243,199],[418,200],[274,201],[328,202],[251,203],[252,204],[399,205],[415,206],[310,207],[423,208],[424,209],[422,210],[419,211],[250,212],[209,213],[354,214],[280,215],[210,216],[281,215],[276,215],[197,215],[246,217],[428,218],[375,219],[376,220],[370,80],[379,83],[371,221],[482,222],[481,223],[414,224],[475,225],[372,80],[304,226],[300,227],[305,228],[302,229],[480,230],[299,227],[469,231],[472,232],[289,233],[288,234],[287,235],[485,80],[286,236],[490,80],[492,237],[425,238],[426,239],[427,240],[202,241],[391,80],[195,242],[390,243],[389,244],[386,245],[384,246],[387,247],[385,246],[201,215],[262,248],[263,249],[260,250],[258,251],[259,252],[397,83],[283,83],[449,253],[456,254],[460,255],[432,256],[493,257],[444,258],[373,259],[374,260],[368,261],[396,262],[434,80],[360,263],[398,264],[393,265],[352,266],[433,267],[436,268],[362,269],[366,270],[357,271],[410,272],[443,273],[314,274],[329,275],[198,276],[442,277],[194,278],[264,279],[265,280],[341,281],[340,282],[334,283],[355,284],[338,285],[266,286],[364,287],[430,288],[343,289],[344,290],[346,291],[348,292],[347,293],[336,276],[350,294],[313,295],[335,296],[342,297],[224,298],[322,299],[326,300],[323,301],[325,302],[327,300],[324,301],[234,303],[284,304],[439,305],[464,306],[466,307],[361,308],[465,309],[437,267],[377,267],[315,310],[230,311],[231,312],[232,313],[228,314],[409,314],[278,314],[316,315],[279,315],[227,316],[320,317],[319,318],[318,319],[317,320],[438,321],[408,322],[407,323],[369,324],[403,325],[406,326],[417,327],[416,328],[412,329],[312,330],[309,331],[311,332],[308,333],[349,334],[351,335],[267,336],[358,238],[356,337],[269,338],[272,339],[270,340],[273,340],[275,341],[306,342],[298,80],[193,343],[458,80],[468,344],[297,80],[462,83],[296,345],[447,346],[294,344],[470,347],[292,80],[293,80],[291,348],[290,349],[237,350],[367,113],[277,113],[332,351],[395,227],[307,80],[441,241],[448,352],[86,80],[89,353],[90,354],[87,80],[247,355],[242,356],[240,357],[446,358],[457,359],[459,360],[461,361],[463,362],[467,363],[500,364],[471,364],[499,365],[473,366],[483,367],[484,368],[486,369],[495,370],[498,241],[496,371],[507,372],[627,373],[585,374],[584,375],[333,170],[996,376],[993,377],[997,378],[110,379],[119,380],[109,379],[128,381],[101,382],[100,383],[127,371],[121,384],[126,385],[103,386],[102,387],[124,388],[98,389],[97,390],[125,391],[99,392],[104,393],[108,393],[130,372],[129,393],[112,394],[113,395],[115,396],[111,397],[114,398],[122,371],[106,399],[107,400],[116,401],[96,402],[118,403],[117,393],[123,404],[557,405],[555,406],[553,19],[554,407],[556,408],[668,409],[667,410],[1007,19],[1008,411],[1005,19],[1006,410],[1009,412],[504,19],[505,19],[568,413],[567,414],[1003,415],[1004,416],[558,19],[657,410],[658,417],[659,410],[660,410],[661,418],[666,419],[664,410],[665,420],[663,410],[662,410],[565,421],[563,422],[562,19],[561,423],[566,424],[564,425],[560,19],[569,426],[559,19],[987,427],[978,428],[985,429],[979,430],[991,431],[990,432],[982,433],[986,429],[984,434],[983,434],[989,435],[988,436],[998,437],[999,83],[1000,438],[1002,439],[714,439],[710,440],[981,441],[718,442],[1001,440],[708,443],[709,444]],"semanticDiagnosticsPerFile":[[643,[{"start":21,"length":4,"code":7016,"category":1,"messageText":{"messageText":"Could not find a declaration file for module 'pg'. '/Users/sammargolis/projects/apps/OpenScribe/node_modules/.pnpm/pg@8.20.0/node_modules/pg/esm/index.mjs' implicitly has an 'any' type.","category":1,"code":7016,"next":[{"info":{"moduleReference":"pg","mode":99}}]}}]],[644,[{"start":529,"length":9,"code":2353,"category":1,"messageText":"Object literal may only specify known properties, and 'trustHost' does not exist in type 'AuthOptions'."}]],[650,[{"start":596,"length":5,"code":2339,"category":1,"messageText":{"messageText":"Property 'email' does not exist on type '({ name?: string | null | undefined; email?: string | null | undefined; image?: string | null | undefined; } & { id?: string | undefined; }) | { id: string; }'.","category":1,"code":2339,"next":[{"messageText":"Property 'email' does not exist on type '{ id: string; }'.","category":1,"code":2339}]}},{"start":642,"length":4,"code":2339,"category":1,"messageText":{"messageText":"Property 'name' does not exist on type '({ name?: string | null | undefined; email?: string | null | undefined; image?: string | null | undefined; } & { id?: string | undefined; }) | { id: string; }'.","category":1,"code":2339,"next":[{"messageText":"Property 'name' does not exist on type '{ id: string; }'.","category":1,"code":2339}]}}]],[655,[{"start":1186,"length":3,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'string | ArrayBufferView | Stream | Iterable | AsyncIterable'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | Stream | Iterable | AsyncIterable<...>'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":1476,"length":3,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"messageText":"Overload 1 of 4, '(algorithm: CipherGCMTypes, key: CipherKey, iv: BinaryLike, options?: CipherGCMOptions | undefined): CipherGCM', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]},{"messageText":"Overload 2 of 4, '(algorithm: string, key: CipherKey, iv: BinaryLike | null, options?: TransformOptions | undefined): Cipher', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]}]},"relatedInformation":[]},{"start":1565,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}},{"start":1576,"length":14,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}},{"start":2311,"length":3,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"messageText":"Overload 1 of 4, '(algorithm: CipherGCMTypes, key: CipherKey, iv: BinaryLike, options?: CipherGCMOptions | undefined): DecipherGCM', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]},{"messageText":"Overload 2 of 4, '(algorithm: string, key: CipherKey, iv: BinaryLike | null, options?: TransformOptions | undefined): Decipher', gave the following error.","category":1,"code":2772,"next":[{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'CipherKey'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView | KeyObject'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}]}]},"relatedInformation":[]},{"start":2344,"length":7,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":2394,"length":9,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'Buffer' is not assignable to parameter of type 'ArrayBufferView'.","category":1,"code":2345,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}]}]}},{"start":2409,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Buffer & string'.","category":1,"code":2322,"next":[{"messageText":"Type 'Buffer' is not assignable to type 'string'.","category":1,"code":2322}]}},{"start":2436,"length":9,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer & string' is not assignable to type 'Uint8Array'."}}]}]}},{"start":2447,"length":16,"code":2322,"category":1,"messageText":{"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'.","category":1,"code":2322,"next":[{"messageText":"The types of 'slice(...).buffer' are incompatible between these types.","category":1,"code":2200,"next":[{"messageText":"Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.","category":1,"code":2322,"next":[{"messageText":"Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength","category":1,"code":2739,"canonicalHead":{"code":2322,"messageText":"Type 'SharedArrayBuffer' is not assignable to type 'ArrayBuffer'."}}],"canonicalHead":{"code":2322,"messageText":"Type 'Buffer' is not assignable to type 'Uint8Array'."}}]}]}}]],[694,[{"start":4646,"length":9,"messageText":"Expected 4 arguments, but got 3.","category":1,"code":2554,"relatedInformation":[{"start":612,"length":20,"messageText":"An argument for 'recoverable' was not provided.","category":3,"code":6210}]}]],[1011,[{"start":6991,"length":19,"messageText":"Property 'openscribeBackend' does not exist on type 'DesktopAPI | undefined'.","category":1,"code":2339},{"start":17962,"length":12,"code":2345,"category":1,"messageText":{"messageText":"Argument of type 'string | undefined' is not assignable to parameter of type 'SetStateAction'.","category":1,"code":2345,"next":[{"messageText":"Type 'undefined' is not assignable to type 'SetStateAction'.","category":1,"code":2322}]}}]]],"affectedFilesPendingEmit":[646,647,650,651,654,655,656,694,695,696,705,1011,704,1010,697,698,649,644,645,643,648,652,653,691,693,692,503,557,555,553,554,556,668,667,1007,1008,1005,1006,1009,504,505,568,567,1003,1004,558,657,658,659,660,661,666,664,665,663,662,565,563,562,561,566,564,560,569,559,987,978,985,979,991,990,982,986,984,983,989,988,998,999,1000,1002,714,710,981,718,1001,708,709],"version":"5.9.3"} \ No newline at end of file diff --git a/config/db/migrations/001_nextauth_tables.sql b/config/db/migrations/001_nextauth_tables.sql new file mode 100644 index 0000000..20fc2d2 --- /dev/null +++ b/config/db/migrations/001_nextauth_tables.sql @@ -0,0 +1,46 @@ +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT, + email TEXT UNIQUE, + "emailVerified" TIMESTAMPTZ, + image TEXT +); + +CREATE TABLE IF NOT EXISTS accounts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "userId" UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + type TEXT NOT NULL, + provider TEXT NOT NULL, + "providerAccountId" TEXT NOT NULL, + refresh_token TEXT, + access_token TEXT, + expires_at BIGINT, + token_type TEXT, + scope TEXT, + id_token TEXT, + session_state TEXT, + oauth_token_secret TEXT, + oauth_token TEXT +); + +CREATE UNIQUE INDEX IF NOT EXISTS accounts_provider_provider_account_id_key + ON accounts (provider, "providerAccountId"); + +CREATE TABLE IF NOT EXISTS sessions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "sessionToken" TEXT NOT NULL UNIQUE, + "userId" UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + expires TIMESTAMPTZ NOT NULL +); + +CREATE TABLE IF NOT EXISTS verification_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMPTZ NOT NULL, + PRIMARY KEY (identifier, token) +); + +CREATE UNIQUE INDEX IF NOT EXISTS verification_token_token_key + ON verification_token (token); diff --git a/config/db/migrations/002_compliance_tables.sql b/config/db/migrations/002_compliance_tables.sql new file mode 100644 index 0000000..4cf8d18 --- /dev/null +++ b/config/db/migrations/002_compliance_tables.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS user_terms_acceptance ( + id BIGSERIAL PRIMARY KEY, + user_id TEXT NOT NULL, + terms_version TEXT NOT NULL, + accepted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + ip_hash TEXT NOT NULL, + ua_hash TEXT NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_user_terms_acceptance_user_id + ON user_terms_acceptance (user_id, accepted_at DESC); + +CREATE TABLE IF NOT EXISTS auth_events ( + id BIGSERIAL PRIMARY KEY, + user_id TEXT, + event_type TEXT NOT NULL, + provider TEXT, + success BOOLEAN NOT NULL, + ip_hash TEXT NOT NULL, + ua_hash TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_auth_events_created_at + ON auth_events (created_at DESC); diff --git a/config/eslint.config.mjs b/config/eslint.config.mjs index 7d9ab77..9af11f7 100644 --- a/config/eslint.config.mjs +++ b/config/eslint.config.mjs @@ -18,6 +18,7 @@ const ignoredPaths = [ "apps/web/public/**", "apps/web/.next/**", "output/**", + ".pnpm-store/**", ] const nodeFiles = ["config/**/*.{js,mjs,cjs}", "packages/shell/**/*.js", "scripts/**/*.{js,mjs,cjs}"] const nodeGlobals = { @@ -105,9 +106,7 @@ export default tseslint.config( files: nodeFiles, languageOptions: { parserOptions: { - projectService: { - allowDefaultProject: ["scripts/*.js", "scripts/*.mjs", "scripts/*.cjs"], - }, + projectService: false, tsconfigRootDir, }, globals: nodeGlobals, diff --git a/config/tsconfig.test.json b/config/tsconfig.test.json index e8ed26e..c1c52c1 100644 --- a/config/tsconfig.test.json +++ b/config/tsconfig.test.json @@ -21,7 +21,12 @@ "../packages/pipeline/medgemma-scribe/src/**/*.ts", "../packages/llm/src/**/*.ts", "../packages/llm-medgemma/src/**/*.ts", - "../packages/storage/src/**/*.ts" + "../packages/storage/src/**/*.ts", + "../apps/web/src/lib/openemr-client.ts", + "../apps/web/src/lib/__tests__/openemr-client.test.ts", + "../apps/web/src/lib/__tests__/openemr-auth-state.test.ts", + "../apps/web/src/lib/openemr-push-handler.ts", + "../apps/web/src/lib/__tests__/openemr-push-handler.test.ts" ], "exclude": [ "node_modules", diff --git a/docker/web-cloudrun.Dockerfile b/docker/web-cloudrun.Dockerfile new file mode 100644 index 0000000..5e1e28b --- /dev/null +++ b/docker/web-cloudrun.Dockerfile @@ -0,0 +1,41 @@ +FROM node:20-bookworm-slim AS builder + +WORKDIR /app +ENV NEXT_TELEMETRY_DISABLED=1 +ARG NEXT_PUBLIC_SECURE_STORAGE_KEY +ENV NEXT_PUBLIC_SECURE_STORAGE_KEY=${NEXT_PUBLIC_SECURE_STORAGE_KEY} +ARG NEXT_PUBLIC_HIPAA_HOSTED_MODE +ENV NEXT_PUBLIC_HIPAA_HOSTED_MODE=${NEXT_PUBLIC_HIPAA_HOSTED_MODE} +ARG DATABASE_URL +ENV DATABASE_URL=${DATABASE_URL} + +RUN corepack enable + +COPY package.json pnpm-lock.yaml tsconfig.json ./ +COPY config ./config +COPY apps ./apps +COPY packages ./packages +COPY scripts ./scripts +COPY local-only ./local-only + +RUN pnpm install --frozen-lockfile +RUN pnpm build + +FROM node:20-bookworm-slim AS runner + +WORKDIR /app +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN npm install --global pnpm@10.23.0 + +RUN groupadd --system --gid 1001 nodejs \ + && useradd --system --uid 1001 --gid nodejs nextjs + +COPY --from=builder /app ./ + +USER nextjs + +EXPOSE 8080 + +CMD ["sh", "-c", "pnpm start -- -p ${PORT:-8080}"] diff --git a/docker/whisper-cloudrun.Dockerfile b/docker/whisper-cloudrun.Dockerfile new file mode 100644 index 0000000..c5980c2 --- /dev/null +++ b/docker/whisper-cloudrun.Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.11-slim + +WORKDIR /app + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ffmpeg build-essential \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt ./requirements.txt +COPY local-only/openscribe-backend/requirements.txt ./local-backend-requirements.txt +RUN pip install --no-cache-dir -r requirements.txt -r local-backend-requirements.txt + +COPY scripts ./scripts +COPY local-only ./local-only + +EXPOSE 8081 + +CMD ["sh", "-c", "python scripts/whisper_server.py --host 0.0.0.0 --port ${PORT:-8081} --model ${WHISPER_LOCAL_MODEL:-tiny.en} --backend ${WHISPER_LOCAL_BACKEND:-cpp} --gpu"] diff --git a/docs/BRANCH_PROTECTION.md b/docs/BRANCH_PROTECTION.md index e8c42d8..cd38d79 100644 --- a/docs/BRANCH_PROTECTION.md +++ b/docs/BRANCH_PROTECTION.md @@ -2,6 +2,7 @@ ## Protected branch - `main` +- `codex/prod-hipaa` ## Required settings - Pull request required before merge @@ -23,3 +24,5 @@ ## Release policy - Production deploys are allowed only from signed tags `v*` - `main` merges may deploy to non-production environments only +- `codex/prod-hipaa` is the only branch allowed to deploy to production web hosting +- Require `Deploy Web (GCP HIPAA) / deploy` to pass before production promotion diff --git a/docs/GCP_DEPLOY_PLAN.md b/docs/GCP_DEPLOY_PLAN.md new file mode 100644 index 0000000..843ca5e --- /dev/null +++ b/docs/GCP_DEPLOY_PLAN.md @@ -0,0 +1,401 @@ +# OpenScribe GCP Deployment Plan (prod-hipaa) + +## GCP Organization & Billing +- **Org:** `trymentat.com` (ID: `551180838370`) — BAA signed here +- **Billing account:** `01BAE9-727C79-2A06A1` + +## GitHub Repo +- `sammargolis/OpenScribe` (origin remote) +- Workflow triggers on push to `codex/prod-hipaa` + +--- + +## Naming Conventions + +| Variable | Value | +|---|---| +| `GCP_PROJECT_ID` | `openscribe-prod` | +| `GCP_REGION` | `us-central1` | +| `GCP_CLOUD_RUN_SERVICE` | `openscribe-web` | +| `GCP_WHISPER_CLOUD_RUN_SERVICE` | `openscribe-whisper` | +| `GCP_RUNTIME_SERVICE_ACCOUNT` | `openscribe-web-runner@openscribe-prod.iam.gserviceaccount.com` | +| `GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT` | `openscribe-whisper-runner@openscribe-prod.iam.gserviceaccount.com` | +| `GCP_ARTIFACT_REPO` | `openscribe-images` | +| `GCP_DEPLOY_SERVICE_ACCOUNT` | `openscribe-deployer@openscribe-prod.iam.gserviceaccount.com` | + +--- + +## Secret Values — COLLECTED STATUS + +| Secret | Value | Status | +|---|---|---| +| `ANTHROPIC_API_KEY` | `sk-ant-api03-d8kvayVY-YgYPX_...` (from .env.local) | ✅ Have it | +| `AUTH_SECRET` | `9xJFyyBVCstL/6tel/9dfaw02cegWQCXuoKTp0fEIA8=` | ✅ Generated | +| `NEXT_PUBLIC_SECURE_STORAGE_KEY` | `jWky4LpBHyrC/WjtEDr01ajC/misy6IkVfsNYytqFHo=` (from .env.local) | ✅ Have it | +| `GOOGLE_CLIENT_ID` | — | ❌ Needs OAuth setup (browser) | +| `GOOGLE_CLIENT_SECRET` | — | ❌ Needs OAuth setup (browser) | +| `DATABASE_URL` | `postgresql://openscribe_app:PASSWORD@HOST/openscribe` | ❌ After Cloud SQL created | +| `REDIS_URL` | `redis://10.X.X.X:6379` | ❌ After Memorystore created | +| `GCP_WORKLOAD_IDENTITY_PROVIDER` | — | ❌ After WIF setup | + +--- + +## ⚠️ Issues Found in Workflow — Must Resolve + +### 1. DB Migrations run from GitHub Actions runner +The workflow runs `pnpm db:migrate` by fetching `DATABASE_URL` from Secret Manager and running it +directly on the GitHub Actions runner (not inside Cloud Run). This means Cloud SQL needs either: +- **Public IP with authorized networks** — simplest; add `0.0.0.0/0` or a specific CIDR for GitHub IPs +- **Cloud SQL Auth Proxy on the runner** — more secure; add a workflow step + +**Recommendation:** Enable public IP on Cloud SQL and add `--authorized-networks=0.0.0.0/0` during +creation (or restrict to GitHub's IP ranges). For HIPAA stricter posture, use Cloud SQL Auth Proxy. + +### 2. Redis VPC connectivity +The workflow does NOT set `--vpc-connector` on Cloud Run. Memorystore Redis has no public IP, so +Cloud Run can't reach it without a VPC connector. Must either: +- Add `--vpc-connector=openscribe-connector --vpc-egress=private-ranges-only` to both `gcloud run deploy` commands in the workflow, OR +- Use a publicly accessible Redis (e.g., Redis Enterprise Cloud) — not recommended for HIPAA + +**Recommendation:** Update the workflow to add VPC connector flags, and create the VPC connector +in Step 6 below. + +### 3. `NEXT_PUBLIC_SECURE_STORAGE_KEY` not passed to Cloud Build +This `NEXT_PUBLIC_*` variable is baked into the Next.js bundle at build time. The workflow uses +`gcloud builds submit` but doesn't pass this key. It must be provided as a Cloud Build substitution +or build arg. Must update the workflow's `gcloud builds submit` command to add: +``` +--substitutions="_NEXT_PUBLIC_SECURE_STORAGE_KEY=VALUE" +``` +And update `docker/web-cloudrun.Dockerfile` to use `ARG NEXT_PUBLIC_SECURE_STORAGE_KEY` at build time. + +### 4. Deployer SA needs Cloud Build permissions +The workflow uses `gcloud builds submit` (Cloud Build), not local Docker push. The deployer SA needs: +- `roles/cloudbuild.builds.editor` — to submit builds +- The Cloud Build service account (`PROJECT_NUMBER@cloudbuild.gserviceaccount.com`) needs + `roles/artifactregistry.writer` automatically (GCP handles this), but confirm after project creation. + +--- + +## Steps + +### Step 1 — Create project under org + link billing +```bash +gcloud projects create openscribe-prod \ + --name="OpenScribe Production" \ + --organization=551180838370 \ + --account=sam@trymentat.com + +gcloud billing projects link openscribe-prod \ + --billing-account=01BAE9-727C79-2A06A1 \ + --account=sam@trymentat.com +``` + +### Step 2 — Enable required APIs +```bash +gcloud services enable \ + run.googleapis.com \ + cloudbuild.googleapis.com \ + sqladmin.googleapis.com \ + redis.googleapis.com \ + artifactregistry.googleapis.com \ + secretmanager.googleapis.com \ + iam.googleapis.com \ + iamcredentials.googleapis.com \ + cloudresourcemanager.googleapis.com \ + compute.googleapis.com \ + vpcaccess.googleapis.com \ + servicenetworking.googleapis.com \ + logging.googleapis.com \ + --project=openscribe-prod \ + --account=sam@trymentat.com +``` + +### Step 3 — Create Artifact Registry repo +The workflow auto-creates this if missing, but pre-creating is cleaner: +```bash +gcloud artifacts repositories create openscribe-images \ + --repository-format=docker \ + --location=us-central1 \ + --description="OpenScribe production Docker images" \ + --project=openscribe-prod \ + --account=sam@trymentat.com +``` +→ `GCP_ARTIFACT_REPO=openscribe-images` + +### Step 4 — Create service accounts + IAM bindings +```bash +PROJECT=openscribe-prod + +# Runtime SAs +gcloud iam service-accounts create openscribe-web-runner \ + --display-name="OpenScribe Web Runtime" --project=$PROJECT + +gcloud iam service-accounts create openscribe-whisper-runner \ + --display-name="OpenScribe Whisper Runtime" --project=$PROJECT + +# Deploy SA +gcloud iam service-accounts create openscribe-deployer \ + --display-name="OpenScribe GitHub Actions Deployer" --project=$PROJECT + +# Runtime SAs: Secret Manager + Cloud SQL access +for SA in openscribe-web-runner openscribe-whisper-runner; do + gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:${SA}@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/secretmanager.secretAccessor" + + gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:${SA}@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/cloudsql.client" +done + +# Deploy SA: Cloud Build + Artifact Registry + Cloud Run + act as runtime SAs +gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:openscribe-deployer@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/cloudbuild.builds.editor" + +gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:openscribe-deployer@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/artifactregistry.writer" + +gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:openscribe-deployer@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/run.admin" + +gcloud projects add-iam-policy-binding $PROJECT \ + --member="serviceAccount:openscribe-deployer@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/secretmanager.viewer" + +for RUNTIME_SA in openscribe-web-runner openscribe-whisper-runner; do + gcloud iam service-accounts add-iam-policy-binding \ + ${RUNTIME_SA}@${PROJECT}.iam.gserviceaccount.com \ + --member="serviceAccount:openscribe-deployer@${PROJECT}.iam.gserviceaccount.com" \ + --role="roles/iam.serviceAccountUser" \ + --project=$PROJECT +done +``` + +### Step 5 — Create Cloud SQL Postgres 15 ⏱ ~10 min +```bash +PROJECT=openscribe-prod + +gcloud sql instances create openscribe-db \ + --database-version=POSTGRES_15 \ + --tier=db-g1-small \ + --region=us-central1 \ + --storage-type=SSD \ + --storage-size=20GB \ + --storage-auto-increase \ + --backup-start-time=03:00 \ + --enable-point-in-time-recovery \ + --deletion-protection \ + --authorized-networks=0.0.0.0/0 \ + --project=$PROJECT + +gcloud sql databases create openscribe \ + --instance=openscribe-db --project=$PROJECT + +# Choose a strong password and save it +gcloud sql users create openscribe_app \ + --instance=openscribe-db \ + --password=CHOOSE_STRONG_PASSWORD \ + --project=$PROJECT + +# Get the public IP +gcloud sql instances describe openscribe-db \ + --project=$PROJECT \ + --format="value(ipAddresses[0].ipAddress)" +``` +→ `DATABASE_URL=postgresql://openscribe_app:PASSWORD@PUBLIC_IP/openscribe?sslmode=require` + +Note: sslmode=require is important since we're using public IP. + +### Step 6 — Create VPC connector + Memorystore Redis ⏱ ~10 min +```bash +PROJECT=openscribe-prod + +# VPC connector (needed for Cloud Run → Redis) +gcloud compute networks vpc-access connectors create openscribe-connector \ + --region=us-central1 \ + --range=10.8.0.0/28 \ + --project=$PROJECT + +# Redis instance +gcloud redis instances create openscribe-redis \ + --size=1 \ + --region=us-central1 \ + --tier=BASIC \ + --redis-version=redis_7_0 \ + --project=$PROJECT + +# Get Redis IP (run after ~10 min) +gcloud redis instances describe openscribe-redis \ + --region=us-central1 --project=$PROJECT \ + --format="value(host,port)" +``` +→ `REDIS_URL=redis://10.X.X.X:6379` + +### Step 7 — Workload Identity Federation for GitHub Actions +```bash +PROJECT=openscribe-prod +PROJECT_NUMBER=$(gcloud projects describe $PROJECT --format='value(projectNumber)') + +gcloud iam workload-identity-pools create github-pool \ + --location=global \ + --display-name="GitHub Actions Pool" \ + --project=$PROJECT + +gcloud iam workload-identity-pools providers create-oidc github-provider \ + --location=global \ + --workload-identity-pool=github-pool \ + --display-name="GitHub Provider" \ + --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.actor=assertion.actor" \ + --issuer-uri="https://token.actions.githubusercontent.com" \ + --project=$PROJECT + +# Bind deploy SA to sammargolis/OpenScribe repo +gcloud iam service-accounts add-iam-policy-binding \ + openscribe-deployer@${PROJECT}.iam.gserviceaccount.com \ + --role="roles/iam.workloadIdentityUser" \ + --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/sammargolis/OpenScribe" \ + --project=$PROJECT + +# Get the provider resource name +gcloud iam workload-identity-pools providers describe github-provider \ + --location=global \ + --workload-identity-pool=github-pool \ + --project=$PROJECT \ + --format="value(name)" +``` +→ `GCP_WORKLOAD_IDENTITY_PROVIDER=projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/providers/github-provider` + +### Step 8 — Google OAuth ⚠️ Browser required +1. Configure consent screen: + https://console.cloud.google.com/apis/credentials/consent?project=openscribe-prod + - App name: `OpenScribe`, support email: `sam@trymentat.com` + - Scopes: `openid`, `email`, `profile` + +2. Create OAuth 2.0 Client ID: + https://console.cloud.google.com/apis/credentials?project=openscribe-prod + - Type: **Web application**, Name: `OpenScribe Web` + - Authorized redirect URIs: `https:///api/auth/callback/google` + (use a placeholder now; update after Step 10) + - Copy **Client ID** and **Client Secret** + +→ Collects: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` + +### Step 9 — Store all secrets in Secret Manager +```bash +PROJECT=openscribe-prod + +# ANTHROPIC_API_KEY (from .env.local) +echo -n "sk-ant-api03-d8kvayVY-YgYPX_GRiOaeQ1lfd2jMn9z55zv43Q6oz3Atyo_Id1f6Xv8qAejTDGjYaUpyf92inlXm6mxZmjd8A-QR_RuwAA" | \ + gcloud secrets create ANTHROPIC_API_KEY --data-file=- --replication-policy=automatic --project=$PROJECT + +# AUTH_SECRET (generated) +echo -n "9xJFyyBVCstL/6tel/9dfaw02cegWQCXuoKTp0fEIA8=" | \ + gcloud secrets create AUTH_SECRET --data-file=- --replication-policy=automatic --project=$PROJECT + +# GOOGLE_CLIENT_ID (from Step 8) +echo -n "PASTE_VALUE" | \ + gcloud secrets create GOOGLE_CLIENT_ID --data-file=- --replication-policy=automatic --project=$PROJECT + +# GOOGLE_CLIENT_SECRET (from Step 8) +echo -n "PASTE_VALUE" | \ + gcloud secrets create GOOGLE_CLIENT_SECRET --data-file=- --replication-policy=automatic --project=$PROJECT + +# DATABASE_URL (from Step 5 — use public IP) +echo -n "postgresql://openscribe_app:PASSWORD@PUBLIC_IP/openscribe?sslmode=require" | \ + gcloud secrets create DATABASE_URL --data-file=- --replication-policy=automatic --project=$PROJECT + +# REDIS_URL (from Step 6) +echo -n "redis://10.X.X.X:6379" | \ + gcloud secrets create REDIS_URL --data-file=- --replication-policy=automatic --project=$PROJECT +``` + +### Step 10 — Fix workflow issues before first deploy +Before pushing to trigger the workflow, apply these fixes: + +**Fix A:** Add VPC connector to both `gcloud run deploy` commands in +`.github/workflows/deploy-web-gcp-hipaa.yml`: +```yaml +--vpc-connector=openscribe-connector \ +--vpc-egress=private-ranges-only \ +``` + +**Fix B:** Pass `NEXT_PUBLIC_SECURE_STORAGE_KEY` to Cloud Build. Update the +`gcloud builds submit` commands: +```bash +gcloud builds submit \ + --tag "$WEB_IMAGE_URI" \ + -f docker/web-cloudrun.Dockerfile \ + --substitutions="_NEXT_PUBLIC_SECURE_STORAGE_KEY=jWky4LpBHyrC/WjtEDr01ajC/misy6IkVfsNYytqFHo=" \ + . +``` +And update `docker/web-cloudrun.Dockerfile` to declare: +```dockerfile +ARG _NEXT_PUBLIC_SECURE_STORAGE_KEY +ENV NEXT_PUBLIC_SECURE_STORAGE_KEY=$_NEXT_PUBLIC_SECURE_STORAGE_KEY +``` + +### Step 11 — Add GitHub Actions secrets +Go to: https://github.com/sammargolis/OpenScribe/settings/secrets/actions + +| Secret Name | Value | +|---|---| +| `GCP_WORKLOAD_IDENTITY_PROVIDER` | from Step 7 | +| `GCP_DEPLOY_SERVICE_ACCOUNT` | `openscribe-deployer@openscribe-prod.iam.gserviceaccount.com` | +| `GCP_PROJECT_ID` | `openscribe-prod` | +| `GCP_REGION` | `us-central1` | +| `GCP_ARTIFACT_REPO` | `openscribe-images` | +| `GCP_CLOUD_RUN_SERVICE` | `openscribe-web` | +| `GCP_WHISPER_CLOUD_RUN_SERVICE` | `openscribe-whisper` | +| `GCP_RUNTIME_SERVICE_ACCOUNT` | `openscribe-web-runner@openscribe-prod.iam.gserviceaccount.com` | +| `GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT` | `openscribe-whisper-runner@openscribe-prod.iam.gserviceaccount.com` | + +### Step 12 — First deploy +After all above steps + OAuth redirect URI updated: +```bash +git push origin codex/prod-hipaa +``` +Then: +1. Watch GitHub Actions for the deploy +2. Get the web service URL from the workflow output +3. Go back to OAuth console and add the real redirect URI: + `https:///api/auth/callback/google` + +--- + +## Dependency Order + +``` +Step 1 (project + billing) + └─ Step 2 (APIs) + ├─ Step 3 (Artifact Registry) + ├─ Step 4 (Service Accounts + IAM) + ├─ Step 5 (Cloud SQL) ──────────────┐ + ├─ Step 6 (VPC + Redis) ────────────┤ + └─ Step 7 (WIF) [parallel w/ 5+6] │ + │ + Step 8 (OAuth) [browser, parallel ok] + │ + Step 9 (Secrets) ← needs values from 5, 6, 8 + │ + Step 10 (Fix workflow) + │ + Step 11 (GitHub secrets) ← needs WIF from Step 7 + │ + Step 12 (Push → first deploy) + │ + Update OAuth redirect URI with real Cloud Run URL +``` + +--- + +## HIPAA Notes +- All resources under `trymentat.com` org — BAA applies +- Cloud SQL has `--deletion-protection` and PITR enabled +- Enable Data Access Audit Logs post-setup: + IAM & Admin → Audit Logs → enable DATA_READ/DATA_WRITE for Cloud SQL, Secret Manager, Cloud Run +- `--authorized-networks=0.0.0.0/0` on Cloud SQL is pragmatic for migrations but consider + tightening to specific CIDR ranges in steady state diff --git a/docs/HIPAA_EVIDENCE_INDEX.md b/docs/HIPAA_EVIDENCE_INDEX.md new file mode 100644 index 0000000..88ec36e --- /dev/null +++ b/docs/HIPAA_EVIDENCE_INDEX.md @@ -0,0 +1,23 @@ +# HIPAA Evidence Index + +## Ownership +- Security/Compliance owner: `TBD` (required) +- Engineering owner: `TBD` + +## Recurring controls +- Daily: authentication and abuse log review +- Weekly: access review (users, service accounts, elevated roles) +- Monthly: secret rotation verification +- Quarterly: incident response tabletop drill + +## Evidence map +| Control | Evidence | Location | +|---|---|---| +| Auth enforced for PHI APIs | API auth tests + route guards | CI logs + code review | +| Secret-managed credentials only | Secret Manager versions + deploy config | GCP Secret Manager + workflow logs | +| Audit logging retention | Log sink + bucket retention policy | Cloud Logging + Cloud Storage | +| Deployment traceability | Build/deploy runs and image tags | GitHub Actions + Artifact Registry | +| Access governance | IAM policy snapshots | GCP IAM exports | + +## Collection cadence +- Keep exported evidence snapshots monthly and before each major release. diff --git a/docs/HIPAA_GCP_WEB_HOSTING.md b/docs/HIPAA_GCP_WEB_HOSTING.md new file mode 100644 index 0000000..1caf997 --- /dev/null +++ b/docs/HIPAA_GCP_WEB_HOSTING.md @@ -0,0 +1,93 @@ +# HIPAA Web Hosting (Simple GCP Path) + +This is the shortest path to host OpenScribe web on Google Cloud in a HIPAA-oriented production setup. + +## Scope +- Runtime: Cloud Run web + Cloud Run whisper service +- Identity: Google OAuth via Auth.js +- Secrets: Secret Manager only (no in-app key management) +- Audit evidence: Cloud Logging sink to retained Cloud Storage bucket + +## 1. Production branch +```bash +git checkout codex/prod-hipaa +git pull --ff-only +``` + +## 2. Required Secret Manager secrets +Create or update: +- `ANTHROPIC_API_KEY` +- `AUTH_SECRET` +- `GOOGLE_CLIENT_ID` +- `GOOGLE_CLIENT_SECRET` +- `DATABASE_URL` +- `REDIS_URL` + +Example: +```bash +echo -n "value" | gcloud secrets versions add AUTH_SECRET --data-file=- +``` + +## 3. One-time setup + deploy +From repo root: +```bash +PROJECT_ID="your-gcp-project-id" \ +REGION="us-central1" \ +WEB_SERVICE_NAME="openscribe-web-prod" \ +WHISPER_SERVICE_NAME="openscribe-whisper-prod" \ +./scripts/deploy-gcp-hipaa-web.sh +``` + +This deploys: +- `openscribe-whisper-prod` (private, IAM-invoked only) +- `openscribe-web-prod` (public sign-in surface, authenticated PHI endpoints) +- DB migrations from `config/db/migrations/*.sql` before service rollout + +## 4. GitHub Actions deploy (recommended) +Workflow file: `.github/workflows/deploy-web-gcp-hipaa.yml` + +Set repository secrets: +- `GCP_WORKLOAD_IDENTITY_PROVIDER` +- `GCP_DEPLOY_SERVICE_ACCOUNT` +- `GCP_PROJECT_ID` +- `GCP_REGION` +- `GCP_ARTIFACT_REPO` +- `GCP_CLOUD_RUN_SERVICE` +- `GCP_RUNTIME_SERVICE_ACCOUNT` +- `GCP_WHISPER_CLOUD_RUN_SERVICE` +- `GCP_WHISPER_RUNTIME_SERVICE_ACCOUNT` + +Push to `codex/prod-hipaa` to deploy. + +## 5. Hosted-mode behavior +When `HIPAA_HOSTED_MODE=true`: +- Google sign-in is required. +- Terms acceptance is required before PHI actions. +- `/api/settings/api-keys` returns `410` (disabled). +- Transcription is forced to internal whisper service. + +## 6. Audit evidence to retain +- Cloud Run revision/deploy history (web + whisper) +- Cloud Audit Logs export via `openscribe-hipaa-audit-sink` +- CI run logs for each production deployment +- IAM policy bindings for runtime/deploy service accounts +- Secret version history and rotation records + +## 7. Apply Cloud Armor rate limits (required for open signup) +```bash +PROJECT_ID="your-gcp-project-id" \ +BACKEND_SERVICE="your-https-lb-backend-service" \ +./scripts/setup-cloud-armor-rate-limit.sh +``` + +## 8. Minimal release gate +Before each production merge: +- `lint` green +- `typecheck` green +- `test` green +- `no-phi-log-check` green +- `Deploy Web (GCP HIPAA) / deploy` green + +## Notes +- This is a technical hosting baseline, not legal certification. +- Open signup + rate limits only is accepted risk for this launch configuration. diff --git a/docs/superpowers/plans/2026-03-17-openemr-integration.md b/docs/superpowers/plans/2026-03-17-openemr-integration.md new file mode 100644 index 0000000..6862c45 --- /dev/null +++ b/docs/superpowers/plans/2026-03-17-openemr-integration.md @@ -0,0 +1,1228 @@ +# OpenEMR Integration Implementation Plan + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a "Push to OpenEMR" button to the note editor that sends a completed clinical note to an OpenEMR patient chart as a FHIR R4 DocumentReference. + +**Architecture:** A standalone `openemr-client.ts` module owns all FHIR API logic. A pure `openemr-push-handler.ts` owns request validation and delegation logic (testable without Next.js). The Next.js route is a thin wrapper around the handler. The note editor button uses a pure `buildOpenEMRPushPayload` function for payload construction. All trust boundaries are covered by failing tests before any production code is written. + +**TDD Rules (non-negotiable):** +1. Write the failing test first. Run it. Confirm it fails. +2. Write the minimal production code to make it pass. Nothing more. +3. Run the test. Confirm it passes. +4. Commit. Summarize what changed. + +**Trust boundary focus:** Tests specifically cover identity binding (patient ID from input = patient ID sent to FHIR), auth guards (unauthenticated paths never reach OpenEMR), and input validation (malformed inputs are rejected before any OpenEMR call). + +**Tech Stack:** Next.js App Router (TypeScript), native `fetch` (Node 18+), FHIR R4, OpenEMR OAuth2 client_credentials, Node.js built-in test runner (`node:test`) + +--- + +## Spec Reference + +`docs/superpowers/specs/2026-03-16-openemr-integration-design.md` + +--- + +## File Map + +| File | Action | Responsibility | +|---|---|---| +| `apps/web/.env.local.example` | **Modify** | Document the four new env vars | +| `config/tsconfig.test.json` | **Modify** | Add all new testable modules to includes | +| `apps/web/src/lib/openemr-client.ts` | **Create** | Token fetch (with cache + timeout), patient validation, DocumentReference creation | +| `apps/web/src/lib/__tests__/openemr-client.test.ts` | **Create** | Trust boundary tests: auth chain, identity binding, FHIR payload structure | +| `apps/web/src/lib/openemr-push-handler.ts` | **Create** | Pure request validation + delegation logic (no Next.js dependency) | +| `apps/web/src/lib/__tests__/openemr-push-handler.test.ts` | **Create** | Trust boundary tests: input guard, identity binding to client module | +| `apps/web/src/app/api/integrations/openemr/push/route.ts` | **Create** | Thin POST handler: auth guard → delegate to pure handler | +| `packages/ui/src/components/new-encounter-form.tsx` | **Modify** | Add conditional required `patient_id` field | +| `packages/pipeline/render/src/components/note-editor.tsx` | **Modify** | Add "Push to OpenEMR" button, states, error display | + +--- + +## Trust Boundary Map + +``` +Browser (untrusted) + │ + ▼ POST /api/integrations/openemr/push +┌─────────────────────────────────────┐ +│ Next.js Route │ +│ ① requireAuthenticatedUser() │ ← identity check (auth guard) +│ ② parsePushBody(body) │ ← input validation (tested pure) +└─────────────────────────────────────┘ + │ validated { patientId, noteMarkdown, ... } + ▼ +┌─────────────────────────────────────┐ +│ openemr-push-handler.ts │ +│ ③ pushNoteToOpenEMR(params) │ ← identity binding: patientId passes through exactly +└─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ openemr-client.ts │ +│ ④ getAccessToken() │ ← credential boundary: creds never leave server +│ ⑤ validatePatient(token, id) │ ← patient existence check before write +│ ⑥ createDocumentReference(...) │ ← FHIR payload: patient_id bound to subject.reference +└─────────────────────────────────────┘ + │ + ▼ +OpenEMR FHIR API (external) +``` + +Circles ①–⑥ are each covered by at least one failing test before implementation. + +--- + +## Chunk 1: Configuration and Test Infrastructure + +### Task 1: Document env vars and extend test tsconfig + +No production logic. No tests needed. This is build plumbing. + +**Files:** +- Modify: `apps/web/.env.local.example` +- Modify: `config/tsconfig.test.json` + +- [ ] **Step 1: Append to `.env.local.example`** + +```bash +# OpenEMR Integration (optional — enables "Push to OpenEMR" in the note editor) +# Register an OAuth2 client in OpenEMR Admin → System → API Clients +# with scopes: system/DocumentReference.write system/Patient.read +OPENEMR_BASE_URL="" +OPENEMR_CLIENT_ID="" +OPENEMR_CLIENT_SECRET="" +# Set to "true" at BUILD TIME to show the Push to OpenEMR button. +# NEXT_PUBLIC_* vars are inlined by Next.js at build — changing this requires a rebuild. +NEXT_PUBLIC_OPENEMR_ENABLED="false" +``` + +- [ ] **Step 2: Confirm `.env.local` is in `.gitignore`** + +```bash +grep "\.env\.local" /Users/sammargolis/projects/apps/OpenScribe/.gitignore +``` + +Expected: at least one match. If missing, add `.env.local` before continuing. + +- [ ] **Step 3: Add new modules to `config/tsconfig.test.json` includes** + +Add these four entries to the `"include"` array: + +```json +"../apps/web/src/lib/openemr-client.ts", +"../apps/web/src/lib/__tests__/openemr-client.test.ts", +"../apps/web/src/lib/openemr-push-handler.ts", +"../apps/web/src/lib/__tests__/openemr-push-handler.test.ts" +``` + +**Why four specific files, not a glob:** Every other file in `apps/web/src/lib/` imports from `next/server` or `next-auth`, which the NodeNext test compiler cannot resolve. These four are pure Node.js. + +- [ ] **Step 4: Verify existing tests still pass** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm test +``` + +Expected: all existing tests pass, no regressions. + +- [ ] **Step 5: Commit** + +```bash +git add apps/web/.env.local.example config/tsconfig.test.json +git commit -m "build: document OpenEMR env vars and extend test tsconfig" +``` + +**Summary:** No logic changed. Test infrastructure extended to cover the two new testable modules. + +--- + +## Chunk 2: OpenEMR FHIR Client (trust boundary ④⑤⑥) + +### Task 2: Write failing tests for openemr-client + +Write ALL tests before any implementation code exists. Run them. Confirm they fail. + +**Files:** +- Create: `apps/web/src/lib/__tests__/openemr-client.test.ts` + +- [ ] **Step 1: Create the test file** + +```typescript +// apps/web/src/lib/__tests__/openemr-client.test.ts +import assert from "node:assert/strict" +import test from "node:test" +import { + pushNoteToOpenEMR, + isOpenEMRConfigured, + _resetTokenCacheForTesting, +} from "../openemr-client.js" + +// ─── Helpers ──────────────────────────────────────────────────────────────── + +function mockFetch(responses: Array<{ status: number; body: unknown }>) { + let i = 0 + globalThis.fetch = async (_url: string | URL | Request, _opts?: RequestInit): Promise => { + const resp = responses[i++] + if (!resp) throw new Error(`Unexpected fetch call #${i}`) + return { + ok: resp.status >= 200 && resp.status < 300, + status: resp.status, + json: async () => resp.body, + text: async () => JSON.stringify(resp.body), + } as Response + } +} + +const BASE = { + patientId: "42", + noteMarkdown: "# Note\nPatient is well.", + patientName: "Jane Doe", + visitReason: "problem_visit", +} + +process.env.OPENEMR_BASE_URL = "http://localhost:8080" +process.env.OPENEMR_CLIENT_ID = "test-client" +process.env.OPENEMR_CLIENT_SECRET = "test-secret" + +// ─── Configuration boundary ───────────────────────────────────────────────── + +test("isOpenEMRConfigured: returns true when all three vars are set", () => { + assert.equal(isOpenEMRConfigured(), true) +}) + +test("isOpenEMRConfigured: returns false when OPENEMR_BASE_URL is absent", () => { + const saved = process.env.OPENEMR_BASE_URL + delete process.env.OPENEMR_BASE_URL + assert.equal(isOpenEMRConfigured(), false) + process.env.OPENEMR_BASE_URL = saved! +}) + +test("pushNoteToOpenEMR: returns failure when not configured", async () => { + _resetTokenCacheForTesting() + const saved = process.env.OPENEMR_BASE_URL + delete process.env.OPENEMR_BASE_URL + + const result = await pushNoteToOpenEMR(BASE) + + assert.equal(result.success, false) + process.env.OPENEMR_BASE_URL = saved! +}) + +// ─── Auth boundary (trust boundary ④) ────────────────────────────────────── + +test("auth boundary: 401 from token endpoint → auth failure message, no further calls", async () => { + _resetTokenCacheForTesting() + let callCount = 0 + globalThis.fetch = async (): Promise => { + callCount++ + return { ok: false, status: 401, json: async () => ({}), text: async () => "" } as Response + } + + const result = await pushNoteToOpenEMR(BASE) + + assert.equal(result.success, false) + if (!result.success) assert.match(result.error, /authentication failed/i) + assert.equal(callCount, 1, "Must stop after auth failure — no patient or FHIR calls") +}) + +test("auth boundary: token is reused on second call (credential not re-sent)", async () => { + _resetTokenCacheForTesting() + let tokenCalls = 0 + globalThis.fetch = async (url: string | URL | Request, opts?: RequestInit): Promise => { + const u = typeof url === "string" ? url : url.toString() + if (u.includes("/oauth2/")) { + tokenCalls++ + return { ok: true, status: 200, json: async () => ({ access_token: "tok", expires_in: 3600 }), text: async () => "" } as Response + } + if (u.includes("DocumentReference")) { + return { ok: true, status: 201, json: async () => ({ id: "doc-1" }), text: async () => "" } as Response + } + return { ok: true, status: 200, json: async () => ({ id: "42" }), text: async () => "" } as Response + } + + await pushNoteToOpenEMR(BASE) + await pushNoteToOpenEMR(BASE) + + assert.equal(tokenCalls, 1, "Credentials must not be re-sent when token is cached") +}) + +// ─── Patient identity boundary (trust boundary ⑤) ────────────────────────── + +test("patient boundary: 404 from Patient endpoint → not-found message, no FHIR write", async () => { + _resetTokenCacheForTesting() + let fhirWriteCalled = false + globalThis.fetch = async (url: string | URL | Request): Promise => { + const u = typeof url === "string" ? url : url.toString() + if (u.includes("/oauth2/")) return { ok: true, status: 200, json: async () => ({ access_token: "tok", expires_in: 3600 }), text: async () => "" } as Response + if (u.includes("DocumentReference")) { fhirWriteCalled = true; return { ok: true, status: 201, json: async () => ({ id: "x" }), text: async () => "" } as Response } + return { ok: false, status: 404, json: async () => ({}), text: async () => "" } as Response + } + + const result = await pushNoteToOpenEMR(BASE) + + assert.equal(result.success, false) + if (!result.success) assert.match(result.error, /not found in openemr/i) + assert.equal(fhirWriteCalled, false, "Must not write DocumentReference for unknown patient") +}) + +// ─── Identity binding (trust boundary ⑥) ──────────────────────────────────── + +test("identity binding: patientId param is bound to DocumentReference subject.reference exactly", async () => { + _resetTokenCacheForTesting() + let capturedBody: Record | null = null + + globalThis.fetch = async (url: string | URL | Request, opts?: RequestInit): Promise => { + const u = typeof url === "string" ? url : url.toString() + if (u.includes("/oauth2/")) return { ok: true, status: 200, json: async () => ({ access_token: "tok", expires_in: 3600 }), text: async () => "" } as Response + if (u.includes("DocumentReference") && opts?.method === "POST") { + capturedBody = JSON.parse(opts.body as string) + return { ok: true, status: 201, json: async () => ({ id: "doc-99" }), text: async () => "" } as Response + } + return { ok: true, status: 200, json: async () => ({ id: "42" }), text: async () => "" } as Response + } + + const result = await pushNoteToOpenEMR({ ...BASE, patientId: "42" }) + + assert.equal(result.success, true) + assert.ok(capturedBody, "DocumentReference payload must be sent") + // The patient ID from the request must appear verbatim in the FHIR subject reference + assert.deepEqual(capturedBody!.subject, { reference: "Patient/42" }) +}) + +test("identity binding: noteMarkdown is base64-encoded without alteration", async () => { + _resetTokenCacheForTesting() + let capturedAttachment: { contentType: string; data: string } | null = null + + globalThis.fetch = async (url: string | URL | Request, opts?: RequestInit): Promise => { + const u = typeof url === "string" ? url : url.toString() + if (u.includes("/oauth2/")) return { ok: true, status: 200, json: async () => ({ access_token: "tok", expires_in: 3600 }), text: async () => "" } as Response + if (u.includes("DocumentReference") && opts?.method === "POST") { + const body = JSON.parse(opts.body as string) as { content: Array<{ attachment: { contentType: string; data: string } }> } + capturedAttachment = body.content[0].attachment + return { ok: true, status: 201, json: async () => ({ id: "doc-1" }), text: async () => "" } as Response + } + return { ok: true, status: 200, json: async () => ({ id: "42" }), text: async () => "" } as Response + } + + const note = "# Visit Note\n\nChief complaint: headache." + await pushNoteToOpenEMR({ ...BASE, noteMarkdown: note }) + + assert.ok(capturedAttachment) + assert.equal(capturedAttachment!.contentType, "text/markdown") + assert.equal(Buffer.from(capturedAttachment!.data, "base64").toString(), note) +}) + +test("identity binding: FHIR payload includes required category and status fields", async () => { + _resetTokenCacheForTesting() + let capturedBody: Record | null = null + + globalThis.fetch = async (url: string | URL | Request, opts?: RequestInit): Promise => { + const u = typeof url === "string" ? url : url.toString() + if (u.includes("/oauth2/")) return { ok: true, status: 200, json: async () => ({ access_token: "tok", expires_in: 3600 }), text: async () => "" } as Response + if (u.includes("DocumentReference") && opts?.method === "POST") { + capturedBody = JSON.parse(opts.body as string) + return { ok: true, status: 201, json: async () => ({ id: "doc-1" }), text: async () => "" } as Response + } + return { ok: true, status: 200, json: async () => ({ id: "42" }), text: async () => "" } as Response + } + + await pushNoteToOpenEMR(BASE) + + const p = capturedBody! + assert.equal(p.status, "current") + const cat = p.category as Array<{ coding: Array<{ code: string }> }> + assert.equal(cat[0].coding[0].code, "clinical-note") + assert.equal(p.description, BASE.visitReason) +}) + +// ─── Network / timeout boundary ───────────────────────────────────────────── + +test("network boundary: ECONNREFUSED → 'could not reach' message", async () => { + _resetTokenCacheForTesting() + globalThis.fetch = async () => { throw new Error("fetch failed: ECONNREFUSED ::1:8080") } + + const result = await pushNoteToOpenEMR(BASE) + + assert.equal(result.success, false) + if (!result.success) assert.match(result.error, /could not reach openemr/i) +}) + +test("network boundary: timeout (AbortError) → timeout message", async () => { + _resetTokenCacheForTesting() + globalThis.fetch = async () => { + const err = new Error("The operation was aborted") + ;(err as NodeJS.ErrnoException).name = "AbortError" + throw err + } + + const result = await pushNoteToOpenEMR(BASE) + + assert.equal(result.success, false) + if (!result.success) assert.match(result.error, /timed out/i) +}) +``` + +- [ ] **Step 2: Run tests — confirm they ALL fail** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm build:test 2>&1 | grep openemr +``` + +Expected: compile error — `openemr-client.ts` does not exist yet. This is correct. Do not proceed until you see a failure. + +--- + +### Task 3: Implement openemr-client.ts to pass all tests + +Write the minimal implementation that satisfies the tests above. Nothing extra. + +**Files:** +- Create: `apps/web/src/lib/openemr-client.ts` + +- [ ] **Step 1: Create the module** + +```typescript +// apps/web/src/lib/openemr-client.ts + +const FETCH_TIMEOUT_MS = 15_000 + +function fetchWithTimeout(url: string, options: RequestInit = {}): Promise { + const controller = new AbortController() + const id = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS) + return fetch(url, { ...options, signal: controller.signal }).finally(() => clearTimeout(id)) +} + +type TokenCache = { accessToken: string; expiresAt: number } +let tokenCache: TokenCache | null = null + +function getConfig() { + return { + baseUrl: process.env.OPENEMR_BASE_URL?.replace(/\/$/, "") ?? "", + clientId: process.env.OPENEMR_CLIENT_ID ?? "", + clientSecret: process.env.OPENEMR_CLIENT_SECRET ?? "", + } +} + +export function isOpenEMRConfigured(): boolean { + const { baseUrl, clientId, clientSecret } = getConfig() + return Boolean(baseUrl && clientId && clientSecret) +} + +/** Test-only: reset in-process token cache between test cases. */ +export function _resetTokenCacheForTesting(): void { + tokenCache = null +} + +async function getAccessToken(): Promise { + const { baseUrl, clientId, clientSecret } = getConfig() + if (!baseUrl || !clientId || !clientSecret) throw new Error("not_configured") + + const now = Date.now() + if (tokenCache && tokenCache.expiresAt > now + 5 * 60 * 1000) return tokenCache.accessToken + + const res = await fetchWithTimeout(`${baseUrl}/oauth2/default/token`, { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ + grant_type: "client_credentials", + client_id: clientId, + client_secret: clientSecret, + scope: "system/DocumentReference.write system/Patient.read", + }).toString(), + }) + if (!res.ok) throw new Error("auth_failure") + + const data = (await res.json()) as { access_token: string; expires_in: number } + tokenCache = { accessToken: data.access_token, expiresAt: now + data.expires_in * 1000 } + return tokenCache.accessToken +} + +async function validatePatient(token: string, baseUrl: string, patientId: string): Promise { + const res = await fetchWithTimeout(`${baseUrl}/apis/default/fhir/Patient/${patientId}`, { + headers: { Authorization: `Bearer ${token}` }, + }) + if (!res.ok) throw new Error("patient_not_found") +} + +async function createDocumentReference( + token: string, + baseUrl: string, + params: { patientId: string; noteMarkdown: string; patientName: string; visitReason: string } +): Promise { + const resource = { + resourceType: "DocumentReference", + status: "current", + type: { coding: [{ system: "http://loinc.org", code: "34109-9", display: "Note" }] }, + category: [{ + coding: [{ + system: "http://hl7.org/fhir/us/core/CodeSystem/us-core-documentreference-category", + code: "clinical-note", + display: "Clinical Note", + }], + }], + subject: { reference: `Patient/${params.patientId}` }, + date: new Date().toISOString(), + description: params.visitReason, + content: [{ + attachment: { + contentType: "text/markdown", + data: Buffer.from(params.noteMarkdown).toString("base64"), + title: `Clinical Note — ${params.patientName}`, + }, + }], + } + + const res = await fetchWithTimeout(`${baseUrl}/apis/default/fhir/DocumentReference`, { + method: "POST", + headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/fhir+json" }, + body: JSON.stringify(resource), + }) + if (!res.ok) { + const text = await res.text() + throw new Error(`fhir_error:${res.status}:${text.slice(0, 200)}`) + } + + return ((await res.json()) as { id: string }).id +} + +export type PushNoteParams = { + patientId: string + noteMarkdown: string + patientName: string + visitReason: string +} +export type PushNoteResult = { success: true; id: string } | { success: false; error: string } + +export async function pushNoteToOpenEMR(params: PushNoteParams): Promise { + const { baseUrl } = getConfig() + if (!isOpenEMRConfigured()) return { success: false, error: "OpenEMR is not configured." } + + try { + const token = await getAccessToken() + await validatePatient(token, baseUrl, params.patientId) + const id = await createDocumentReference(token, baseUrl, params) + return { success: true, id } + } catch (error) { + const e = error instanceof Error ? error : new Error(String(error)) + + if (e.name === "AbortError") { + return { success: false, error: `OpenEMR push timed out after ${FETCH_TIMEOUT_MS / 1000}s. Check that the server is responding at ${baseUrl}.` } + } + if (e.message === "auth_failure") { + return { success: false, error: "OpenEMR authentication failed. Check OPENEMR_CLIENT_ID and OPENEMR_CLIENT_SECRET." } + } + if (e.message === "patient_not_found") { + return { success: false, error: `Patient ID ${params.patientId} was not found in OpenEMR. Verify the ID and try again.` } + } + if (e.message.includes("fetch failed") || e.message.includes("ECONNREFUSED") || e.message.includes("ENOTFOUND")) { + return { success: false, error: `Could not reach OpenEMR at ${baseUrl}. Check that the server is running.` } + } + if (e.message.startsWith("fhir_error:")) { + return { success: false, error: `OpenEMR push failed: FHIR error ${e.message.split(":")[1]}` } + } + return { success: false, error: `OpenEMR push failed: ${e.message}` } + } +} +``` + +- [ ] **Step 2: Build tests** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm build:test 2>&1 | tail -10 +``` + +Expected: compilation succeeds with no errors. + +- [ ] **Step 3: Run tests — confirm they ALL pass** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && node --test build/tests-dist/web/src/lib/__tests__/openemr-client.test.js 2>&1 +``` + +Expected: all 11 tests pass. If any fail, fix the implementation (not the tests) before continuing. + +- [ ] **Step 4: Commit** + +```bash +git add apps/web/src/lib/openemr-client.ts apps/web/src/lib/__tests__/openemr-client.test.ts +git commit -m "feat(openemr): FHIR client module — 11 trust boundary tests passing" +``` + +**Summary of what changed:** `openemr-client.ts` created. 11 tests pass covering: configuration boundary, auth guard (token not re-sent on cache hit, stops on 401), patient identity boundary (no FHIR write on 404), identity binding (patientId → subject.reference, noteMarkdown → base64 attachment, category + status required), network/timeout errors. No other files changed. + +--- + +## Chunk 3: Route Handler (trust boundary ①②③) + +### Task 4: Write failing tests for the pure push handler + +The Next.js route imports from `next/server` and cannot be compiled by the test runner. Extract all testable logic into `openemr-push-handler.ts` (pure Node.js). The route becomes a 10-line wrapper. Write tests first. + +**Trust boundaries tested here:** +- ① Auth identity check fires before any call to `pushNoteToOpenEMR` +- ② Input validation: missing `patientId` or `noteMarkdown` → rejected before any OpenEMR call +- ③ Identity binding: request body fields pass through to `pushNoteToOpenEMR` without transformation + +**Files:** +- Create: `apps/web/src/lib/__tests__/openemr-push-handler.test.ts` + +- [ ] **Step 1: Create the test file** + +```typescript +// apps/web/src/lib/__tests__/openemr-push-handler.test.ts +import assert from "node:assert/strict" +import test from "node:test" +import { handlePushRequest } from "../openemr-push-handler.js" +import type { PushNoteResult } from "../openemr-client.js" + +// ─── Minimal mock for pushNoteToOpenEMR ───────────────────────────────────── + +type PushFn = (params: { + patientId: string + noteMarkdown: string + patientName: string + visitReason: string +}) => Promise + +const successPush: PushFn = async () => ({ success: true, id: "doc-1" }) +const failPush: PushFn = async () => ({ success: false, error: "auth failed" }) + +// ─── Auth boundary (trust boundary ①) ────────────────────────────────────── + +test("auth boundary: unauthenticated request returns 401 without calling pushFn", async () => { + let pushCalled = false + const trackingPush: PushFn = async (p) => { pushCalled = true; return successPush(p) } + + const result = await handlePushRequest( + { isAuthenticated: false }, + { patientId: "42", noteMarkdown: "note", patientName: "Jane", visitReason: "visit" }, + trackingPush + ) + + assert.equal(result.status, 401) + assert.equal(pushCalled, false, "pushNoteToOpenEMR must not be called for unauthenticated requests") +}) + +test("auth boundary: authenticated request proceeds past auth check", async () => { + const result = await handlePushRequest( + { isAuthenticated: true }, + { patientId: "42", noteMarkdown: "note", patientName: "Jane", visitReason: "visit" }, + successPush + ) + + assert.equal(result.status, 200) +}) + +// ─── Input validation (trust boundary ②) ──────────────────────────────────── + +test("input guard: missing patientId returns 400 without calling pushFn", async () => { + let pushCalled = false + const trackingPush: PushFn = async (p) => { pushCalled = true; return successPush(p) } + + const result = await handlePushRequest( + { isAuthenticated: true }, + { patientId: "", noteMarkdown: "note", patientName: "Jane", visitReason: "visit" }, + trackingPush + ) + + assert.equal(result.status, 400) + assert.equal(pushCalled, false, "pushNoteToOpenEMR must not be called with missing patientId") +}) + +test("input guard: missing noteMarkdown returns 400 without calling pushFn", async () => { + let pushCalled = false + const trackingPush: PushFn = async (p) => { pushCalled = true; return successPush(p) } + + const result = await handlePushRequest( + { isAuthenticated: true }, + { patientId: "42", noteMarkdown: "", patientName: "Jane", visitReason: "visit" }, + trackingPush + ) + + assert.equal(result.status, 400) + assert.equal(pushCalled, false, "pushNoteToOpenEMR must not be called with empty noteMarkdown") +}) + +test("input guard: null body returns 400 without calling pushFn", async () => { + let pushCalled = false + const trackingPush: PushFn = async (p) => { pushCalled = true; return successPush(p) } + + const result = await handlePushRequest( + { isAuthenticated: true }, + null, + trackingPush + ) + + assert.equal(result.status, 400) + assert.equal(pushCalled, false) +}) + +// ─── Identity binding (trust boundary ③) ──────────────────────────────────── + +test("identity binding: patientId from request body passes to pushFn unchanged", async () => { + let capturedParams: Parameters[0] | null = null + const capturingPush: PushFn = async (p) => { capturedParams = p; return { success: true, id: "x" } } + + await handlePushRequest( + { isAuthenticated: true }, + { patientId: "patient-42", noteMarkdown: "note text", patientName: "Jane Doe", visitReason: "consult" }, + capturingPush + ) + + assert.ok(capturedParams) + assert.equal(capturedParams!.patientId, "patient-42") + assert.equal(capturedParams!.noteMarkdown, "note text") + assert.equal(capturedParams!.patientName, "Jane Doe") + assert.equal(capturedParams!.visitReason, "consult") +}) + +// ─── Response shape ────────────────────────────────────────────────────────── + +test("response: success from pushFn → status 200 with id", async () => { + const result = await handlePushRequest( + { isAuthenticated: true }, + { patientId: "42", noteMarkdown: "note", patientName: "Jane", visitReason: "visit" }, + async () => ({ success: true, id: "doc-99" }) + ) + + assert.equal(result.status, 200) + assert.deepEqual(result.json, { success: true, id: "doc-99" }) +}) + +test("response: failure from pushFn → status 500 with error", async () => { + const result = await handlePushRequest( + { isAuthenticated: true }, + { patientId: "42", noteMarkdown: "note", patientName: "Jane", visitReason: "visit" }, + async () => ({ success: false, error: "Patient not found" }) + ) + + assert.equal(result.status, 500) + assert.deepEqual(result.json, { success: false, error: "Patient not found" }) +}) +``` + +- [ ] **Step 2: Run tests — confirm they fail** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm build:test 2>&1 | grep push-handler +``` + +Expected: compile error — `openemr-push-handler.ts` does not exist yet. Correct. Do not proceed until confirmed. + +--- + +### Task 5: Implement openemr-push-handler.ts and the API route + +Write the minimal code to pass the handler tests, then wrap it in a route. + +**Files:** +- Create: `apps/web/src/lib/openemr-push-handler.ts` +- Create: `apps/web/src/app/api/integrations/openemr/push/route.ts` + +- [ ] **Step 1: Create the pure handler** + +```typescript +// apps/web/src/lib/openemr-push-handler.ts +import type { PushNoteParams, PushNoteResult } from "./openemr-client.js" + +type AuthContext = { isAuthenticated: boolean } +type PushFn = (params: PushNoteParams) => Promise +type HandlerResult = { status: number; json: unknown } + +export async function handlePushRequest( + auth: AuthContext, + body: unknown, + push: PushFn +): Promise { + if (!auth.isAuthenticated) { + return { status: 401, json: { success: false, error: "Unauthorized" } } + } + + if (!body || typeof body !== "object") { + return { status: 400, json: { success: false, error: "Invalid request body" } } + } + + const b = body as Record + const patientId = typeof b.patientId === "string" ? b.patientId.trim() : "" + const noteMarkdown = typeof b.noteMarkdown === "string" ? b.noteMarkdown.trim() : "" + + if (!patientId || !noteMarkdown) { + return { status: 400, json: { success: false, error: "patientId and noteMarkdown are required" } } + } + + const result = await push({ + patientId, + noteMarkdown, + patientName: typeof b.patientName === "string" ? b.patientName : "", + visitReason: typeof b.visitReason === "string" ? b.visitReason : "", + }) + + return { status: result.success ? 200 : 500, json: result } +} +``` + +- [ ] **Step 2: Build and run handler tests — confirm they all pass** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm build:test 2>&1 | tail -5 && node --test build/tests-dist/web/src/lib/__tests__/openemr-push-handler.test.js +``` + +Expected: all 8 tests pass. If any fail, fix the handler before continuing. + +- [ ] **Step 3: Create the thin Next.js route wrapper** + +```typescript +// apps/web/src/app/api/integrations/openemr/push/route.ts +import { NextRequest, NextResponse } from "next/server" +import { requireAuthenticatedUser } from "@/lib/auth-guard" +import { pushNoteToOpenEMR } from "@/lib/openemr-client" +import { handlePushRequest } from "@/lib/openemr-push-handler" + +export async function POST(req: NextRequest) { + const auth = await requireAuthenticatedUser() + let body: unknown + try { body = await req.json() } catch { body = null } + + const result = await handlePushRequest( + { isAuthenticated: auth.ok }, + body, + pushNoteToOpenEMR + ) + + if (!auth.ok && !result) return auth.response + return NextResponse.json(result.json, { status: result.status }) +} +``` + +- [ ] **Step 4: TypeScript check on the route** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && npx tsc --noEmit --project apps/web/tsconfig.json 2>&1 | grep -i openemr +``` + +Expected: no errors. + +- [ ] **Step 5: Commit** + +```bash +git add apps/web/src/lib/openemr-push-handler.ts apps/web/src/lib/__tests__/openemr-push-handler.test.ts apps/web/src/app/api/integrations/openemr/push/route.ts +git commit -m "feat(openemr): push handler + API route — 8 trust boundary tests passing" +``` + +**Summary of what changed:** `openemr-push-handler.ts` created with `handlePushRequest` — a pure function that takes auth context, body, and push function as arguments. 8 tests pass covering: auth guard stops unauthenticated calls, input guard stops missing fields, identity binding passes params unchanged. Route is a thin wrapper delegating to the handler. + +--- + +## Chunk 4: Form and UI + +### Task 6: New encounter form — conditional patient_id field + +The form validation logic is simple enough to test through manual verification. The key trust boundary — "OPENEMR_ENABLED=true AND blank patientId blocks submission" — is best verified by running the app. There is no extractable pure logic that would benefit from a unit test beyond what's already covered in the handler tests. + +**Files:** +- Modify: `packages/ui/src/components/new-encounter-form.tsx` + +- [ ] **Step 1: Run the app and verify current behavior (baseline)** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm dev & +``` + +Open `http://localhost:3001`. Click "New Encounter". Confirm: no patient ID field exists today. This is the before state. + +Kill the server: `kill %1` + +- [ ] **Step 2: Write the minimal change** + +Replace `new-encounter-form.tsx` with: + +```typescript +"use client" + +import type React from "react" +import { useState } from "react" +import { Button } from "@ui/lib/ui/button" +import { Input } from "@ui/lib/ui/input" +import { Label } from "@ui/lib/ui/label" +import { Mic } from "lucide-react" + +interface NewEncounterFormProps { + onStart: (data: { patient_name: string; patient_id: string; visit_reason: string }) => void + onCancel: () => void +} + +const VISIT_TYPE_OPTIONS = [ + { label: "History & Physical", value: "history_physical" }, + { label: "Problem Visit", value: "problem_visit" }, + { label: "Consult Note", value: "consult_note" }, +] + +// Build-time constant — inlined by Next.js webpack. Changing requires a rebuild. +// Intentionally duplicated from note-editor.tsx (both are build-time constants in +// separate packages; a shared constant would require a new cross-package export for +// a single boolean — not worth the abstraction). +const OPENEMR_ENABLED = process.env.NEXT_PUBLIC_OPENEMR_ENABLED === "true" + +export function NewEncounterForm({ onStart, onCancel }: NewEncounterFormProps) { + const [patientName, setPatientName] = useState("") + const [patientId, setPatientId] = useState("") + const [visitType, setVisitType] = useState(VISIT_TYPE_OPTIONS[0]?.value ?? "") + const [patientIdError, setPatientIdError] = useState("") + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault() + if (OPENEMR_ENABLED && !patientId.trim()) { + setPatientIdError("OpenEMR Patient ID is required") + return + } + onStart({ patient_name: patientName, patient_id: patientId, visit_reason: visitType }) + } + + return ( +
+

New Interview

+ +
+
+ + setPatientName(e.target.value)} + className="rounded-xl border-border bg-secondary" + /> +
+ + {OPENEMR_ENABLED && ( +
+ + { + setPatientId(e.target.value) + if (e.target.value.trim()) setPatientIdError("") + }} + className="rounded-xl border-border bg-secondary" + aria-describedby={patientIdError ? "patient-id-error" : undefined} + /> + {patientIdError && ( +

+ {patientIdError} +

+ )} +
+ )} + +
+ + +
+ +
+ + +
+
+
+ ) +} +``` + +- [ ] **Step 3: Start dev server and verify manually** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm dev & +``` + +**Without flag set (current `.env.local`):** Open `http://localhost:3001`, click "New Encounter". +- ✓ No patient ID field appears +- ✓ Form submits as before + +**With flag set:** Add `NEXT_PUBLIC_OPENEMR_ENABLED=true` to `.env.local`, kill server, restart. +- ✓ "OpenEMR Patient ID" field appears +- ✓ Submitting blank shows: "OpenEMR Patient ID is required" +- ✓ Entering a value clears the error +- ✓ Form submits with the entered ID + +Kill server: `kill %1` + +- [ ] **Step 4: Commit** + +```bash +git add packages/ui/src/components/new-encounter-form.tsx +git commit -m "feat(openemr): conditional required patient ID field in encounter form" +``` + +**Summary of what changed:** `new-encounter-form.tsx` now conditionally renders an "OpenEMR Patient ID" input when `NEXT_PUBLIC_OPENEMR_ENABLED=true`. Field is required — blank submission shows inline error. When flag is false, form is unchanged. `patient_id` now passes the entered value (was hardcoded `""`). + +--- + +### Task 7: Note editor — Push to OpenEMR button + +**Files:** +- Modify: `packages/pipeline/render/src/components/note-editor.tsx` + +- [ ] **Step 1: Add `Upload` to the lucide-react import (line 9)** + +```typescript +import { Save, Copy, Download, Check, AlertTriangle, Send, X, MessageSquare, Loader2, Upload } from "lucide-react" +``` + +- [ ] **Step 2: Add state declarations after the OpenClaw state block (after line 67)** + +```typescript +type OpenEMRPushState = "idle" | "pushing" | "success" | "failed" +// Build-time constant. See comment in new-encounter-form.tsx. +const OPENEMR_ENABLED = process.env.NEXT_PUBLIC_OPENEMR_ENABLED === "true" + +const [openEMRPushState, setOpenEMRPushState] = useState("idle") +const [openEMRError, setOpenEMRError] = useState("") +``` + +- [ ] **Step 3: Reset push state when encounter changes** + +In the existing `useEffect` on `[encounter.id, encounter.note_text]`, add: + +```typescript +setOpenEMRPushState("idle") +setOpenEMRError("") +``` + +- [ ] **Step 4: Replace `handleNoteChange` with error-dismissing version** + +The existing function (around line 99): + +```typescript +const handleNoteChange = (value: string) => { + setNoteMarkdown(value) + setHasChanges(true) +} +``` + +Replace with: + +```typescript +const handleNoteChange = (value: string) => { + setNoteMarkdown(value) + setHasChanges(true) + if (openEMRPushState === "failed") { + setOpenEMRPushState("idle") + setOpenEMRError("") + } +} +``` + +- [ ] **Step 5: Add the push handler after `handleExport`** + +```typescript +const handlePushToOpenEMR = async () => { + if (!noteMarkdown.trim() || !encounter.patient_id) return + setOpenEMRPushState("pushing") + setOpenEMRError("") + + try { + const res = await fetch("/api/integrations/openemr/push", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + encounterId: encounter.id, + patientId: encounter.patient_id, + noteMarkdown, + patientName: encounter.patient_name ?? "", + visitReason: encounter.visit_reason ?? "", + }), + }) + const result = (await res.json()) as { success: boolean; id?: string; error?: string } + + if (result.success) { + setOpenEMRPushState("success") + setTimeout(() => setOpenEMRPushState("idle"), 3000) + } else { + setOpenEMRError(result.error ?? "OpenEMR push failed.") + setOpenEMRPushState("failed") + } + } catch { + setOpenEMRError("Could not reach the OpenEMR push endpoint. Check your network connection.") + setOpenEMRPushState("failed") + } +} +``` + +- [ ] **Step 6: Add button to toolbar (after OpenClaw button block, before Save button)** + +```tsx +{activeTab === "note" && OPENEMR_ENABLED && ( + +)} +``` + +- [ ] **Step 7: Add error display (after the OpenClaw error block)** + +```tsx +{openEMRError && openEMRPushState === "failed" && ( +
+ + {openEMRError} +
+)} +``` + +- [ ] **Step 8: TypeScript check** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && npx tsc --noEmit --project apps/web/tsconfig.json 2>&1 | head -20 +``` + +Expected: no errors. + +- [ ] **Step 9: Verify manually (with `NEXT_PUBLIC_OPENEMR_ENABLED=true` in `.env.local`)** + +Start dev server: +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm dev & +``` + +- ✓ Button appears in toolbar when flag set +- ✓ Button disabled when note is empty +- ✓ Button disabled when `patient_id` is empty (old encounters) +- ✓ Push in-flight: spinner + "Pushing..." text, button disabled +- ✓ Success: checkmark + "Pushed to OpenEMR", resets to idle after 3s +- ✓ Failure: red error banner below editor +- ✓ Editing note while failed: error banner clears + +Kill server: `kill %1` + +- [ ] **Step 10: Commit** + +```bash +git add packages/pipeline/render/src/components/note-editor.tsx +git commit -m "feat(openemr): Push to OpenEMR button with full state machine" +``` + +**Summary of what changed:** `note-editor.tsx` has a new "Push to OpenEMR" button gated on `NEXT_PUBLIC_OPENEMR_ENABLED`. State machine: idle → pushing → success/failed. Error banner clears on note edit. Button disabled when note empty, patient_id empty, or push in flight. All OpenClaw behavior unchanged. + +--- + +## Chunk 5: End-to-End Verification + +### Task 8: Smoke test against local OpenEMR + +**Prerequisite:** Ask the developer to add values to `apps/web/.env.local` before this step: +``` +OPENEMR_BASE_URL=http://localhost:8080 +OPENEMR_CLIENT_ID= +OPENEMR_CLIENT_SECRET= +NEXT_PUBLIC_OPENEMR_ENABLED=true +``` + +- [ ] **Step 1: Start OpenEMR** + +```bash +cd /Users/sammargolis/openemr-docker && docker compose up -d +``` + +Wait ~30 seconds, then verify FHIR is up: +```bash +curl -s http://localhost:8080/apis/default/fhir/metadata | python3 -m json.tool | head -5 +``` + +Expected: FHIR CapabilityStatement JSON. + +- [ ] **Step 2: Run the full test suite (no regressions)** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm test +``` + +Expected: all tests pass including the 19 new OpenEMR tests. + +- [ ] **Step 3: Start OpenScribe** + +```bash +cd /Users/sammargolis/projects/apps/OpenScribe && pnpm dev:local +``` + +- [ ] **Step 4: Create a test patient in OpenEMR** + +Open `http://localhost:8080`, log in as `admin` / `adminpass`. Create a test patient. Note their numeric patient ID (visible in the URL after navigating to their chart, e.g. `/patient_dashboard/index/pid/1`). + +- [ ] **Step 5: Create an encounter and push the note** + +1. Open `http://localhost:3001` +2. Click "New Encounter", enter the patient ID from Step 4 +3. Record a short encounter, wait for note generation +4. Click "Push to OpenEMR" +5. Verify button shows "Pushed to OpenEMR" ✓ + +- [ ] **Step 6: Verify DocumentReference in OpenEMR via FHIR API** + +```bash +TOKEN=$(curl -s -X POST http://localhost:8080/oauth2/default/token \ + -d "grant_type=client_credentials&client_id=&client_secret=&scope=system/DocumentReference.read" \ + | python3 -c "import json,sys; print(json.load(sys.stdin)['access_token'])") + +curl -s "http://localhost:8080/apis/default/fhir/DocumentReference?subject=Patient/" \ + -H "Authorization: Bearer $TOKEN" | python3 -m json.tool | grep '"id"' +``` + +Expected: a DocumentReference entry with an `"id"` field. + +- [ ] **Step 7: Test failure case** + +In an existing encounter, temporarily enter a non-existent patient ID (e.g. `99999`), click "Push to OpenEMR". Verify the red error banner reads "Patient ID 99999 was not found in OpenEMR." + +- [ ] **Step 8: Final commit** + +```bash +git add . +git commit -m "feat(openemr): integration verified end-to-end against local OpenEMR" +``` diff --git a/docs/superpowers/specs/2026-03-16-openemr-integration-design.md b/docs/superpowers/specs/2026-03-16-openemr-integration-design.md new file mode 100644 index 0000000..0220292 --- /dev/null +++ b/docs/superpowers/specs/2026-03-16-openemr-integration-design.md @@ -0,0 +1,252 @@ +# OpenEMR Integration Design + +**Date:** 2026-03-16 +**Status:** Approved +**Scope:** Push-only, web app (`apps/web`), per-clinic credentials, FHIR R4 DocumentReference + +--- + +## Overview + +Enable clinicians using OpenScribe's web app to push a completed, reviewed clinical note directly into an OpenEMR patient chart as a FHIR R4 DocumentReference. The integration is additive — it does not replace or affect the existing OpenClaw demo path. + +--- + +## Requirements + +- A clinician records an encounter, reviews the generated note, and clicks "Push to OpenEMR" to send it to the patient's chart. +- The OpenEMR patient must be identified by their OpenEMR patient ID, entered at the start of the encounter. +- Authentication uses a single per-clinic OAuth2 client credential pair configured by a clinic admin — no per-user login. +- The integration is silently inactive when `OPENEMR_BASE_URL` is not set, so existing deployments are unaffected. +- The OpenClaw integration coexists unchanged. + +--- + +## Out of Scope + +- Patient search or auto-matching by name +- Pulling patient or prior-note context from OpenEMR into OpenScribe +- Bidirectional sync +- Desktop (Electron) support +- Retry logic (clinician retries manually on failure) +- Extending the HIPAA audit log for push events (future work) + +--- + +## Prerequisites (Manual — Clinic Admin) + +Before the integration can be used, a clinic admin must register an OAuth2 client in OpenEMR: + +1. Navigate to `Admin → System → API Clients` in OpenEMR. +2. Create a new client with scopes: `system/DocumentReference.write system/Patient.read`. +3. Record the generated **Client ID** and **Client Secret**. +4. Add the following to `apps/web/.env.local`: + +``` +OPENEMR_BASE_URL=http://localhost:8080 +OPENEMR_CLIENT_ID= +OPENEMR_CLIENT_SECRET= +``` + +--- + +## Configuration + +### Server-side env vars (`apps/web/.env.local`) + +| Variable | Required | Description | +|---|---|---| +| `OPENEMR_BASE_URL` | Yes (to enable) | Base URL of the OpenEMR instance, e.g. `http://localhost:8080` | +| `OPENEMR_CLIENT_ID` | Yes (to enable) | OAuth2 client ID registered in OpenEMR | +| `OPENEMR_CLIENT_SECRET` | Yes (to enable) | OAuth2 client secret | + +These are server-side only. They are never sent to the browser. + +### Public feature flag + +`NEXT_PUBLIC_OPENEMR_ENABLED` is a **separate, explicitly set build-time env var** in `apps/web/.env.local`: + +``` +NEXT_PUBLIC_OPENEMR_ENABLED=true +``` + +`NEXT_PUBLIC_*` variables are inlined at build time by Next.js. They cannot be derived at runtime from server-only vars like `OPENEMR_BASE_URL` in Cloud Run or Docker deployments where env vars are injected at container start, not build time. Admins must set this flag explicitly alongside the server vars. + +This flag controls conditional rendering of the "Push to OpenEMR" button in the client-side note editor. Add it to `apps/web/.env.local.example` with a commented explanation. + +--- + +## Data Model Change + +**File:** `packages/ui/src/components/new-encounter-form.tsx` + +`patient_id` is promoted from an optional field (previously hardcoded to `""`) to a **required** field with form validation, **only when `NEXT_PUBLIC_OPENEMR_ENABLED === "true"`**. When the flag is false, the field is not shown and `patient_id` remains `""` as before — preserving the existing workflow for non-OpenEMR deployments. + +When shown: +- Input label: "OpenEMR Patient ID" +- Placeholder: "Enter OpenEMR patient ID" +- Validation: non-empty string; inline error message if submitted blank +- No format validation (OpenEMR patient IDs are numeric strings but format enforcement is deferred) + +No changes to the `Encounter` type in `packages/storage/src/types.ts` — `patient_id: string` already exists. + +--- + +## API Route + +**File:** `apps/web/src/app/api/integrations/openemr/push/route.ts` + +### Request + +`POST /api/integrations/openemr/push` + +```ts +{ + encounterId: string // OpenScribe encounter ID (for error context) + patientId: string // OpenEMR patient ID + noteMarkdown: string // Reviewed clinical note text + patientName: string // For DocumentReference title + visitReason: string // For DocumentReference description +} +``` + +### Response + +Success: +```ts +{ success: true, id: string } // FHIR DocumentReference resource ID +``` + +Failure: +```ts +{ success: false, error: string } +``` + +### Implementation Steps + +**Step 0 — Authentication guard** + +Call `requireAuthenticatedUser()` (already used by existing API routes in this codebase) before any OpenEMR calls. Return HTTP 401 if the caller does not have a valid OpenScribe session. This prevents unauthenticated requests from triggering PHI writes into OpenEMR using the clinic's credentials. + +**Step 1 — OAuth2 token (client_credentials)** + +``` +POST {OPENEMR_BASE_URL}/oauth2/default/token +Content-Type: application/x-www-form-urlencoded + +grant_type=client_credentials +&client_id={OPENEMR_CLIENT_ID} +&client_secret={OPENEMR_CLIENT_SECRET} +&scope=system/DocumentReference.write system/Patient.read +``` + +Token is cached in module-level memory with the expiry timestamp minus a 5-minute buffer. On each request, if the cached token is still valid it is reused; otherwise a new one is fetched. No Redis or file I/O required. + +**Note on serverless:** Module memory does not persist between invocations in serverless runtimes (Vercel, Cloud Run with `min-instances=0`). In those environments the cache is a no-op and a new token is fetched on every push request. This is acceptable for MVP — the token endpoint round-trip adds ~100–300ms latency and is not rate-limited under normal clinical usage. If this becomes a bottleneck, migrate to a shared cache (e.g., Redis/Cloud Memorystore). The primary deployment target for this integration is self-hosted/local where module memory persists. + +**Step 2 — Patient validation** + +``` +GET {OPENEMR_BASE_URL}/apis/default/fhir/Patient/{patientId} +Authorization: Bearer {token} +``` + +If the response is not HTTP 200, abort and return a patient-not-found error. This prevents creating a DocumentReference linked to a non-existent patient. + +**Step 3 — Create DocumentReference** + +``` +POST {OPENEMR_BASE_URL}/apis/default/fhir/DocumentReference +Authorization: Bearer {token} +Content-Type: application/fhir+json + +{ + "resourceType": "DocumentReference", + "status": "current", + "type": { + "coding": [{ + "system": "http://loinc.org", + "code": "34109-9", + "display": "Note" + }] + }, + "category": [{ + "coding": [{ + "system": "http://hl7.org/fhir/us/core/CodeSystem/us-core-documentreference-category", + "code": "clinical-note", + "display": "Clinical Note" + }] + }], + "subject": { "reference": "Patient/{patientId}" }, + "date": "", + "description": "{visitReason}", + "content": [{ + "attachment": { + "contentType": "text/markdown", + "data": "", + "title": "Clinical Note — {patientName}" + } + }] +} +``` + +`category` is required by US Core DocumentReference profile and necessary for OpenEMR to route the document correctly. Omitting it causes a 422 rejection. + +Return the created resource's `id` on success. + +--- + +## UI — Note Editor Button + +**File:** `packages/pipeline/render/src/components/note-editor.tsx` + +A "Push to OpenEMR" button is added to the existing toolbar row alongside the copy, download, and "Send to OpenClaw" controls. It is conditionally rendered only when `NEXT_PUBLIC_OPENEMR_ENABLED === "true"`. + +### Button states + +| State | Label | Icon | +|---|---|---| +| Idle | "Push to OpenEMR" | `Upload` (lucide) | +| Pushing | "Pushing..." | `Loader2` spinning | +| Success | "Pushed to OpenEMR" | `Check` (resets to idle after 3s) | + +### Disabled conditions + +The button is disabled when: +- Note markdown is empty +- `encounter.patient_id` is empty +- A push is already in flight + +### Error display + +On failure, an inline error message appears below the editor using the same styling as the existing OpenClaw error display (`border-destructive/30 bg-destructive/10 text-destructive`). The error dismisses when the clinician edits the note or clicks away. + +--- + +## Error Messages + +| Condition | User-facing message | +|---|---| +| OpenEMR unreachable | `Could not reach OpenEMR at {OPENEMR_BASE_URL}. Check that the server is running.` | +| Patient not found | `Patient ID {patientId} was not found in OpenEMR. Verify the ID and try again.` | +| Auth failure | `OpenEMR authentication failed. Check OPENEMR_CLIENT_ID and OPENEMR_CLIENT_SECRET.` | +| Unexpected server error | `OpenEMR push failed: {error message from server}` | + +--- + +## File Changelist + +| File | Change | +|---|---| +| `apps/web/.env.local` | Add `OPENEMR_BASE_URL`, `OPENEMR_CLIENT_ID`, `OPENEMR_CLIENT_SECRET`, `NEXT_PUBLIC_OPENEMR_ENABLED` | +| `apps/web/.env.local.example` | Document the four new vars with placeholder values only (never real credentials) | +| `apps/web/next.config.mjs` | No change needed — `NEXT_PUBLIC_OPENEMR_ENABLED` is set directly in `.env.local` | +| `apps/web/src/app/api/integrations/openemr/push/route.ts` | New — push API route | +| `packages/ui/src/components/new-encounter-form.tsx` | Require `patient_id` field | +| `packages/pipeline/render/src/components/note-editor.tsx` | Add "Push to OpenEMR" button and state | + +--- + +## OpenEMR Docker Reference + +For local development, the OpenEMR instance is at `http://localhost:8080` via `/Users/sammargolis/openemr-docker/docker-compose.yml`. Default admin credentials: `admin` / `adminpass`. The OAuth2 client must be registered through the admin UI before first use. diff --git a/local-only/cloud-sql-proxy b/local-only/cloud-sql-proxy new file mode 100755 index 0000000..7401017 Binary files /dev/null and b/local-only/cloud-sql-proxy differ diff --git a/output/compliance-evidence/2026-03-16T13:49:40Z/encryption-posture-snapshot.txt b/output/compliance-evidence/2026-03-16T13:49:40Z/encryption-posture-snapshot.txt new file mode 100644 index 0000000..49cba36 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:49:40Z/encryption-posture-snapshot.txt @@ -0,0 +1,24 @@ +timestamp_utc: 2026-03-16T13:49:40Z +project: openscribe-prod + +== Cloud SQL openscribe-db == +name: openscribe-db +region: us-central1 +settings: + ipConfiguration: + ipv4Enabled: true + message: Configuring authorized network or using CloudSQL auth proxy or language + connectors is a prerequisite for connecting to Public IP. Please refer to the + documentation for more details https://cloud.google.com/sql/docs/mysql/authorize-networks. + requireSsl: false + serverCaMode: GOOGLE_MANAGED_INTERNAL_CA + serverCertificateRotationMode: SERVER_CERTIFICATE_ROTATION_MODE_UNSPECIFIED + sslMode: ALLOW_UNENCRYPTED_AND_ENCRYPTED + +== Redis openscribe-redis == +name: projects/openscribe-prod/locations/us-central1/instances/openscribe-redis +transitEncryptionMode: DISABLED + +== Artifact Registry openscribe-images == +format: DOCKER +name: projects/openscribe-prod/locations/us-central1/repositories/openscribe-images diff --git a/output/compliance-evidence/2026-03-16T13:49:40Z/kms-keyrings-and-keys.txt b/output/compliance-evidence/2026-03-16T13:49:40Z/kms-keyrings-and-keys.txt new file mode 100644 index 0000000..ecb8f50 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:49:40Z/kms-keyrings-and-keys.txt @@ -0,0 +1,18 @@ +timestamp_utc: 2026-03-16T13:49:40Z +project: openscribe-prod + +== us-central1 key rings == +NAME CREATE_TIME +openscribe-hipaa 2026-03-16T13:46:57.994841546Z + +== us-central1 keys (openscribe-hipaa) == +NAME PURPOSE PRIMARY_STATE PRIMARY_ALGORITHM ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED GOOGLE_SYMMETRIC_ENCRYPTION 7776000s 2026-06-14T13:46:58Z + +== us-east1 key rings == +NAME CREATE_TIME +openscribe-hipaa 2026-03-16T13:47:00.375500780Z + +== us-east1 keys (openscribe-hipaa) == +NAME PURPOSE PRIMARY_STATE PRIMARY_ALGORITHM ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED GOOGLE_SYMMETRIC_ENCRYPTION 7776000s 2026-06-14T13:47:00Z diff --git a/output/compliance-evidence/2026-03-16T13:49:40Z/scc-services-status.txt b/output/compliance-evidence/2026-03-16T13:49:40Z/scc-services-status.txt new file mode 100644 index 0000000..91bbf1d --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:49:40Z/scc-services-status.txt @@ -0,0 +1,31 @@ +timestamp_utc: 2026-03-16T13:49:40Z +project: openscribe-prod +note: SCC legacy sources endpoint is deprecated; using Security Center Services state instead. + +== SCC services list == +NAME INTENDED_ENABLEMENT_STATE SERVICE_ENABLEMENT_STATE +EVENT_THREAT_DETECTION ENABLED +WEB_SECURITY_SCANNER INHERITED +CLOUD_RUN_THREAT_DETECTION INHERITED +CONTAINER_THREAT_DETECTION INHERITED +VM_THREAT_DETECTION INHERITED +EC2_VULNERABILITY_ASSESSMENT INHERITED +AGENT_ENGINE_THREAT_DETECTION INHERITED +VM_MANAGER INHERITED +VM_THREAT_DETECTION_AWS INHERITED +AZURE_VULNERABILITY_ASSESSMENT INHERITED +NOTEBOOK_SECURITY_SCANNER INHERITED +GCE_VULNERABILITY_ASSESSMENT INHERITED +ARTIFACT_GUARD INHERITED +SECURITY_HEALTH_ANALYTICS ENABLED +ARTIFACT_ANALYSIS INHERITED + +== SHA service == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/security-health-analytics + +== ETD service == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/event-threat-detection diff --git a/output/compliance-evidence/2026-03-16T13:56:15Z/kms-status.txt b/output/compliance-evidence/2026-03-16T13:56:15Z/kms-status.txt new file mode 100644 index 0000000..ec72f2e --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:56:15Z/kms-status.txt @@ -0,0 +1,19 @@ +timestamp_utc: 2026-03-16T13:56:15Z +project: openscribe-prod +organization: 551180838370 + +== key rings us-central1 == +NAME CREATE_TIME +openscribe-hipaa 2026-03-16T13:46:57.994841546Z + +== keys us-central1 openscribe-hipaa == +NAME PURPOSE PRIMARY_STATE ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED 7776000s 2026-06-14T13:46:58Z + +== key rings us-east1 == +NAME CREATE_TIME +openscribe-hipaa 2026-03-16T13:47:00.375500780Z + +== keys us-east1 openscribe-hipaa == +NAME PURPOSE PRIMARY_STATE ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED 7776000s 2026-06-14T13:47:00Z diff --git a/output/compliance-evidence/2026-03-16T13:56:15Z/org-iam-security-roles.txt b/output/compliance-evidence/2026-03-16T13:56:15Z/org-iam-security-roles.txt new file mode 100644 index 0000000..e5fff24 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:56:15Z/org-iam-security-roles.txt @@ -0,0 +1,12 @@ +timestamp_utc: 2026-03-16T13:56:15Z +organization: 551180838370 + +== org IAM roles for sam@trymentat.com == +roles/orgpolicy.policyAdmin +roles/resourcemanager.organizationAdmin +roles/securitycenter.admin +roles/securitycenter.sourcesAdmin +roles/securitycentermanagement.admin +roles/securitycentermanagement.securityCenterServicesEditor +roles/securitycentermanagement.securityCenterServicesViewer +roles/securitycentermanagement.settingsEditor diff --git a/output/compliance-evidence/2026-03-16T13:56:15Z/scc-status.txt b/output/compliance-evidence/2026-03-16T13:56:15Z/scc-status.txt new file mode 100644 index 0000000..09f62b4 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T13:56:15Z/scc-status.txt @@ -0,0 +1,50 @@ +timestamp_utc: 2026-03-16T13:56:15Z +organization: 551180838370 +project: openscribe-prod + +== SCC services at org scope == +NAME INTENDED_ENABLEMENT_STATE SERVICE_ENABLEMENT_STATE +ARTIFACT_GUARD INHERITED +CLOUD_RUN_THREAT_DETECTION INHERITED +EC2_VULNERABILITY_ASSESSMENT INHERITED +VM_THREAT_DETECTION INHERITED +NOTEBOOK_SECURITY_SCANNER INHERITED +WEB_SECURITY_SCANNER INHERITED +SECURITY_HEALTH_ANALYTICS ENABLED +GCE_VULNERABILITY_ASSESSMENT INHERITED +AGENT_ENGINE_THREAT_DETECTION INHERITED +ARTIFACT_ANALYSIS INHERITED +AZURE_VULNERABILITY_ASSESSMENT INHERITED +VM_THREAT_DETECTION_AWS INHERITED +EVENT_THREAT_DETECTION ENABLED +VM_MANAGER INHERITED +CONTAINER_THREAT_DETECTION INHERITED + +== SCC SHA org == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: organizations/551180838370/locations/global/securityCenterServices/security-health-analytics + +== SCC ETD org == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: organizations/551180838370/locations/global/securityCenterServices/event-threat-detection + +== SCC SHA project == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/security-health-analytics + +== SCC ETD project == +effectiveEnablementState: DISABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/event-threat-detection + +== Legacy sources endpoint check == +{ + "error": { + "code": 400, + "message": "Security Command Center Legacy has been permanently disabled as of June 7, 2021. Migrate to Security Command Center's Standard tier or Premium tier to maintain access to Security Command Center. See https://cloud.google.com/security-command-center/docs/quickstart-security-command-center for more info.", + "status": "INVALID_ARGUMENT" + } +} diff --git a/output/compliance-evidence/2026-03-16T14:41:52Z/01-kms.txt b/output/compliance-evidence/2026-03-16T14:41:52Z/01-kms.txt new file mode 100644 index 0000000..df1d365 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:41:52Z/01-kms.txt @@ -0,0 +1,9 @@ +timestamp_utc: 2026-03-16T14:41:52Z +project: openscribe-prod +organization: 551180838370 + +== KMS key rings and keys == +NAME CREATE_TIME +openscribe-hipaa 2026-03-16T13:46:57.994841546Z +NAME PURPOSE PRIMARY_STATE ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED 7776000s 2026-06-14T13:46:58Z diff --git a/output/compliance-evidence/2026-03-16T14:41:52Z/02-scc-services.txt b/output/compliance-evidence/2026-03-16T14:41:52Z/02-scc-services.txt new file mode 100644 index 0000000..6e26a7f --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:41:52Z/02-scc-services.txt @@ -0,0 +1,16 @@ +timestamp_utc: 2026-03-16T14:41:52Z +== SCC org services == +effectiveEnablementState: ENABLED +intendedEnablementState: ENABLED +name: organizations/551180838370/locations/global/securityCenterServices/security-health-analytics +effectiveEnablementState: ENABLED +intendedEnablementState: ENABLED +name: organizations/551180838370/locations/global/securityCenterServices/event-threat-detection + +== SCC project services == +effectiveEnablementState: ENABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/security-health-analytics +effectiveEnablementState: ENABLED +intendedEnablementState: ENABLED +name: projects/706903146695/locations/global/securityCenterServices/event-threat-detection diff --git a/output/compliance-evidence/2026-03-16T14:41:52Z/03-runtime-security.txt b/output/compliance-evidence/2026-03-16T14:41:52Z/03-runtime-security.txt new file mode 100644 index 0000000..d73ccf0 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:41:52Z/03-runtime-security.txt @@ -0,0 +1,73 @@ +timestamp_utc: 2026-03-16T14:41:52Z +== Cloud SQL hardening == +name: openscribe-db +settings: + connectorEnforcement: REQUIRED + ipConfiguration: + ipv4Enabled: true + sslMode: ENCRYPTED_ONLY + +== Redis secure instance == +authEnabled: true +customerManagedKey: projects/openscribe-prod/locations/us-central1/keyRings/openscribe-hipaa/cryptoKeys/openscribe-app-cmek +host: 10.119.66.124 +name: projects/openscribe-prod/locations/us-central1/instances/openscribe-redis-secure +port: 6378 +state: READY +tier: STANDARD_HA +transitEncryptionMode: SERVER_AUTHENTICATION + +== Cloud Run web revision using latest REDIS_URL secret == +spec: + template: + spec: + containers: + - env: + - name: NODE_ENV + value: production + - name: HIPAA_HOSTED_MODE + value: 'true' + - name: NEXT_PUBLIC_HIPAA_HOSTED_MODE + value: 'true' + - name: NEXTAUTH_URL + value: https://openscribe-web-c7tayewpaq-uc.a.run.app + - name: TRANSCRIPTION_PROVIDER + value: whisper_local + - name: WHISPER_LOCAL_URL + value: https://openscribe-whisper-c7tayewpaq-uc.a.run.app/v1/audio/transcriptions + - name: WHISPER_LOCAL_AUTH_TYPE + value: identity_token + - name: ANTHROPIC_API_KEY + valueFrom: + secretKeyRef: + key: latest + name: ANTHROPIC_API_KEY + - name: AUTH_SECRET + valueFrom: + secretKeyRef: + key: latest + name: AUTH_SECRET + - name: GOOGLE_CLIENT_ID + valueFrom: + secretKeyRef: + key: latest + name: GOOGLE_CLIENT_ID + - name: GOOGLE_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: latest + name: GOOGLE_CLIENT_SECRET + - name: DATABASE_URL + valueFrom: + secretKeyRef: + key: latest + name: DATABASE_URL + - name: REDIS_URL + valueFrom: + secretKeyRef: + key: latest + name: REDIS_URL + - name: REDIS_ROLLOUT_AT + value: 20260316T144055Z +status: + latestReadyRevisionName: openscribe-web-00012-6gq diff --git a/output/compliance-evidence/2026-03-16T14:52:20Z/01-scc-enabled.txt b/output/compliance-evidence/2026-03-16T14:52:20Z/01-scc-enabled.txt new file mode 100644 index 0000000..9049c67 --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:52:20Z/01-scc-enabled.txt @@ -0,0 +1,6 @@ +timestamp_utc: 2026-03-16T14:52:20Z +== SCC org + project states == +organizations/551180838370/locations/global/securityCenterServices/security-health-analytics ENABLED ENABLED +organizations/551180838370/locations/global/securityCenterServices/event-threat-detection ENABLED ENABLED +projects/706903146695/locations/global/securityCenterServices/security-health-analytics ENABLED ENABLED +projects/706903146695/locations/global/securityCenterServices/event-threat-detection ENABLED ENABLED diff --git a/output/compliance-evidence/2026-03-16T14:52:20Z/02-kms-redis.txt b/output/compliance-evidence/2026-03-16T14:52:20Z/02-kms-redis.txt new file mode 100644 index 0000000..5eaa9cd --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:52:20Z/02-kms-redis.txt @@ -0,0 +1,12 @@ +timestamp_utc: 2026-03-16T14:52:20Z +== KMS and Redis secure == +NAME PURPOSE PRIMARY_STATE ROTATION_PERIOD NEXT_ROTATION_TIME +openscribe-app-cmek ENCRYPT_DECRYPT ENABLED 7776000s 2026-06-14T13:46:58Z +authEnabled: true +customerManagedKey: projects/openscribe-prod/locations/us-central1/keyRings/openscribe-hipaa/cryptoKeys/openscribe-app-cmek +host: 10.119.66.124 +name: projects/openscribe-prod/locations/us-central1/instances/openscribe-redis-secure +port: 6378 +state: READY +tier: STANDARD_HA +transitEncryptionMode: SERVER_AUTHENTICATION diff --git a/output/compliance-evidence/2026-03-16T14:52:20Z/03-cloudsql-web-rollout.txt b/output/compliance-evidence/2026-03-16T14:52:20Z/03-cloudsql-web-rollout.txt new file mode 100644 index 0000000..e3e2b5e --- /dev/null +++ b/output/compliance-evidence/2026-03-16T14:52:20Z/03-cloudsql-web-rollout.txt @@ -0,0 +1,75 @@ +timestamp_utc: 2026-03-16T14:52:20Z +== Cloud SQL and rollout status == +name: openscribe-db +settings: + connectorEnforcement: REQUIRED + ipConfiguration: + ipv4Enabled: true + message: Configuring authorized network or using CloudSQL auth proxy or language + connectors is a prerequisite for connecting to Public IP. Please refer to the + documentation for more details https://cloud.google.com/sql/docs/mysql/authorize-networks. + privateNetwork: projects/openscribe-prod/global/networks/default + requireSsl: false + serverCaMode: GOOGLE_MANAGED_INTERNAL_CA + serverCertificateRotationMode: SERVER_CERTIFICATE_ROTATION_MODE_UNSPECIFIED + sslMode: ENCRYPTED_ONLY +state: RUNNABLE + +NAME TYPE STATUS START END MESSAGE +58d2b8ab-1c56-44d5-836b-955b00000032 UPDATE RUNNING 2026-03-16T14:43:43.804+00:00 T +9c606ab4-9406-4689-9e43-6b6d00000032 UPDATE DONE 2026-03-16T14:34:48.054+00:00 2026-03-16T14:35:09.285+00:00 +6bad7781-bb0b-4401-aa17-230f00000032 BACKUP_VOLUME DONE 2026-03-16T03:13:18.268+00:00 2026-03-16T03:14:08.946+00:00 + +spec: + template: + spec: + containers: + - env: + - name: NODE_ENV + value: production + - name: HIPAA_HOSTED_MODE + value: 'true' + - name: NEXT_PUBLIC_HIPAA_HOSTED_MODE + value: 'true' + - name: NEXTAUTH_URL + value: https://openscribe-web-c7tayewpaq-uc.a.run.app + - name: TRANSCRIPTION_PROVIDER + value: whisper_local + - name: WHISPER_LOCAL_URL + value: https://openscribe-whisper-c7tayewpaq-uc.a.run.app/v1/audio/transcriptions + - name: WHISPER_LOCAL_AUTH_TYPE + value: identity_token + - name: ANTHROPIC_API_KEY + valueFrom: + secretKeyRef: + key: latest + name: ANTHROPIC_API_KEY + - name: AUTH_SECRET + valueFrom: + secretKeyRef: + key: latest + name: AUTH_SECRET + - name: GOOGLE_CLIENT_ID + valueFrom: + secretKeyRef: + key: latest + name: GOOGLE_CLIENT_ID + - name: GOOGLE_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: latest + name: GOOGLE_CLIENT_SECRET + - name: DATABASE_URL + valueFrom: + secretKeyRef: + key: latest + name: DATABASE_URL + - name: REDIS_URL + valueFrom: + secretKeyRef: + key: latest + name: REDIS_URL + - name: REDIS_ROLLOUT_AT + value: 20260316T144055Z +status: + latestReadyRevisionName: openscribe-web-00012-6gq diff --git a/package.json b/package.json index 3182941..1779d42 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "test:e2e:real": "pnpm build:test && node --test build/tests-dist/pipeline/eval/src/tests/e2e-real-api.test.js", "test:api": "pnpm build:test && node --test build/tests-dist/pipeline/eval/src/tests/api-simple.test.js", "test:no-phi-logs": "node scripts/check-no-phi-logs.mjs", - "test:llm": "pnpm build:test && find build/tests-dist/llm/src/__tests__ -name \"*.test.js\" -print0 | xargs -0 node --test", + "test:llm": "pnpm build:test && find build/tests-dist/packages/llm/src/__tests__ -name \"*.test.js\" -print0 | xargs -0 node --test", "test:note": "pnpm build:test && find build/tests-dist/pipeline/note-core/src/__tests__ -name \"*.test.js\" -print0 | xargs -0 node --test", "build:desktop": "node scripts/build-desktop.mjs current", "build:desktop:all": "node scripts/build-desktop.mjs all", @@ -49,10 +49,13 @@ "test:e2e:desktop:signing": "node scripts/e2e/verify-signing.mjs", "download:ollama": "bash local-only/openscribe-backend/scripts/download-ollama.sh", "medgemma:scribe": "node scripts/medgemma-scribe.mjs", - "medscribe:local": ". .venv-med/bin/activate && python scripts/local_medscribe.py" + "medscribe:local": ". .venv-med/bin/activate && python scripts/local_medscribe.py", + "db:migrate": "node scripts/run-db-migrations.mjs", + "openemr:ensure-patient": "bash scripts/openemr-ensure-patient.sh" }, "dependencies": { "@anthropic-ai/sdk": "^0.71.2", + "@auth/pg-adapter": "^1.11.1", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "1.2.2", "@radix-ui/react-alert-dialog": "1.1.4", @@ -90,16 +93,19 @@ "embla-carousel-react": "8.5.1", "get-port": "5.1.1", "input-otp": "1.4.1", + "ioredis": "^5.10.0", "lucide-react": "^0.454.0", "next": "16.1.5", + "next-auth": "^4.24.13", "next-themes": "^0.4.6", + "pg": "^8.20.0", + "posthog-node": "^4.18.0", "react": "19.2.0", "react-day-picker": "9.8.0", "react-dom": "19.2.0", "react-hook-form": "^7.60.0", "react-resizable-panels": "^2.1.7", "recharts": "2.15.4", - "posthog-node": "^4.18.0", "sonner": "^1.7.4", "swr": "latest", "tailwind-merge": "^2.5.5", @@ -189,4 +195,17 @@ } }, "packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b" + , + "pnpm": { + "overrides": { + "@isaacs/brace-expansion": "^5.0.1", + "axios": "^1.13.5", + "flatted": "^3.4.2", + "minimatch@3.1.2": "^3.1.4", + "minimatch@5.1.6": "^5.1.8", + "minimatch@9.0.5": "^9.0.7", + "minimatch@10.1.1": "^10.2.3", + "tar": "^7.5.12" + } + } } diff --git a/packages/pipeline/assemble/src/session-store.ts b/packages/pipeline/assemble/src/session-store.ts index 350aaa9..c8b0411 100644 --- a/packages/pipeline/assemble/src/session-store.ts +++ b/packages/pipeline/assemble/src/session-store.ts @@ -18,6 +18,7 @@ export interface TranscriptionEvent { interface SessionRecord { id: string + ownerUserId?: string segments: Map stitchedText: string status: TranscriptionStatus @@ -99,11 +100,12 @@ class TranscriptionSessionStore { } } - getSession(sessionId: string): SessionRecord { + getSession(sessionId: string, ownerUserId?: string): SessionRecord { let session = this.sessions.get(sessionId) if (!session) { session = { id: sessionId, + ownerUserId, segments: new Map(), stitchedText: "", status: "recording", @@ -112,12 +114,16 @@ class TranscriptionSessionStore { this.sessions.set(sessionId, session) this.sessionTimestamps.set(sessionId, Date.now()) console.log(`[SessionStore] Created new session: ${sessionId}. Total sessions: ${this.sessions.size}`) + } else if (ownerUserId && session.ownerUserId && session.ownerUserId !== ownerUserId) { + throw new Error("Unauthorized session access") + } else if (ownerUserId && !session.ownerUserId) { + session.ownerUserId = ownerUserId } return session } - subscribe(sessionId: string, listener: (event: TranscriptionEvent) => void): () => void { - const session = this.getSession(sessionId) + subscribe(sessionId: string, listener: (event: TranscriptionEvent) => void, ownerUserId?: string): () => void { + const session = this.getSession(sessionId, ownerUserId) session.listeners.add(listener) console.log(`[SessionStore] Subscriber added to session ${sessionId}. Total listeners: ${session.listeners.size}`) @@ -148,8 +154,8 @@ class TranscriptionSessionStore { }) } - addSegment(sessionId: string, segment: Omit & { transcript: string }) { - const session = this.getSession(sessionId) + addSegment(sessionId: string, segment: Omit & { transcript: string }, ownerUserId?: string) { + const session = this.getSession(sessionId, ownerUserId) session.segments.set(segment.seqNo, segment) const orderedSegments = Array.from(session.segments.values()).sort((a, b) => a.seqNo - b.seqNo) @@ -175,8 +181,8 @@ class TranscriptionSessionStore { }) } - setStatus(sessionId: string, status: TranscriptionStatus) { - const session = this.getSession(sessionId) + setStatus(sessionId: string, status: TranscriptionStatus, ownerUserId?: string) { + const session = this.getSession(sessionId, ownerUserId) session.status = status this.emit(session, { event: "status", @@ -189,8 +195,8 @@ class TranscriptionSessionStore { }) } - setFinalTranscript(sessionId: string, transcript: string) { - const session = this.getSession(sessionId) + setFinalTranscript(sessionId: string, transcript: string, ownerUserId?: string) { + const session = this.getSession(sessionId, ownerUserId) session.finalTranscript = transcript session.status = "completed" this.sessionTimestamps.set(sessionId, Date.now()) // Update timestamp on completion @@ -204,8 +210,8 @@ class TranscriptionSessionStore { }) } - emitError(sessionId: string, error: PipelineError | Error | unknown) { - const session = this.getSession(sessionId) + emitError(sessionId: string, error: PipelineError | Error | unknown, ownerUserId?: string) { + const session = this.getSession(sessionId, ownerUserId) session.status = "error" const normalizedError = toPipelineError(error, { code: "assembly_error", @@ -223,6 +229,13 @@ class TranscriptionSessionStore { }, }) } + + isSessionOwner(sessionId: string, userId: string): boolean { + const session = this.sessions.get(sessionId) + if (!session) return false + if (!session.ownerUserId) return false + return session.ownerUserId === userId + } } declare global { diff --git a/packages/pipeline/render/src/components/note-editor.tsx b/packages/pipeline/render/src/components/note-editor.tsx index 48f3f57..19349c7 100644 --- a/packages/pipeline/render/src/components/note-editor.tsx +++ b/packages/pipeline/render/src/components/note-editor.tsx @@ -6,7 +6,7 @@ import { Button } from "@ui/lib/ui/button" import { Textarea } from "@ui/lib/ui/textarea" import { Badge } from "@ui/lib/ui/badge" import { ScrollArea } from "@ui/lib/ui/scroll-area" -import { Save, Copy, Download, Check, AlertTriangle, Send, X, MessageSquare, Loader2 } from "lucide-react" +import { Save, Copy, Download, Check, AlertTriangle, Send, X, MessageSquare, Loader2, Upload } from "lucide-react" import { format } from "date-fns" import { cn } from "@ui/lib/utils" @@ -21,8 +21,47 @@ interface NoteEditorProps { onSave: (noteText: string) => void } +// Note: this constant is intentionally duplicated from apps/web where +// NEXT_PUBLIC_* vars are inlined at build time. This package can't import +// from apps/web, and the duplication is minimal and explicit. +const OPENEMR_ENABLED = process.env.NEXT_PUBLIC_OPENEMR_ENABLED === "true" + type TabType = "note" | "transcript" type OpenClawInitState = "idle" | "sending" | "sent" | "failed" +type OpenEMRPushState = "idle" | "pushing" | "success" | "failed" +type OpenEMRPreflight = { + configured: boolean + auth_ok: boolean + patient_id_valid: boolean + patient_resolvable: boolean + note_ok: boolean + can_push: boolean + document_verified: boolean | null + blockers: Array<{ code: string; message: string }> + token_state: { + has_token: boolean + source: "persisted" | "env" | "none" + last_refresh_attempt: string | null + last_refresh_error: string | null + } +} +type OpenEMRPushResponse = + | { + success: true + id: string + uploadedAt: string + verifiedPreview: string + verifiedLength: number + openEMRDocumentUrl: string | null + } + | { success: false; error?: string; code?: string } +type OpenEMRAuthSetupResponse = + | { + success: true + message: string + mode: "user" | "service" + } + | { success: false; error?: string; code?: string } type OpenClawPayload = { source: "openscribe" @@ -57,6 +96,17 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { const [copied, setCopied] = useState(false) const [saved, setSaved] = useState(false) + const [openEMRPushState, setOpenEMRPushState] = useState("idle") + const [openEMRError, setOpenEMRError] = useState("") + const [openEMRPreflight, setOpenEMRPreflight] = useState(null) + const [openEMRPreflightLoading, setOpenEMRPreflightLoading] = useState(false) + const [openEMRPreflightError, setOpenEMRPreflightError] = useState("") + const [openEMRAuthSetupState, setOpenEMRAuthSetupState] = useState<"idle" | "setting_up" | "failed" | "done">("idle") + const [openEMRAuthSetupMessage, setOpenEMRAuthSetupMessage] = useState("") + const [openEMRPushResult, setOpenEMRPushResult] = useState | null>( + null, + ) + const [openClawAvailable, setOpenClawAvailable] = useState(false) const [openClawPanelOpen, setOpenClawPanelOpen] = useState(false) const [openClawInitState, setOpenClawInitState] = useState("idle") @@ -77,6 +127,14 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { setOpenClawMessages([]) setOpenClawInput("") setOpenClawSending(false) + setOpenEMRPushState("idle") + setOpenEMRError("") + setOpenEMRPreflight(null) + setOpenEMRPreflightLoading(false) + setOpenEMRPreflightError("") + setOpenEMRAuthSetupState("idle") + setOpenEMRAuthSetupMessage("") + setOpenEMRPushResult(null) }, [encounter.id, encounter.note_text]) useEffect(() => { @@ -100,6 +158,13 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { setNoteMarkdown(value) setHasChanges(true) setSaved(false) + if (openEMRPushState === "failed" || openEMRPushState === "success") { + setOpenEMRPushState("idle") + setOpenEMRError("") + } + if (openEMRPushResult) { + setOpenEMRPushResult(null) + } } const handleSave = () => { @@ -248,16 +313,7 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { } const buildInitialHandoffMessage = (): string => { - const payload: OpenClawPayload = { - source: "openscribe", - encounterId: encounter.id, - patientName: encounter.patient_name || "", - patientId: encounter.patient_id || "", - visitReason: encounter.visit_reason || "", - noteMarkdown, - transcript: encounter.transcript_text || "", - requestedAction: "openemr_apply_note", - } + const payload = buildOpenClawPayload() return [ "You are receiving a structured handoff from OpenScribe.", @@ -280,6 +336,111 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { ].join("\n") } + const buildOpenClawPayload = (): OpenClawPayload => { + return { + source: "openscribe", + encounterId: encounter.id, + patientName: encounter.patient_name || "", + patientId: encounter.patient_id || "", + visitReason: encounter.visit_reason || "", + noteMarkdown, + transcript: encounter.transcript_text || "", + requestedAction: "openemr_apply_note", + } + } + + const runOpenEMRPreflight = async (documentId?: string) => { + if (!OPENEMR_ENABLED) return + setOpenEMRPreflightLoading(true) + setOpenEMRPreflightError("") + try { + const params = new URLSearchParams({ + patientId: encounter.patient_id || "", + noteMarkdown, + }) + params.set("_ts", String(Date.now())) + if (documentId) params.set("documentId", documentId) + const resp = await fetch(`/api/integrations/openemr/status?${params.toString()}`, { cache: "no-store" }) + const data = (await resp.json()) as OpenEMRPreflight + setOpenEMRPreflight(data) + } catch (err) { + setOpenEMRPreflightError(err instanceof Error ? err.message : "Failed to run OpenEMR preflight.") + } finally { + setOpenEMRPreflightLoading(false) + } + } + + useEffect(() => { + if (!OPENEMR_ENABLED || activeTab !== "note") return + const timer = setTimeout(() => { + void runOpenEMRPreflight(openEMRPushResult?.id) + }, 350) + return () => clearTimeout(timer) + }, [activeTab, encounter.patient_id, noteMarkdown, openEMRPushResult?.id]) + + const handleVerifyOpenEMRUpload = async () => { + if (!openEMRPushResult?.id) return + await runOpenEMRPreflight(openEMRPushResult.id) + } + + const handlePushToOpenEMR = async () => { + if (!openEMRPreflight?.can_push) { + setOpenEMRPushState("failed") + const firstBlocker = openEMRPreflight?.blockers?.[0]?.message + setOpenEMRError(firstBlocker || "OpenEMR preflight checks are failing. Resolve blockers and retry.") + return + } + setOpenEMRPushState("pushing") + setOpenEMRError("") + try { + const resp = await fetch("/api/integrations/openemr/push", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + encounterId: encounter.id, + patientId: encounter.patient_id || "", + noteMarkdown, + patientName: encounter.patient_name || "", + visitReason: encounter.visit_reason || "", + }), + }) + const data = (await resp.json()) as OpenEMRPushResponse + if (data.success) { + setOpenEMRPushState("success") + setOpenEMRPushResult(data) + await runOpenEMRPreflight(data.id) + } else { + setOpenEMRPushState("failed") + setOpenEMRError(data.error || "OpenEMR push failed.") + } + } catch (err) { + setOpenEMRPushState("failed") + setOpenEMRError(err instanceof Error ? err.message : "OpenEMR push failed.") + } + } + + const handleSetupOpenEMRAuth = async () => { + setOpenEMRAuthSetupState("setting_up") + setOpenEMRAuthSetupMessage("") + try { + const resp = await fetch("/api/integrations/openemr/auth/setup", { + method: "POST", + }) + const data = (await resp.json()) as OpenEMRAuthSetupResponse + if (data.success) { + setOpenEMRAuthSetupState("done") + setOpenEMRAuthSetupMessage(data.message || "OpenEMR auth is ready.") + await runOpenEMRPreflight(openEMRPushResult?.id) + } else { + setOpenEMRAuthSetupState("failed") + setOpenEMRAuthSetupMessage(data.error || "OpenEMR auth setup failed.") + } + } catch (err) { + setOpenEMRAuthSetupState("failed") + setOpenEMRAuthSetupMessage(err instanceof Error ? err.message : "OpenEMR auth setup failed.") + } + } + const handleOpenOpenClawChat = async () => { setOpenClawPanelOpen(true) @@ -304,6 +465,13 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { } } + const firstOpenEMRBlocker = openEMRPreflight?.blockers?.[0]?.message || openEMRPreflightError + const hasOpenEMRAuthBlocker = Boolean( + openEMRPreflight?.blockers?.some((blocker) => + blocker.code === "OPENEMR_AUTH_INVALID" || blocker.code === "OPENEMR_AUTH_EXPIRED", + ), + ) + const handleSendUserMessage = async () => { const text = openClawInput.trim() if (!text || openClawSending) return @@ -412,6 +580,37 @@ export function NoteEditor({ encounter, onSave }: NoteEditorProps) { )} + {activeTab === "note" && OPENEMR_ENABLED && ( + + )} {activeTab === "note" && ( + {openEMRAuthSetupMessage && {openEMRAuthSetupMessage}} + + )} + + )} + {openEMRPushResult && ( +
+

Uploaded to OpenEMR

+

+ Document ID: {openEMRPushResult.id} +

+

+ Uploaded at: {openEMRPushResult.uploadedAt} +

+

Verified length: {openEMRPushResult.verifiedLength} chars

+

+ Preview: {openEMRPushResult.verifiedPreview || "(empty)"} +

+
+ + {openEMRPushResult.openEMRDocumentUrl && ( + + Open in OpenEMR + + )} + {openEMRPreflight?.document_verified !== null && ( + + {openEMRPreflight?.document_verified ? "Verified" : "Not verified"} + + )} +
+
+ )} ) : (
diff --git a/packages/pipeline/transcribe/src/providers/provider-resolver.ts b/packages/pipeline/transcribe/src/providers/provider-resolver.ts index c00f741..88a1ac6 100644 --- a/packages/pipeline/transcribe/src/providers/provider-resolver.ts +++ b/packages/pipeline/transcribe/src/providers/provider-resolver.ts @@ -1,6 +1,7 @@ import { transcribeWavBuffer as transcribeWithMedASR } from "./medasr-transcriber" import { transcribeWavBuffer as transcribeWithWhisperLocal } from "./whisper-local-transcriber" import { transcribeWavBuffer as transcribeWithWhisperOpenAI } from "./whisper-transcriber" +import { PipelineStageError } from "../../../shared/src/error" export type TranscriptionProvider = "whisper_local" | "whisper_openai" | "medasr" @@ -18,6 +19,7 @@ function normalizeProvider(rawProvider: string | undefined): string { } export function resolveTranscriptionProvider(env: NodeJS.ProcessEnv = process.env): ResolvedTranscriptionProvider { + const hipaaHostedMode = env.HIPAA_HOSTED_MODE === "true" const provider = normalizeProvider(env.TRANSCRIPTION_PROVIDER) if (provider === "medasr" || provider === "med_asr") { @@ -28,6 +30,13 @@ export function resolveTranscriptionProvider(env: NodeJS.ProcessEnv = process.en } if (provider === "whisper_openai" || provider === "whisper-openai" || provider === "openai" || provider === "whisper") { + if (hipaaHostedMode) { + throw new PipelineStageError( + "configuration_error", + "whisper_openai is disabled in HIPAA hosted mode. Use internal whisper_local service.", + false, + ) + } return { provider: "whisper_openai", model: env.WHISPER_OPENAI_MODEL?.trim() || DEFAULT_WHISPER_OPENAI_MODEL, diff --git a/packages/pipeline/transcribe/src/providers/whisper-local-transcriber.ts b/packages/pipeline/transcribe/src/providers/whisper-local-transcriber.ts index 10a8539..41cb508 100644 --- a/packages/pipeline/transcribe/src/providers/whisper-local-transcriber.ts +++ b/packages/pipeline/transcribe/src/providers/whisper-local-transcriber.ts @@ -66,6 +66,26 @@ async function fetchWithTimeout(fetchFn: typeof fetch, timeoutMs: number, url: s } } +async function getGoogleIdentityToken(fetchFn: typeof fetch, audience: string): Promise { + const metadataUrl = + `http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=${encodeURIComponent(audience)}&format=full` + const response = await fetchFn(metadataUrl, { + method: "GET", + headers: { + "Metadata-Flavor": "Google", + }, + }) + if (!response.ok) { + const body = await response.text() + throw new PipelineStageError("auth_error", `Failed to obtain identity token (${response.status}): ${body}`, false) + } + const token = (await response.text()).trim() + if (!token) { + throw new PipelineStageError("auth_error", "Received empty identity token", false) + } + return token +} + function shouldRetryStatus(status: number): boolean { return status === 408 || status === 425 || status === 429 || status >= 500 } @@ -101,8 +121,14 @@ export async function transcribeWavBuffer( const totalAttempts = maxRetries + 1 for (let attempt = 1; attempt <= totalAttempts; attempt += 1) { try { + const headers: Record = {} + const authType = (process.env.WHISPER_LOCAL_AUTH_TYPE || "").trim().toLowerCase() + if (authType === "identity_token") { + headers.Authorization = `Bearer ${await getGoogleIdentityToken(fetchFn, url)}` + } const response = await fetchWithTimeout(fetchFn, timeoutMs, url, { method: "POST", + headers, body: formData, }) diff --git a/packages/storage/src/__tests__/encounters.test.ts b/packages/storage/src/__tests__/encounters.test.ts index 463533c..d02f847 100644 --- a/packages/storage/src/__tests__/encounters.test.ts +++ b/packages/storage/src/__tests__/encounters.test.ts @@ -13,7 +13,13 @@ import type { Encounter } from "../types.js" // Mock localStorage for Node.js environment const mockStorage: Record = {} -global.localStorage = { +const testGlobal = global as typeof globalThis & { + localStorage: Storage + window: Window & typeof globalThis + crypto: Crypto +} + +testGlobal.localStorage = { getItem: (key: string) => mockStorage[key] || null, setItem: (key: string, value: string) => { mockStorage[key] = value @@ -28,32 +34,16 @@ global.localStorage = { length: Object.keys(mockStorage).length, } as Storage +testGlobal.window = { + localStorage: testGlobal.localStorage, +} as unknown as Window & typeof globalThis + // Mock crypto.randomUUID for testing -if (!global.crypto) { - global.crypto = {} as Crypto -} -if (!global.crypto.randomUUID) { +if (!testGlobal.crypto.randomUUID) { let counter = 0 - // @ts-ignore - Mock for testing - global.crypto.randomUUID = () => `test-uuid-${++counter}` + testGlobal.crypto.randomUUID = () => `00000000-0000-4000-8000-${String(++counter).padStart(12, "0")}` } -// Mock secure storage for testing -// Note: In real app this would use AES-GCM encryption -// @ts-ignore - mocking module -await import("../secure-storage.js").then(module => { - const original = { ...module } - // @ts-ignore - module.loadSecureItem = async (key: string) => { - const data = localStorage.getItem(key) - return data ? JSON.parse(data) : null - } - // @ts-ignore - module.saveSecureItem = async (key: string, value: any) => { - localStorage.setItem(key, JSON.stringify(value)) - } -}) - test("saveEncounters strips audio_blob before persistence", async () => { // Clear storage localStorage.clear() diff --git a/packages/storage/src/api-keys.ts b/packages/storage/src/api-keys.ts index 62f096c..ae05247 100644 --- a/packages/storage/src/api-keys.ts +++ b/packages/storage/src/api-keys.ts @@ -60,6 +60,9 @@ export async function setApiKeys(keys: Partial): Promise { body: JSON.stringify(updated), }) + if (response.status === 410) { + return + } if (!response.ok) { console.error("Failed to sync API keys to server") } diff --git a/packages/ui/src/components/new-encounter-form.tsx b/packages/ui/src/components/new-encounter-form.tsx index 4b52ff2..d2f5053 100644 --- a/packages/ui/src/components/new-encounter-form.tsx +++ b/packages/ui/src/components/new-encounter-form.tsx @@ -19,15 +19,80 @@ const VISIT_TYPE_OPTIONS = [ { label: "Consult Note", value: "consult_note" }, ] +// Note: this constant is intentionally duplicated from apps/web where +// NEXT_PUBLIC_* vars are inlined at build time. This package can't import +// from apps/web, and the duplication is minimal and explicit. +const OPENEMR_ENABLED = process.env.NEXT_PUBLIC_OPENEMR_ENABLED === "true" +const OPENEMR_PATIENT_ID_PATTERN = + /^(?:[1-9]\d*|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i + export function NewEncounterForm({ onStart, onCancel }: NewEncounterFormProps) { const [patientName, setPatientName] = useState("") + const [patientId, setPatientId] = useState("") + const [patientIdError, setPatientIdError] = useState("") + const [pushToOpenEMR, setPushToOpenEMR] = useState(false) + const [authCheckState, setAuthCheckState] = useState<"idle" | "checking" | "ready" | "failed">("idle") + const [authCheckMessage, setAuthCheckMessage] = useState("") const [visitType, setVisitType] = useState(VISIT_TYPE_OPTIONS[0]?.value ?? "") + const runOpenEMRAuthCheck = async () => { + setAuthCheckState("checking") + setAuthCheckMessage("") + try { + const response = await fetch("/api/integrations/openemr/auth/setup", { + method: "POST", + }) + const data = (await response.json()) as { + success?: boolean + message?: string + error?: string + } + if (data.success) { + setAuthCheckState("ready") + setAuthCheckMessage(data.message || "OpenEMR auth is ready.") + } else { + setAuthCheckState("failed") + setAuthCheckMessage(data.error || "OpenEMR auth failed. Reconnect and retry.") + } + } catch (error) { + setAuthCheckState("failed") + setAuthCheckMessage(error instanceof Error ? error.message : "OpenEMR auth failed. Reconnect and retry.") + } + } + + const handleSetPushToOpenEMR = (enabled: boolean) => { + setPushToOpenEMR(enabled) + setPatientIdError("") + if (!enabled) { + setPatientId("") + setAuthCheckState("idle") + setAuthCheckMessage("") + return + } + void runOpenEMRAuthCheck() + } + const handleSubmit = (e: React.FormEvent) => { e.preventDefault() + + if (OPENEMR_ENABLED && pushToOpenEMR && !patientId.trim()) { + setPatientIdError("OpenEMR Patient ID is required") + return + } + + if (OPENEMR_ENABLED && pushToOpenEMR && !OPENEMR_PATIENT_ID_PATTERN.test(patientId.trim())) { + setPatientIdError("OpenEMR Patient ID must be a numeric PID or UUID") + return + } + + if (OPENEMR_ENABLED && pushToOpenEMR && authCheckState !== "ready") { + setPatientIdError("OpenEMR auth is not ready. Click Retry Auth Check.") + return + } + onStart({ patient_name: patientName, - patient_id: "", + patient_id: OPENEMR_ENABLED && pushToOpenEMR ? patientId.trim() : "", visit_reason: visitType, }) } @@ -68,6 +133,74 @@ export function NewEncounterForm({ onStart, onCancel }: NewEncounterFormProps) {
+ {OPENEMR_ENABLED && ( +
+ +
+ + +
+ + {pushToOpenEMR && ( +
+ + { + setPatientId(e.target.value) + if (patientIdError) setPatientIdError("") + }} + className={`rounded-xl border-border bg-secondary${patientIdError ? " border-destructive" : ""}`} + /> +
+ + {authCheckState === "checking" + ? "Checking OpenEMR auth..." + : authCheckMessage || "OpenEMR auth not checked yet."} + + +
+ {patientIdError &&

{patientIdError}

} +
+ )} +
+ )} +