diff --git a/.github/scripts/ci-changes.sh b/.github/scripts/ci-changes.sh index 0e25d496970..c506a2149bf 100755 --- a/.github/scripts/ci-changes.sh +++ b/.github/scripts/ci-changes.sh @@ -6,7 +6,8 @@ # diff sets all of them. # # full integration, e2e, e2e-build, e2e-mobile: any file not allowlisted below -# test the Vitest shards: content, docs app, and desktop changes, plus `full` +# test the Vitest shards and test-types: content, docs app, and desktop changes, +# plus `full` # build the app's `next build`: content changes, plus `full` # desktop_live the live Electron suite: any file outside its own skip list # diff --git a/.github/scripts/ci-gate.sh b/.github/scripts/ci-gate.sh index c7e4572e48b..c5303551763 100755 --- a/.github/scripts/ci-gate.sh +++ b/.github/scripts/ci-gate.sh @@ -6,7 +6,7 @@ # A skip passes only for a gated job whose `changes` flag is exactly `false`: # # integration, e2e, e2e-build, e2e-mobile full -# test test +# test, test-types test # build build # desktop-live desktop_live # @@ -25,7 +25,7 @@ fi failed="$(jq -r ' {"integration": "full", "e2e": "full", "e2e-build": "full", "e2e-mobile": "full", "test": "test", - "build": "build", "desktop-live": "desktop_live"} as $gate + "test-types": "test", "build": "build", "desktop-live": "desktop_live"} as $gate | (.changes.outputs // {}) as $flags | to_entries[] | select(.value.result != "success") diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 66e78161a70..c4163d32a94 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -653,9 +653,9 @@ jobs: # Every workspace, not just realtime. packages/emcn, packages/utils, # apps/desktop and apps/docs had no type check in CI at all; apps/sim's # source was covered only as a side effect of `next build` in the separate - # `build` job. Note this does NOT cover apps/sim's tests — its tsconfig - # excludes *.test.ts(x), and including them today surfaces ~2.2k errors, - # so that is its own cleanup rather than a gate to switch on here. + # `build` job. This does NOT cover apps/sim's tests — its tsconfig + # excludes *.test.ts(x), which carry ~2.2k errors; the `test-types` job + # ratchets those per file instead. - name: Type-check all workspaces run: bunx turbo run type-check @@ -672,6 +672,41 @@ jobs: fi echo "✅ Schema and migrations are in sync" + # Type errors in apps/sim's unit tests, ratcheted per file and TS code against a committed + # baseline (scripts/check-test-types.ts). It type-checks the whole app with its ~3.4k test files: + # lint's uncached apps/sim type-check alone takes ~35 s on this runner, so it gets its own job + # beside lint rather than a place in check:audits, which also runs on laptops. Gated like `test`. + # On failure the compiler output and its exit status are uploaded, so a fix can shrink the + # existing baseline from them (`--diagnostics --update`) without a local compile; nothing + # ever raises the baseline. + test-types: + name: test-types + needs: changes + if: needs.changes.outputs.test == 'true' + runs-on: *runner-4vcpu + timeout-minutes: 10 + + steps: + - *checkout-mirror + - *checkout-plain + + - name: Setup workspace + uses: ./.github/actions/setup + with: + provider: ${{ vars.CI_PROVIDER }} + + - name: Ratchet type errors in apps/sim tests + run: bun run scripts/check-test-types.ts --report "$RUNNER_TEMP/test-types" + + - name: Upload compiler output and counts + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: test-types + path: ${{ runner.temp }}/test-types/ + if-no-files-found: ignore + retention-days: 14 + # The root scripts and every workspace's Vitest suite (`bun run test`), split in two. apps/sim is # about 98% of the time, so only its files are sharded; shard 1 also runs the root scripts and # the other workspaces. Each shard keeps its own Turbo cache: pass-through args are part of the @@ -876,7 +911,8 @@ jobs: # on a cancelled run would report a cancelled head commit as passing. ci: name: ci - needs: [changes, integration, e2e, e2e-mobile, desktop-live, lint, test, build, e2e-build] + needs: + [changes, integration, e2e, e2e-mobile, desktop-live, lint, test-types, test, build, e2e-build] if: ${{ always() }} runs-on: *runner-2vcpu timeout-minutes: 5 diff --git a/CLAUDE.md b/CLAUDE.md index c93216218b8..dc7d197144e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,7 +22,7 @@ This file (also `AGENTS.md`) holds the repo-wide rules. Area detail lives in `.c - `compareStrings(left, right)` from `@sim/utils/string` — code-unit ordering for hashes, fingerprints, and cross-process comparisons; never `localeCompare` there - `backoffWithJitter(attempt, retryAfterMs, options?)` / `parseRetryAfter(header)` from `@sim/utils/retry` — never reimplement exponential backoff inline - **Deployment flags in the browser**: client code inside a workspace, organization, or standalone settings surface reads `hosted`, `billingEnabled`, `chatEnabled`, and the enterprise feature set through `useDeploymentShape()` (components) or `getDeploymentShape()` (block conditions, stores, helpers) from `@/lib/core/config/deployment-shape`, never `isHosted`/`isBillingEnabled`/... from `env-flags`. Those constants freeze at module init from the root layout's `NEXT_PUBLIC_*` transport, which Next's bare 404 shell and `global-error` never emit, so a recovered tab would render Sim Cloud as self-hosted; the reader is seeded from the server-resolved workspace host context, organization layout, or standalone settings layout instead. Server code keeps reading `env-flags`. -- **Type-checking**: `bun run type-check` at the root checks every workspace (`bun run type-check` inside a workspace checks just that one). `apps/sim`'s tsconfig excludes `*.test.ts(x)`, so its tests are not type-checked. Never remove the `@typescript/native` alias from the root `devDependencies`: nothing imports it, but without it a bare `tsc` resolves to the ~10x slower TypeScript 6 compiler. `bun run check:native-typecheck` enforces this; its header explains the bin-resolution trap. +- **Type-checking**: `bun run type-check` at the root checks every workspace (`bun run type-check` inside a workspace checks just that one). `apps/sim`'s tsconfig excludes `*.test.ts(x)`, so `type-check` skips its tests; CI's `test-types` job ratchets their errors per file and TS code instead (`check:test-types`, whose header says how to fix a finding): a test file may not gain one. Never remove the `@typescript/native` alias from the root `devDependencies`: nothing imports it, but without it a bare `tsc` resolves to the ~10x slower TypeScript 6 compiler. `bun run check:native-typecheck` enforces this; its header explains the bin-resolution trap. ## Architecture diff --git a/apps/sim/app/api/auth/socket-token/route.test.ts b/apps/sim/app/api/auth/socket-token/route.test.ts index 52a6b80182d..281703914d1 100644 --- a/apps/sim/app/api/auth/socket-token/route.test.ts +++ b/apps/sim/app/api/auth/socket-token/route.test.ts @@ -41,7 +41,7 @@ const IP_BACKSTOP = 300 async function mintAs(userId: string | null, ip: string) { requestUtilsMockFns.mockGetClientIp.mockReturnValue(ip) authMockFns.mockGetSession.mockResolvedValue(userId ? { user: { id: userId } } : null) - return POST(createMockRequest('POST')) + return POST(createMockRequest('POST'), { params: Promise.resolve({}) }) } describe('POST /api/auth/socket-token', () => { diff --git a/apps/sim/tsconfig.tests.json b/apps/sim/tsconfig.tests.json new file mode 100644 index 00000000000..4a10413b802 --- /dev/null +++ b/apps/sim/tsconfig.tests.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", ".next", "vitest.config.ts", "vitest.setup.ts"] +} diff --git a/package.json b/package.json index 3a7a6fa8e0a..709d70be2bb 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "check:unused-exports": "bun run scripts/check-unused-exports.ts", "check:explicit-any": "bun run scripts/check-explicit-any.ts", "check:file-names": "bun run scripts/check-file-names.ts", + "check:test-types": "bun run scripts/check-test-types.ts", "desktop-bridge-contract:update": "bun run scripts/check-desktop-bridge-contract.ts --update", "mship-contracts:generate": "bun run scripts/sync-mothership-stream-contract.ts", "mship-contracts:check": "bun run scripts/sync-mothership-stream-contract.ts --check", diff --git a/scripts/check-test-types.baseline.json b/scripts/check-test-types.baseline.json new file mode 100644 index 00000000000..0537f8fe9fe --- /dev/null +++ b/scripts/check-test-types.baseline.json @@ -0,0 +1,2987 @@ +{ + "apps/sim/app/(auth)/oauth/sign-in/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/(interfaces)/chat/components/message/components/file-download.test.tsx": { + "TS2683": 1 + }, + "apps/sim/app/.well-known/oauth-protected-resource/api/mcp/search/organizations/[organizationId]/route.ts": { + "TS18048": 1 + }, + "apps/sim/app/api/auth/[...all]/route.test.ts": { + "TS2554": 14 + }, + "apps/sim/app/api/auth/forget-password/route.test.ts": { + "TS2554": 8 + }, + "apps/sim/app/api/auth/instagram/authorize/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/auth/oauth/credentials/route.test.ts": { + "TS2322": 1, + "TS2345": 2, + "TS2554": 5 + }, + "apps/sim/app/api/auth/oauth/token/route.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2554": 11, + "TS2739": 2 + }, + "apps/sim/app/api/auth/oauth2/authorize/route.test.ts": { + "TS2345": 2, + "TS2554": 22 + }, + "apps/sim/app/api/auth/oauth2/callback/quickbooks/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/auth/oauth2/callback/shopify/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/auth/oauth2/register/route.test.ts": { + "TS2554": 7 + }, + "apps/sim/app/api/auth/oauth2/revoke/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/auth/oauth2/token/route.test.ts": { + "TS2345": 1, + "TS2554": 14 + }, + "apps/sim/app/api/auth/reset-password/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/auth/shopify/authorize/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/auth/sso/resolve/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/billing/invoices/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/billing/route.test.ts": { + "TS2345": 1, + "TS2554": 4 + }, + "apps/sim/app/api/billing/switch-plan/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/billing/update-cost/replay.live.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/billing/update-cost/route.test.ts": { + "TS2554": 51 + }, + "apps/sim/app/api/billing/update-cost/worker.live.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/blocks/visibility/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/chat/[identifier]/otp/route.test.ts": { + "TS2345": 3 + }, + "apps/sim/app/api/chat/[identifier]/route.test.ts": { + "TS18048": 4 + }, + "apps/sim/app/api/chat/validate/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/cli/auth/approve/route.test.ts": { + "TS2554": 10 + }, + "apps/sim/app/api/cli/auth/poll/route.test.ts": { + "TS2554": 7 + }, + "apps/sim/app/api/copilot/api-keys/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/copilot/api-keys/validate/route.test.ts": { + "TS2554": 55 + }, + "apps/sim/app/api/copilot/chat/stop/route.test.ts": { + "TS18046": 2, + "TS2345": 1, + "TS2554": 1, + "TS2571": 2 + }, + "apps/sim/app/api/copilot/confirm/route.test.ts": { + "TS2554": 31 + }, + "apps/sim/app/api/copilot/feedback/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/copilot/tool-permission/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/copilot/tools/execute/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/credential-groups/slack-managed-users/callback/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/cron/cleanup-file-versions/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/cron/cleanup-stale-executions/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/cron/cleanup-table-row-ttl/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/cron/renew-subscriptions/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/desktop/auth/handoff/route.test.ts": { + "TS2554": 5 + }, + "apps/sim/app/api/desktop/tool/authorize/route.test.ts": { + "TS2554": 20 + }, + "apps/sim/app/api/desktop/tool/file/route.test.ts": { + "TS2322": 1, + "TS2554": 5 + }, + "apps/sim/app/api/files/authorization.test.ts": { + "TS2322": 1, + "TS2345": 2 + }, + "apps/sim/app/api/files/delete/route.test.ts": { + "TS2345": 1, + "TS2554": 1 + }, + "apps/sim/app/api/files/export/[id]/route.test.ts": { + "TS2345": 3 + }, + "apps/sim/app/api/files/serve/[...path]/route.test.ts": { + "TS2345": 3 + }, + "apps/sim/app/api/files/uploads/finalizers.test.ts": { + "TS2741": 1 + }, + "apps/sim/app/api/files/uploads/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/folders/reorder/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/folders/route.test.ts": { + "TS2352": 1, + "TS2554": 5 + }, + "apps/sim/app/api/guardrails/mask-batch/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/guardrails/pii/validate/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/internal/file-doc/seed/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/invitations/[id]/resend/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/invitations/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/knowledge/connectors/directory-sync/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/knowledge/connectors/member-sync/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/knowledge/connectors/sync/route.test.ts": { + "TS2554": 4 + }, + "apps/sim/app/api/knowledge/github/setup/redirects.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/knowledge/slack/oauth/callback/route.test.ts": { + "TS2554": 8 + }, + "apps/sim/app/api/knowledge/utils.test.ts": { + "TS2493": 1 + }, + "apps/sim/app/api/link-preview/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/logs/export/route.test.ts": { + "TS2554": 9 + }, + "apps/sim/app/api/logs/stats/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/mcp/discover/route.test.ts": { + "TS2345": 1, + "TS2554": 2 + }, + "apps/sim/app/api/mcp/events/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/mcp/oauth/callback/route.test.ts": { + "TS2554": 7 + }, + "apps/sim/app/api/mcp/oauth/start/route.test.ts": { + "TS2554": 5 + }, + "apps/sim/app/api/mcp/serve/[serverId]/route.test.ts": { + "TS2322": 2 + }, + "apps/sim/app/api/mcp/servers/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/mcp/servers/test-connection/route.test.ts": { + "TS2554": 5 + }, + "apps/sim/app/api/mothership/chats/[chatId]/fork/route.test.ts": { + "TS2488": 1, + "TS2571": 3 + }, + "apps/sim/app/api/mothership/chats/read/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/mothership/chats/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/mothership/events/route.test.ts": { + "TS2554": 10 + }, + "apps/sim/app/api/organizations/[id]/permission-groups/[groupId]/route.test.ts": { + "TS2550": 2 + }, + "apps/sim/app/api/organizations/route.test.ts": { + "TS2554": 3, + "TS2769": 1 + }, + "apps/sim/app/api/pinned-items/route.test.ts": { + "TS2352": 1, + "TS2554": 2 + }, + "apps/sim/app/api/providers/baseten/models/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/providers/ollama-cloud/models/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/providers/ollama/models/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/providers/together/models/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/providers/vllm/models/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/resume/poll/route.test.ts": { + "TS2367": 1, + "TS2554": 10 + }, + "apps/sim/app/api/schedules/execute/route.test.ts": { + "TS2739": 30 + }, + "apps/sim/app/api/schedules/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/selectors/execute/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/skills/route.test.ts": { + "TS2554": 6 + }, + "apps/sim/app/api/table/[tableId]/columns/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/[tableId]/delete-async/route.test.ts": { + "TS2345": 2 + }, + "apps/sim/app/api/table/[tableId]/export/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/[tableId]/import/route.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/app/api/table/[tableId]/restore/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/[tableId]/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/[tableId]/rows/find/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/capability-gate.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/table/executor-capability-exemption.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2554": 2 + }, + "apps/sim/app/api/table/import-csv/route.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2554": 8 + }, + "apps/sim/app/api/table/utils.test.ts": { + "TS2353": 1 + }, + "apps/sim/app/api/tools/custom/route.test.ts": { + "TS2345": 2, + "TS2554": 1 + }, + "apps/sim/app/api/users/me/settings/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/users/me/subscription/[id]/transfer/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/users/me/usage-limits/route.test.ts": { + "TS2345": 1, + "TS2554": 1 + }, + "apps/sim/app/api/users/me/usage-logs/cursor-route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/users/me/usage-logs/export/route.test.ts": { + "TS2554": 5 + }, + "apps/sim/app/api/users/me/usage-logs/route.test.ts": { + "TS2554": 3 + }, + "apps/sim/app/api/v1/audit-logs/[id]/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/v1/audit-logs/route.test.ts": { + "TS2345": 1, + "TS2554": 3 + }, + "apps/sim/app/api/v1/capability-gate.test.ts": { + "TS2345": 1, + "TS2554": 6 + }, + "apps/sim/app/api/v1/knowledge/[id]/documents/route.test.ts": { + "TS2578": 1 + }, + "apps/sim/app/api/v1/knowledge/search/route.test.ts": { + "TS2322": 1, + "TS2554": 4 + }, + "apps/sim/app/api/v1/logs/projection.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/v1/tables/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/v1/workflows/[id]/export/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/v1/workflows/[id]/rollback/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/v1/workflows/import/route.test.ts": { + "TS2345": 1, + "TS2554": 5 + }, + "apps/sim/app/api/v2/access-requests.test.ts": { + "TS2345": 14 + }, + "apps/sim/app/api/v2/chat/route.test.ts": { + "TS18046": 1, + "TS2353": 1, + "TS7053": 1 + }, + "apps/sim/app/api/v2/knowledge/[knowledgeBaseId]/documents/uploads/[uploadId]/complete/route.test.ts": { + "TS2345": 2 + }, + "apps/sim/app/api/v2/knowledge/search/route.application.test.ts": { + "TS2540": 1 + }, + "apps/sim/app/api/v2/tables/presenters.test.ts": { + "TS2345": 5, + "TS2739": 7 + }, + "apps/sim/app/api/v2/uploads/[uploadId]/route.test.ts": { + "TS2322": 1 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/duplicate/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/execute/route.test.ts": { + "TS2769": 3 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/export/route.test.ts": { + "TS18048": 3 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/operations/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/restore/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/state/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/v2/workflows/[workflowId]/versions/[version]/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/webhooks/[id]/reactivation-gate.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/app/api/webhooks/agentmail/route.test.ts": { + "TS2554": 6 + }, + "apps/sim/app/api/webhooks/quickbooks/[appKey]/route.test.ts": { + "TS2322": 1 + }, + "apps/sim/app/api/webhooks/route.test.ts": { + "TS2352": 1, + "TS2493": 1, + "TS2554": 15 + }, + "apps/sim/app/api/webhooks/slack/route.test.ts": { + "TS2554": 1 + }, + "apps/sim/app/api/webhooks/tiktok/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/webhooks/trigger/[path]/route.test.ts": { + "TS2339": 1 + }, + "apps/sim/app/api/workflows/[id]/chat/status/route.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/api/workflows/[id]/execute/response-block.test.ts": { + "TS2305": 1 + }, + "apps/sim/app/api/workflows/[id]/execute/route.test.ts": { + "TS2339": 1 + }, + "apps/sim/app/api/workflows/[id]/variables/route.test.ts": { + "TS2345": 2 + }, + "apps/sim/app/api/workflows/middleware.test.ts": { + "TS2322": 2 + }, + "apps/sim/app/api/workflows/route.test.ts": { + "TS2345": 1, + "TS2554": 2 + }, + "apps/sim/app/api/workspace-events/poll/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/api/workspaces/invitations/route.test.ts": { + "TS2322": 1, + "TS2554": 1 + }, + "apps/sim/app/api/workspaces/route.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/credential-groups/enroll/[token]/page.test.tsx": { + "TS2322": 1 + }, + "apps/sim/app/desktop/auth/page.test.tsx": { + "TS2345": 1 + }, + "apps/sim/app/desktop/connect/page.test.tsx": { + "TS2345": 1 + }, + "apps/sim/app/o/[organizationId]/home/organization-home.test.tsx": { + "TS2698": 1 + }, + "apps/sim/app/o/[organizationId]/settings/components/integrations/search-source-setup.test.tsx": { + "TS2339": 31, + "TS2345": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/apply-streamed-markdown.test.ts": { + "TS2353": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/collab-streaming-integration.test.ts": { + "TS2353": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/file-doc-provider.test.ts": { + "TS2550": 3 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/dirty-on-open.test.ts": { + "TS2578": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-lifecycle.test.tsx": { + "TS2741": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/field-lifecycle.test.tsx": { + "TS2550": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/field-upload.test.tsx": { + "TS2322": 2, + "TS2550": 3 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/image-collaboration.test.tsx": { + "TS2345": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/image-resize.test.tsx": { + "TS2345": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/keymap.test.ts": { + "TS2345": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/link-input-rule.test.ts": { + "TS2554": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/list-input-rules.test.ts": { + "TS2339": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/markdown-paste.test.ts": { + "TS2739": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/markdown-storage.test.ts": { + "TS2339": 2 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/paste-admission.test.ts": { + "TS2684": 1 + }, + "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/use-editable-file-conflicts.test.tsx": { + "TS2550": 6 + }, + "apps/sim/app/workspace/[workspaceId]/home/components/knowledge-search-results/search-transitions.test.tsx": { + "TS2322": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.test.ts": { + "TS18048": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-panel-occlusion.test.ts": { + "TS2493": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.test.ts": { + "TS2769": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/use-prompt-editor.test.tsx": { + "TS2322": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/hooks/preview/apply-file-preview-phase.test.ts": { + "TS2322": 3 + }, + "apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-resource-event.test.ts": { + "TS2741": 1 + }, + "apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.dom.test.tsx": { + "TS2304": 1, + "TS2322": 4, + "TS2353": 1, + "TS2550": 1, + "TS2741": 4 + }, + "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/use-connector-settings-form.test.tsx": { + "TS2322": 1 + }, + "apps/sim/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload.test.tsx": { + "TS2322": 1 + }, + "apps/sim/app/workspace/[workspaceId]/providers/workspace-scope-sync.test.tsx": { + "TS2345": 1 + }, + "apps/sim/app/workspace/[workspaceId]/settings/components/browser/components/password-detail/password-detail.test.tsx": { + "TS2322": 2 + }, + "apps/sim/app/workspace/[workspaceId]/settings/components/browser/components/passwords-view/passwords-view.test.tsx": { + "TS2322": 3 + }, + "apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.test.tsx": { + "TS2339": 4 + }, + "apps/sim/app/workspace/[workspaceId]/settings/components/general/components/privacy-view.test.tsx": { + "TS2550": 2 + }, + "apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-filter/table-filter.test.tsx": { + "TS7017": 1 + }, + "apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table-event-stream.test.ts": { + "TS2739": 3 + }, + "apps/sim/app/workspace/[workspaceId]/tables/[tableId]/utils.test.ts": { + "TS2345": 3 + }, + "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/slack-setup-wizard/slack-setup-wizard.test.tsx": { + "TS2339": 1 + }, + "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-node-utilities.test.tsx": { + "TS2339": 2, + "TS2739": 3 + }, + "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.test.tsx": { + "TS2322": 4, + "TS2345": 5, + "TS2353": 1, + "TS2554": 1, + "TS7006": 2 + }, + "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.test.ts": { + "TS2739": 1 + }, + "apps/sim/app/workspace/[workspaceId]/w/components/workflow-diff/utils.test.ts": { + "TS2322": 2 + }, + "apps/sim/background/async-execution-correlation.test.ts": { + "TS2345": 2 + }, + "apps/sim/background/async-preprocessing-correlation.test.ts": { + "TS2353": 1 + }, + "apps/sim/background/cleanup-soft-deletes.test.ts": { + "TS18046": 2, + "TS2345": 3, + "TS2352": 2, + "TS2493": 2, + "TS7006": 2 + }, + "apps/sim/background/cleanup-stale-executions.test.ts": { + "TS18048": 2, + "TS2493": 1, + "TS2677": 1 + }, + "apps/sim/background/cleanup-tasks.test.ts": { + "TS18046": 3 + }, + "apps/sim/background/drain-governed-subject.test.ts": { + "TS2353": 1 + }, + "apps/sim/background/knowledge-connector-member-sync.test.ts": { + "TS2741": 7 + }, + "apps/sim/background/knowledge-processing.test.ts": { + "TS2339": 3, + "TS2345": 29, + "TS2571": 1 + }, + "apps/sim/background/webhook-execution.test.ts": { + "TS2345": 1, + "TS2353": 1 + }, + "apps/sim/background/workflow-column-execution.test.ts": { + "TS2345": 5, + "TS2352": 1 + }, + "apps/sim/background/workflow-group-governed-subject.test.ts": { + "TS2353": 1 + }, + "apps/sim/blocks/blocks/airtable.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/ashby.test.ts": { + "TS18048": 11 + }, + "apps/sim/blocks/blocks/cloudtrail.test.ts": { + "TS2554": 1 + }, + "apps/sim/blocks/blocks/crowdstrike.test.ts": { + "TS2722": 1 + }, + "apps/sim/blocks/blocks/file.test.ts": { + "TS18048": 2, + "TS2345": 4, + "TS2554": 2, + "TS2722": 13 + }, + "apps/sim/blocks/blocks/gitlab.test.ts": { + "TS18048": 7 + }, + "apps/sim/blocks/blocks/google_drive.test.ts": { + "TS18048": 1, + "TS2554": 4 + }, + "apps/sim/blocks/blocks/instagram.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/jotform.test.ts": { + "TS18048": 1, + "TS2339": 1 + }, + "apps/sim/blocks/blocks/mem0.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/microsoft_ad.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/mintlify.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/mssql.test.ts": { + "TS18048": 1, + "TS2339": 2 + }, + "apps/sim/blocks/blocks/outlook.test.ts": { + "TS18048": 2 + }, + "apps/sim/blocks/blocks/slack.test.ts": { + "TS2339": 1 + }, + "apps/sim/blocks/blocks/supabase.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/blocks/tiktok.test.ts": { + "TS18048": 1 + }, + "apps/sim/blocks/selector-backed-subblocks.test.ts": { + "TS2345": 1 + }, + "apps/sim/blocks/utils.test.ts": { + "TS2322": 1 + }, + "apps/sim/blocks/visibility/visibility.test.ts": { + "TS2352": 1 + }, + "apps/sim/components/integrations/slack-app-manifest.test.tsx": { + "TS2339": 1 + }, + "apps/sim/components/settings/navigation.test.ts": { + "TS2741": 1 + }, + "apps/sim/components/ui/generated-password-input.test.tsx": { + "TS2339": 12 + }, + "apps/sim/connectors/coda/coda.live.test.ts": { + "TS2339": 1 + }, + "apps/sim/connectors/sharepoint/sharepoint.test.ts": { + "TS2339": 4 + }, + "apps/sim/ee/access-control/components/group-detail.test.tsx": { + "TS2345": 1 + }, + "apps/sim/ee/access-control/hooks/permission-groups.test.tsx": { + "TS2741": 3 + }, + "apps/sim/ee/access-requests/lib/application/authorization.test.ts": { + "TS2345": 1 + }, + "apps/sim/ee/access-requests/lib/catalog.test.ts": { + "TS2345": 1, + "TS2740": 17 + }, + "apps/sim/ee/access-requests/lib/notifications.test.ts": { + "TS2493": 2 + }, + "apps/sim/ee/scim/lib/identity/resolve-user.test.ts": { + "TS18046": 2 + }, + "apps/sim/ee/scim/lib/projection/auto-map.test.ts": { + "TS2345": 2 + }, + "apps/sim/ee/scim/lib/projection/reconcile-user.test.ts": { + "TS2345": 15, + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/ee/scim/lib/reconcile/job.test.ts": { + "TS2345": 6 + }, + "apps/sim/ee/sso/components/sso-settings.test.tsx": { + "TS2339": 2 + }, + "apps/sim/ee/workspace-forking/components/fork-sync/copy-reconciliation.test.ts": { + "TS2322": 1 + }, + "apps/sim/ee/workspace-forking/components/fork-sync/use-fork-sync.test.tsx": { + "TS2322": 1 + }, + "apps/sim/ee/workspace-forking/lib/copy/copy-files.test.ts": { + "TS2345": 1, + "TS2554": 1 + }, + "apps/sim/ee/workspace-forking/lib/copy/copy-resources.test.ts": { + "TS2352": 1, + "TS2493": 3 + }, + "apps/sim/ee/workspace-forking/lib/copy/copy-workflows.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2739": 1 + }, + "apps/sim/ee/workspace-forking/lib/copy/workflow-mcp-attachments.test.ts": { + "TS2322": 4 + }, + "apps/sim/ee/workspace-forking/lib/promote/promote.test.ts": { + "TS2322": 2 + }, + "apps/sim/ee/workspace-forking/lib/promote/rollback.test.ts": { + "TS2345": 1 + }, + "apps/sim/executor/dag/construction/edges.test.ts": { + "TS18048": 1 + }, + "apps/sim/executor/execution/block-executor.test.ts": { + "TS2339": 6, + "TS2493": 6, + "TS2741": 8 + }, + "apps/sim/executor/execution/edge-manager.test.ts": { + "TS2322": 4 + }, + "apps/sim/executor/execution/engine.test.ts": { + "TS2322": 2, + "TS2339": 2, + "TS2345": 29, + "TS2430": 1, + "TS2741": 2 + }, + "apps/sim/executor/execution/executor.test.ts": { + "TS2322": 1, + "TS2339": 4, + "TS2739": 3, + "TS2741": 5 + }, + "apps/sim/executor/execution/snapshot-serializer.test.ts": { + "TS2322": 1, + "TS2353": 1 + }, + "apps/sim/executor/execution/snapshot.test.ts": { + "TS2741": 1 + }, + "apps/sim/executor/execution/test-hooks.test.ts": { + "TS2339": 3 + }, + "apps/sim/executor/handlers/agent/agent-handler.test.ts": { + "TS18046": 2, + "TS18048": 6, + "TS2339": 4, + "TS2345": 1, + "TS2352": 1, + "TS2493": 3, + "TS7006": 1 + }, + "apps/sim/executor/handlers/agent/memory.test.ts": { + "TS2739": 1 + }, + "apps/sim/executor/handlers/condition/condition-handler.test.ts": { + "TS2322": 2, + "TS2561": 1, + "TS2739": 4, + "TS2769": 3 + }, + "apps/sim/executor/handlers/evaluator/evaluator-handler.test.ts": { + "TS18048": 1, + "TS2345": 1 + }, + "apps/sim/executor/handlers/mothership/mothership-handler.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2352": 1, + "TS2532": 1 + }, + "apps/sim/executor/handlers/pi/cloud/authoring/backend.test.ts": { + "TS2345": 4, + "TS2353": 1, + "TS2769": 1 + }, + "apps/sim/executor/handlers/pi/cloud/review/backend.test.ts": { + "TS2345": 1 + }, + "apps/sim/executor/handlers/variables/variables-handler.test.ts": { + "TS2339": 1 + }, + "apps/sim/executor/handlers/workflow/workflow-handler.test.ts": { + "TS2493": 1, + "TS2571": 1 + }, + "apps/sim/executor/orchestrators/loop.test.ts": { + "TS2322": 1, + "TS2352": 1, + "TS2741": 1 + }, + "apps/sim/executor/orchestrators/node.test.ts": { + "TS2322": 1, + "TS2345": 2, + "TS2741": 1 + }, + "apps/sim/executor/orchestrators/parallel.test.ts": { + "TS2739": 3 + }, + "apps/sim/executor/utils/block-data.test.ts": { + "TS2345": 1 + }, + "apps/sim/executor/utils/errors.test.ts": { + "TS2741": 4 + }, + "apps/sim/executor/utils/file-tool-processor.test.ts": { + "TS2741": 2 + }, + "apps/sim/executor/utils/resolved-secret-content-projection.test.ts": { + "TS2353": 1 + }, + "apps/sim/executor/utils/run-from-block.test.ts": { + "TS2353": 9 + }, + "apps/sim/executor/variables/resolver.test.ts": { + "TS2352": 3 + }, + "apps/sim/executor/variables/resolvers/loop.test.ts": { + "TS2345": 18 + }, + "apps/sim/executor/variables/resolvers/parallel.test.ts": { + "TS2345": 19 + }, + "apps/sim/hooks/queries/credential-groups.test.tsx": { + "TS2741": 1 + }, + "apps/sim/hooks/queries/folders.test.ts": { + "TS2322": 1, + "TS2551": 1 + }, + "apps/sim/hooks/queries/kb/connectors-cache.test.tsx": { + "TS2550": 1 + }, + "apps/sim/hooks/queries/kb/connectors.test.ts": { + "TS2322": 1 + }, + "apps/sim/hooks/queries/mothership-chat-effort.test.tsx": { + "TS2550": 2 + }, + "apps/sim/hooks/queries/mothership-chats.test.ts": { + "TS2550": 4 + }, + "apps/sim/hooks/queries/organization.test.tsx": { + "TS2339": 7 + }, + "apps/sim/hooks/queries/scoped-credentials-mutations.test.ts": { + "TS2345": 1 + }, + "apps/sim/hooks/queries/search-integrations.test.tsx": { + "TS2550": 1 + }, + "apps/sim/hooks/queries/table-analytics.test.tsx": { + "TS2741": 1 + }, + "apps/sim/hooks/queries/tables.test.ts": { + "TS2339": 1, + "TS2345": 3, + "TS2352": 1, + "TS2551": 4 + }, + "apps/sim/hooks/queries/utils/folder-tree.test.ts": { + "TS2353": 1 + }, + "apps/sim/hooks/queries/utils/reset-organization-search-access.test.ts": { + "TS2550": 2 + }, + "apps/sim/hooks/queries/workflow-mcp-servers.test.tsx": { + "TS2322": 1 + }, + "apps/sim/hooks/queries/workflow-search-replace.test.ts": { + "TS2345": 1 + }, + "apps/sim/hooks/use-autosave.test.tsx": { + "TS2345": 1, + "TS2493": 1, + "TS2550": 1 + }, + "apps/sim/hooks/use-execution-stream.test.tsx": { + "TS2322": 1 + }, + "apps/sim/lib/admin/member-operation.test.ts": { + "TS2739": 3 + }, + "apps/sim/lib/api/client/request.test.ts": { + "TS2352": 1, + "TS2493": 4 + }, + "apps/sim/lib/api/contracts/tables-predicate.test.ts": { + "TS2456": 1 + }, + "apps/sim/lib/api/contracts/v1/tables/index.test.ts": { + "TS2769": 1 + }, + "apps/sim/lib/api/contracts/v2/workflow-deployment-requests.test.ts": { + "TS18048": 4 + }, + "apps/sim/lib/api/cursor-binding.test.ts": { + "TS2769": 1 + }, + "apps/sim/lib/api/list-convention.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/api/list-keyset-paging.test.ts": { + "TS2554": 4 + }, + "apps/sim/lib/api/server/routes/copilot-route-inventory.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/api/server/routes/definition.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/api/server/routes/internal-json-route.test.ts": { + "TS2741": 16 + }, + "apps/sim/lib/api/server/routes/scim-route.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/api/server/routes/v2-binary-route.test.ts": { + "TS2322": 1, + "TS2741": 3 + }, + "apps/sim/lib/api/server/routes/v2-body-lifecycle-route.test.ts": { + "TS18046": 3, + "TS2322": 2, + "TS2741": 4 + }, + "apps/sim/lib/auth/constants.test.ts": { + "TS2339": 4 + }, + "apps/sim/lib/auth/credential-access.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/auth/oauth-provider-adapter-guard.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/auth/oauth-provider-metadata.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/auth/oauth-token-family.test.ts": { + "TS2493": 1 + }, + "apps/sim/lib/auth/principal.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/auth/security-policy.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/auth/session-hooks.test.ts": { + "TS2345": 9 + }, + "apps/sim/lib/auth/session-policy.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/billing/application/usage-limits.test.ts": { + "TS2322": 1, + "TS2353": 2 + }, + "apps/sim/lib/billing/authorization.test.ts": { + "TS2554": 1 + }, + "apps/sim/lib/billing/core/billing-attribution.test.ts": { + "TS2345": 6 + }, + "apps/sim/lib/billing/core/subscription.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/billing/core/usage.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/billing/credits/weekly-refresh.test.ts": { + "TS2352": 1, + "TS2493": 1, + "TS2739": 1 + }, + "apps/sim/lib/billing/enterprise-outbox.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/billing/enterprise-provisioning.test.ts": { + "TS2345": 2, + "TS2739": 16 + }, + "apps/sim/lib/billing/organization.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/billing/organizations/lock-order.test.ts": { + "TS2345": 2, + "TS2352": 1, + "TS2493": 2 + }, + "apps/sim/lib/billing/organizations/member-limits.test.ts": { + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/lib/billing/organizations/membership-reconciliation.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/billing/webhooks/outbox-handlers.test.ts": { + "TS2739": 4 + }, + "apps/sim/lib/billing/workspace-permissions.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/browser-agent/transport.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/catalog/application/catalog-reads.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/catalog/projection/catalog-sweep.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/charts/option.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/charts/spec.test.ts": { + "TS2341": 1 + }, + "apps/sim/lib/collab-doc/converter.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/collab-doc/persist.test.ts": { + "TS2339": 2, + "TS2550": 2 + }, + "apps/sim/lib/collab-doc/seed.test.ts": { + "TS2339": 3, + "TS2550": 2 + }, + "apps/sim/lib/core/application/authorized-workspace-use-case.test.ts": { + "TS2345": 1, + "TS2741": 2 + }, + "apps/sim/lib/core/application/locked-credential-authorization.test.ts": { + "TS2739": 3 + }, + "apps/sim/lib/core/application/organization-authorization.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/core/application/workspace-authorization.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/core/async-jobs/backends/trigger-dev.test.ts": { + "TS18046": 2 + }, + "apps/sim/lib/core/config/env-capabilities.test.ts": { + "TS18046": 3 + }, + "apps/sim/lib/core/config/env.dom.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/core/config/feature-flags.test.ts": { + "TS2307": 1, + "TS2664": 1 + }, + "apps/sim/lib/core/config/redis.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/core/execution-limits/types.test.ts": { + "TS2307": 2, + "TS2664": 1 + }, + "apps/sim/lib/core/idempotency/service.test.ts": { + "TS2339": 1, + "TS2493": 1 + }, + "apps/sim/lib/core/network/application/read-organization-network.test.ts": { + "TS2345": 1, + "TS2352": 1, + "TS2353": 1 + }, + "apps/sim/lib/core/network/gateway.server.test.ts": { + "TS2724": 1, + "TS2740": 2 + }, + "apps/sim/lib/core/network/resource-scope.server.test.ts": { + "TS18048": 1, + "TS2322": 1, + "TS2739": 1 + }, + "apps/sim/lib/core/rate-limiter/hosted-key/hosted-key-rate-limiter.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/core/rate-limiter/provider-admission.test.ts": { + "TS2345": 1, + "TS7006": 1 + }, + "apps/sim/lib/core/rate-limiter/rate-limiter.test.ts": { + "TS2307": 4, + "TS2352": 1, + "TS2664": 2 + }, + "apps/sim/lib/core/rate-limiter/storage/factory.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/core/security/encryption.test.ts": { + "TS2352": 2 + }, + "apps/sim/lib/core/security/guarded-request-fetch.server.test.ts": { + "TS2307": 2, + "TS2664": 1 + }, + "apps/sim/lib/core/security/pinned-fetch.server.test.ts": { + "TS2307": 2, + "TS2664": 1 + }, + "apps/sim/lib/core/security/ssrf-guarded-lookup.test.ts": { + "TS2307": 2, + "TS2664": 1 + }, + "apps/sim/lib/core/utils/request-attribution.test.ts": { + "TS2769": 2 + }, + "apps/sim/lib/credential-groups/application/authorization.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/credential-groups/application/list-credentials.test.ts": { + "TS18048": 1 + }, + "apps/sim/lib/credential-groups/application/manage-access.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/credential-groups/application/manage-groups.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/credential-groups/application/organization-access.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/credential-groups/application/public-enrollment.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/credential-groups/application/slack-managed-users.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/credential-groups/oauth.test.ts": { + "TS2345": 10 + }, + "apps/sim/lib/credential-groups/organization-account-options.test.ts": { + "TS18048": 1 + }, + "apps/sim/lib/credential-groups/organization-provider-setup.test.ts": { + "TS2345": 5, + "TS2769": 1 + }, + "apps/sim/lib/credential-groups/provider-configuration.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/credential-groups/slack-managed-users.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/credential-groups/slack-provider.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/credential-groups/standard-oauth-provider.test.ts": { + "TS2739": 1, + "TS2741": 1 + }, + "apps/sim/lib/credentials/application/authorized-credential-use-case.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/lib/credentials/application/credential-crud.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/credentials/application/list-workspace-credentials.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/credentials/application/managed-oauth-delegation.test.ts": { + "TS2554": 1 + }, + "apps/sim/lib/credentials/application/resolve-organization-personal-token.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/credentials/application/service-account.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/credentials/connect-draft.test.ts": { + "TS18048": 2, + "TS2493": 2 + }, + "apps/sim/lib/credentials/environment.test.ts": { + "TS2339": 1, + "TS2493": 1 + }, + "apps/sim/lib/credentials/orchestration/index.test.ts": { + "TS2352": 2, + "TS2493": 2 + }, + "apps/sim/lib/credentials/secret-mount-options.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/custom-tools/application/use-cases.test.ts": { + "TS2322": 3 + }, + "apps/sim/lib/data-drains/destinations/azure-blob.test.ts": { + "TS2345": 2, + "TS2352": 1 + }, + "apps/sim/lib/data-drains/destinations/bigquery.test.ts": { + "TS2345": 1, + "TS2352": 3 + }, + "apps/sim/lib/data-drains/destinations/datadog.test.ts": { + "TS2352": 3, + "TS2493": 2 + }, + "apps/sim/lib/data-drains/destinations/gcs.test.ts": { + "TS2345": 1, + "TS2352": 3 + }, + "apps/sim/lib/data-drains/destinations/s3-transport.test.ts": { + "TS2322": 1, + "TS2739": 3 + }, + "apps/sim/lib/data-drains/destinations/s3.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/data-drains/destinations/snowflake.test.ts": { + "TS2352": 2, + "TS2493": 2 + }, + "apps/sim/lib/data-drains/destinations/webhook.test.ts": { + "TS2741": 7 + }, + "apps/sim/lib/desktop/index.test.ts": { + "TS2740": 5 + }, + "apps/sim/lib/desktop/preferences-loading.test.ts": { + "TS2550": 1, + "TS2740": 1 + }, + "apps/sim/lib/desktop/update-feed.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/embeddings/client.test.ts": { + "TS2339": 1, + "TS2741": 18 + }, + "apps/sim/lib/execution/cancel-workflow-execution.test.ts": { + "TS2740": 1 + }, + "apps/sim/lib/execution/event-buffer.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/execution/files.test.ts": { + "TS2322": 1, + "TS2741": 1 + }, + "apps/sim/lib/execution/payloads/large-value-metadata.test.ts": { + "TS2339": 2, + "TS2493": 3 + }, + "apps/sim/lib/execution/payloads/prune-metadata-sql.test.ts": { + "TS2345": 1, + "TS2749": 1 + }, + "apps/sim/lib/execution/payloads/serializer.test.ts": { + "TS2322": 1, + "TS2339": 1, + "TS2740": 1 + }, + "apps/sim/lib/execution/remote-sandbox/conformance.test.ts": { + "TS2741": 8 + }, + "apps/sim/lib/execution/remote-sandbox/fellows-digest.test.ts": { + "TS2550": 1, + "TS2739": 1, + "TS7006": 1 + }, + "apps/sim/lib/execution/remote-sandbox/resolve.test.ts": { + "TS2345": 3, + "TS2739": 8 + }, + "apps/sim/lib/execution/remote-sandbox/sandbox-spec.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/execution/remote-sandbox/session-sandbox.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/file-parsers/odf-text.test.ts": { + "TS2739": 4 + }, + "apps/sim/lib/file-parsers/ooxml-encryption.test.ts": { + "TS2739": 2 + }, + "apps/sim/lib/file-parsers/ooxml-presentation.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/file-parsers/ooxml-preview-guard.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/file-parsers/pdf-parser-cancellation.test.ts": { + "TS2352": 4 + }, + "apps/sim/lib/file-parsers/pdfjs-server.test.ts": { + "TS2322": 1, + "TS2352": 1 + }, + "apps/sim/lib/file-parsers/pptx-parser.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/file-parsers/sheet-display-text.test.ts": { + "TS2694": 1 + }, + "apps/sim/lib/folders/application-folder-caps.test.ts": { + "TS2353": 1, + "TS2741": 2 + }, + "apps/sim/lib/folders/cascade.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/folders/queries.test.ts": { + "TS2322": 2, + "TS2741": 2 + }, + "apps/sim/lib/function-execution/application/execute-chat-function.test.ts": { + "TS2322": 2, + "TS2353": 1 + }, + "apps/sim/lib/global-work/summary.test.ts": { + "TS2493": 1 + }, + "apps/sim/lib/integrations/credential-visibility.server.test.ts": { + "TS4104": 1 + }, + "apps/sim/lib/internal/a2a/operations.test.ts": { + "TS2345": 1, + "TS2739": 2 + }, + "apps/sim/lib/internal/agiloft/client.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/internal/agiloft/operations.test.ts": { + "TS2322": 1, + "TS2739": 2 + }, + "apps/sim/lib/internal/box/execute-tool.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/internal/box/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/brex/execute-tool.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/internal/brex/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/buffer/operations.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/internal/clickup/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/cloudtrail/execute-tool.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/internal/docusign/operations.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/internal/dropbox/execute-tool.test.ts": { + "TS2339": 1, + "TS2345": 1 + }, + "apps/sim/lib/internal/dropbox/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/elevenlabs/operations.test.ts": { + "TS2345": 1, + "TS2741": 2 + }, + "apps/sim/lib/internal/file/operations.provenance.test.ts": { + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/lib/internal/file/operations.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/internal/file/parser.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/internal/function/execute.test.ts": { + "TS2322": 1, + "TS2741": 1 + }, + "apps/sim/lib/internal/gmail/operations.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/internal/google-drive/file-input.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/guardrails/operations.test.ts": { + "TS2739": 1, + "TS2741": 4 + }, + "apps/sim/lib/internal/iam/client.test.ts": { + "TS2322": 3 + }, + "apps/sim/lib/internal/instagram/execute-tool.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/internal/instagram/operations.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/internal/jira/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/lambda/projection-contract.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/llm/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/mail/attachment-materialization.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/mssql/query.test.ts": { + "TS18048": 5, + "TS2493": 3 + }, + "apps/sim/lib/internal/oci/client.server.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/internal/onedrive/operations.test.ts": { + "TS2305": 1 + }, + "apps/sim/lib/internal/oracle-epm/client.server.test.ts": { + "TS2550": 1 + }, + "apps/sim/lib/internal/oracle-fusion/client.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/internal/oracledb/oracle-worker.test.ts": { + "TS2502": 1 + }, + "apps/sim/lib/internal/oracledb/public-contract.test.ts": { + "TS18048": 1, + "TS2353": 1 + }, + "apps/sim/lib/internal/outlook/operations.test.ts": { + "TS2305": 1 + }, + "apps/sim/lib/internal/pipedrive/operations.test.ts": { + "TS2305": 1 + }, + "apps/sim/lib/internal/postgresql/client.test.ts": { + "TS2493": 2 + }, + "apps/sim/lib/internal/quiver/operations.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/internal/s3/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/sailpoint/execute-tool.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/sap-concur/client.test.ts": { + "TS2339": 8 + }, + "apps/sim/lib/internal/sap-concur/operations.test.ts": { + "TS2739": 2 + }, + "apps/sim/lib/internal/sftp/client.test.ts": { + "TS2554": 2 + }, + "apps/sim/lib/internal/sftp/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/sharepoint/execute-tool.test.ts": { + "TS2339": 1, + "TS2345": 1 + }, + "apps/sim/lib/internal/sharepoint/operations.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/internal/slack/execute-tool.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/internal/slack/operations.test.ts": { + "TS2305": 1 + }, + "apps/sim/lib/internal/ssm/execute-tool.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/internal/stagehand/execute-tool.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/internal/stagehand/schema-conversion.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/internal/stt/execute-tool.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/internal/twilio-voice/operations.test.ts": { + "TS2305": 1 + }, + "apps/sim/lib/internal/vanta/execute-tool.test.ts": { + "TS2339": 3 + }, + "apps/sim/lib/internal/vanta/file-input.test.ts": { + "TS2739": 2 + }, + "apps/sim/lib/internal/vanta/operations.test.ts": { + "TS2305": 1, + "TS2322": 2 + }, + "apps/sim/lib/internal/video/operations.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/internal/whatsapp/upload.test.ts": { + "TS2739": 2 + }, + "apps/sim/lib/internal/windchill/operations.test.ts": { + "TS2322": 4, + "TS2739": 3 + }, + "apps/sim/lib/invitations/application/manage-invitation.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/invitations/application/send-invitation-batch.test.ts": { + "TS2322": 2, + "TS2345": 2 + }, + "apps/sim/lib/invitations/core.test.ts": { + "TS2345": 4, + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/lib/invitations/direct-grant.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/invitations/organization-invitations.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/invitations/resend-policy.test.ts": { + "TS2345": 4, + "TS2741": 1 + }, + "apps/sim/lib/invitations/workspace-invitations.test.ts": { + "TS2322": 3, + "TS2345": 1 + }, + "apps/sim/lib/knowledge/access/availability.test.ts": { + "TS18046": 1 + }, + "apps/sim/lib/knowledge/application/connector-access.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/application/connectors.test.ts": { + "TS2322": 10, + "TS2345": 1 + }, + "apps/sim/lib/knowledge/application/contexts.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/knowledge/application/documents.test.ts": { + "TS2322": 2, + "TS2739": 1 + }, + "apps/sim/lib/knowledge/application/read-original-document.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/application/search-integrations.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/knowledge/application/search-sources.test.ts": { + "TS2322": 1, + "TS2345": 2 + }, + "apps/sim/lib/knowledge/application/search.test.ts": { + "TS2345": 1, + "TS2769": 1 + }, + "apps/sim/lib/knowledge/application/sim-search.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/application/slack-search/identity.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/knowledge/application/slack-search/ingress.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/knowledge/application/slack-search/installations.test.ts": { + "TS2352": 2 + }, + "apps/sim/lib/knowledge/application/slack-search/onboarding.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/knowledge/application/slack-search/setup.test.ts": { + "TS2352": 2 + }, + "apps/sim/lib/knowledge/application/slack-search/stop.test.ts": { + "TS2352": 2 + }, + "apps/sim/lib/knowledge/application/tags.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/knowledge/chunks/keyset-sql.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/knowledge/connectors/connector-error.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/connectors/directory-queue.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/knowledge/connectors/google-company-scheduler.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/knowledge/connectors/member-observations.test.ts": { + "TS2554": 1 + }, + "apps/sim/lib/knowledge/connectors/member-provisioning.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/knowledge/connectors/member-sync-engine.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/knowledge/connectors/sync-content-pass.test.ts": { + "TS2345": 1, + "TS2741": 1 + }, + "apps/sim/lib/knowledge/connectors/sync-engine.test.ts": { + "TS2322": 2, + "TS2345": 14, + "TS2739": 1, + "TS2741": 3 + }, + "apps/sim/lib/knowledge/connectors/sync-persistence.test.ts": { + "TS2345": 2, + "TS2352": 1, + "TS2769": 1 + }, + "apps/sim/lib/knowledge/documents/document-indexing-usage.test.ts": { + "TS2345": 2, + "TS2739": 2 + }, + "apps/sim/lib/knowledge/documents/document-processing-source.test.ts": { + "TS2345": 4, + "TS2352": 1, + "TS2493": 2, + "TS2532": 1 + }, + "apps/sim/lib/knowledge/documents/processing-lane.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/knowledge/documents/processing-payload.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/knowledge/documents/processing-provider-continuation.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/knowledge/documents/processing-queue.test.ts": { + "TS2345": 4, + "TS2532": 1 + }, + "apps/sim/lib/knowledge/documents/processing-recovery-queue-transport.test.ts": { + "TS2540": 2 + }, + "apps/sim/lib/knowledge/documents/processing-recovery-queue.test.ts": { + "TS2540": 2 + }, + "apps/sim/lib/knowledge/documents/retry-processing-grace.test.ts": { + "TS2554": 1, + "TS2739": 2 + }, + "apps/sim/lib/knowledge/documents/service.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/knowledge/documents/storage-cleanup.test.ts": { + "TS18046": 1, + "TS18048": 1, + "TS2345": 1, + "TS2493": 1 + }, + "apps/sim/lib/knowledge/documents/workspace-source-provenance.test.ts": { + "TS2339": 1, + "TS2345": 4, + "TS2493": 1 + }, + "apps/sim/lib/knowledge/mcp/route-handler.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/orchestration/connector-access.test.ts": { + "TS2345": 1, + "TS2741": 3 + }, + "apps/sim/lib/knowledge/orchestration/connectors.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/knowledge/orchestration/documents.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/knowledge/projection/enqueue.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/knowledge/reranker.test.ts": { + "TS2540": 2 + }, + "apps/sim/lib/knowledge/search/diagnostics.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/knowledge/search/prewarm.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/knowledge/search/queries.test.ts": { + "TS2345": 4, + "TS2493": 1, + "TS2554": 1, + "TS2739": 1, + "TS2740": 3, + "TS7006": 4 + }, + "apps/sim/lib/knowledge/search/snippet.test.ts": { + "TS2550": 1 + }, + "apps/sim/lib/knowledge/service.test.ts": { + "TS2322": 1, + "TS2353": 1, + "TS2769": 1 + }, + "apps/sim/lib/knowledge/vector-columns.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/logs/api/route-policies.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/logs/application/read-execution-snapshot.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/logs/execution/logger.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/lib/logs/execution/logging-session.test.ts": { + "TS2322": 5, + "TS2345": 1, + "TS2741": 3 + }, + "apps/sim/lib/logs/execution/pii-large-values.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/logs/execution/trace-secret-projection.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/logs/execution/trace-spans/trace-spans.test.ts": { + "TS2741": 8 + }, + "apps/sim/lib/logs/fetch-log-detail.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/logs/folder-scope.test.ts": { + "TS2559": 2 + }, + "apps/sim/lib/mcp/application/execute-managed-tool.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mcp/application/execute-tool.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mcp/application/operation-access.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mcp/application/operations.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mcp/application/use-cases.test.ts": { + "TS2322": 9, + "TS2345": 4 + }, + "apps/sim/lib/mcp/client.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/mcp/connection-manager.test.ts": { + "TS2345": 9 + }, + "apps/sim/lib/mcp/middleware.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/lib/mcp/oauth/coordinated-fetch.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mcp/service-pool.test.ts": { + "TS2322": 1, + "TS2345": 3 + }, + "apps/sim/lib/mcp/service.test.ts": { + "TS2345": 1, + "TS2556": 1 + }, + "apps/sim/lib/mcp/tool-validation.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/memory/agent-turn-session.test.ts": { + "TS2741": 4 + }, + "apps/sim/lib/memory/message-provenance.test.ts": { + "TS18048": 2, + "TS2493": 1, + "TS4104": 1 + }, + "apps/sim/lib/memory/replay-provenance.test.ts": { + "TS2339": 1, + "TS2741": 1 + }, + "apps/sim/lib/memory/retrieval.test.ts": { + "TS2322": 2, + "TS2345": 1 + }, + "apps/sim/lib/messaging/email/mailer.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/messaging/email/providers/gmail.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mothership/agent-cli/engines/file-read.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/mothership/agent-cli/engines/lint-scope.test.ts": { + "TS2322": 1, + "TS2345": 1 + }, + "apps/sim/lib/mothership/agent-cli/engines/universal-grep.test.ts": { + "TS2550": 6 + }, + "apps/sim/lib/mothership/agent-cli/engines/workflow-inputs.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/agent-cli/file-provenance.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/mothership/agent-cli/file-round-trip-provenance.test.ts": { + "TS18048": 4, + "TS2345": 1, + "TS2493": 1 + }, + "apps/sim/lib/mothership/agent-cli/file-upload-origin.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mothership/agent-cli/saved-run-read.live.test.ts": { + "TS2741": 7, + "TS2769": 1 + }, + "apps/sim/lib/mothership/agent-cli/services.test.ts": { + "TS2345": 2, + "TS2353": 1 + }, + "apps/sim/lib/mothership/application/execute-table-use-case.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/application/execute-workflow-use-case.test.ts": { + "TS2820": 1 + }, + "apps/sim/lib/mothership/block-visibility.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mothership/chat/lifecycle.test.ts": { + "TS2571": 1 + }, + "apps/sim/lib/mothership/chat/messages-store.test.ts": { + "TS18048": 7, + "TS2352": 1, + "TS2493": 2 + }, + "apps/sim/lib/mothership/chat/payload.test.ts": { + "TS2322": 3, + "TS2345": 1, + "TS2353": 1 + }, + "apps/sim/lib/mothership/chat/persisted-message.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/mothership/chat/post.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2550": 2 + }, + "apps/sim/lib/mothership/chat/process-contents.test.ts": { + "TS2322": 6, + "TS2345": 1 + }, + "apps/sim/lib/mothership/chat/terminal-state.test.ts": { + "TS18046": 2, + "TS2571": 1 + }, + "apps/sim/lib/mothership/inbox/executor.test.ts": { + "TS2353": 4 + }, + "apps/sim/lib/mothership/request/application/read-control.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/request/context/result.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/mothership/request/go/file-preview-adapter.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/request/handlers/handlers.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/mothership/request/lifecycle/stream-retry.test.ts": { + "TS2341": 2 + }, + "apps/sim/lib/mothership/request/session/buffer.test.ts": { + "TS2339": 4, + "TS2698": 1 + }, + "apps/sim/lib/mothership/request/session/event.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/mothership/request/session/recovery.test.ts": { + "TS2532": 2 + }, + "apps/sim/lib/mothership/request/session/writer.test.ts": { + "TS2345": 1, + "TS7006": 1 + }, + "apps/sim/lib/mothership/request/tools/desktop-wait.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mothership/request/tools/executor.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2741": 8 + }, + "apps/sim/lib/mothership/request/tools/permission.test.ts": { + "TS2339": 3 + }, + "apps/sim/lib/mothership/request/tools/workflow-client-fallback.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/mothership/request/tools/workflow-context.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/resources/search.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/mothership/tasks/wake.test.ts": { + "TS18046": 2 + }, + "apps/sim/lib/mothership/tool-executor/executor.test.ts": { + "TS2345": 3, + "TS2741": 3 + }, + "apps/sim/lib/mothership/tools/client/completion.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/mothership/tools/client/run-tool-execution.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/mothership/tools/handlers/function-execute-file-mounts.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/mothership/tools/handlers/function-execute-provenance.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/mothership/tools/handlers/function-execute-table-mounts.test.ts": { + "TS2741": 2 + }, + "apps/sim/lib/mothership/tools/handlers/workbench-confidentiality.live.test.ts": { + "TS2339": 1, + "TS2345": 3, + "TS2769": 1 + }, + "apps/sim/lib/mothership/tools/handlers/workflow/mutations.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/tools/handlers/workflow/withheld-run-result.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/mothership/tools/server/files/doc-compile.test.ts": { + "TS2322": 3 + }, + "apps/sim/lib/mothership/tools/server/files/doc-servable.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/mothership/tools/server/knowledge/workspace-search.test.ts": { + "TS18046": 1 + }, + "apps/sim/lib/mothership/tools/server/workspaces.test.ts": { + "TS2345": 1, + "TS2352": 1 + }, + "apps/sim/lib/mothership/vfs/operations.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/oauth/github-repositories.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/oauth/oauth.test.ts": { + "TS2348": 1, + "TS2353": 2 + }, + "apps/sim/lib/oauth/token-resolution.test.ts": { + "TS2739": 3 + }, + "apps/sim/lib/organizations/instance-org.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/organizations/members/lifecycle.test.ts": { + "TS2345": 6 + }, + "apps/sim/lib/permission-groups/application/group-membership.test.ts": { + "TS2345": 6 + }, + "apps/sim/lib/permission-groups/config-scope.server.test.ts": { + "TS2739": 3 + }, + "apps/sim/lib/permission-groups/group-manager.test.ts": { + "TS2550": 2 + }, + "apps/sim/lib/permission-groups/mutation.test.ts": { + "TS2550": 1 + }, + "apps/sim/lib/pinned-items/resources.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/posthog/server.test.ts": { + "TS2769": 2 + }, + "apps/sim/lib/pptx-renderer/renderer/echarts-runtime-render.test.ts": { + "TS2341": 1 + }, + "apps/sim/lib/secrets/usage/record.test.ts": { + "TS18048": 2, + "TS2339": 2, + "TS2493": 3, + "TS2532": 1 + }, + "apps/sim/lib/selectors/manifest.test.ts": { + "TS2339": 3 + }, + "apps/sim/lib/selectors/server/integration-access.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/settings/application/workspace-section-access.test.ts": { + "TS2345": 1, + "TS2739": 3 + }, + "apps/sim/lib/sim-search/connectors.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/sim-search/live/application.test.ts": { + "TS2345": 1, + "TS2353": 1 + }, + "apps/sim/lib/sim-search/live/discussion-reads.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/sim-search/live/scoped-search.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/skills/access.test.ts": { + "TS2367": 1 + }, + "apps/sim/lib/slack-search/shared-app.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/table/api/route-policies.test.ts": { + "TS18047": 2 + }, + "apps/sim/lib/table/application/columns.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/table/application/exports.test.ts": { + "TS2322": 2, + "TS2741": 1 + }, + "apps/sim/lib/table/application/groups.test.ts": { + "TS2345": 1, + "TS2741": 1 + }, + "apps/sim/lib/table/application/operations.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/table/application/rows.test.ts": { + "TS2322": 4, + "TS2345": 1, + "TS2352": 1, + "TS2353": 2, + "TS2493": 1, + "TS2739": 5, + "TS2741": 1 + }, + "apps/sim/lib/table/application/runs.test.ts": { + "TS2345": 2, + "TS2353": 1 + }, + "apps/sim/lib/table/application/tables.test.ts": { + "TS2322": 1, + "TS2741": 1 + }, + "apps/sim/lib/table/bulk-update-concurrency.test.ts": { + "TS2739": 2 + }, + "apps/sim/lib/table/delete-runner.test.ts": { + "TS2502": 1 + }, + "apps/sim/lib/table/dispatch-governed-subject.test.ts": { + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/lib/table/dispatcher.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/table/events.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/table/jobs/service.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/table/orchestration/import.test.ts": { + "TS2698": 4 + }, + "apps/sim/lib/table/rows/bulk-update-patch-validation.test.ts": { + "TS2353": 4 + }, + "apps/sim/lib/table/rows/cursor.test.ts": { + "TS2322": 10 + }, + "apps/sim/lib/table/rows/executions.test.ts": { + "TS2352": 2, + "TS2493": 4 + }, + "apps/sim/lib/table/rows/secret-provenance.test.ts": { + "TS2493": 4 + }, + "apps/sim/lib/table/run-column-governed-subject.test.ts": { + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/lib/table/secret-provenance-selection.test.ts": { + "TS18046": 1, + "TS2345": 3, + "TS2741": 1, + "TS7006": 1 + }, + "apps/sim/lib/table/service-filter-threading.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/table/sql.test.ts": { + "TS2352": 2, + "TS2353": 4 + }, + "apps/sim/lib/table/update-row.test.ts": { + "TS18047": 2, + "TS2493": 1, + "TS2739": 7, + "TS2741": 2 + }, + "apps/sim/lib/table/views/service.test.ts": { + "TS2322": 5, + "TS2352": 1 + }, + "apps/sim/lib/table/workflow-columns.test.ts": { + "TS2741": 4 + }, + "apps/sim/lib/table/workflow-groups/service.test.ts": { + "TS2352": 2, + "TS2493": 2 + }, + "apps/sim/lib/terminal/transport.test.ts": { + "TS2322": 5, + "TS2352": 2, + "TS2493": 2 + }, + "apps/sim/lib/tool-execution/application/execute-tool.test.ts": { + "TS2322": 1, + "TS2741": 1 + }, + "apps/sim/lib/uploads/client/download.test.ts": { + "TS2550": 1, + "TS2683": 1, + "TS2741": 1 + }, + "apps/sim/lib/uploads/client/upload-session.test.ts": { + "TS2322": 7 + }, + "apps/sim/lib/uploads/contexts/execution/execution-file-manager.test.ts": { + "TS2339": 4, + "TS2493": 3, + "TS2698": 3 + }, + "apps/sim/lib/uploads/contexts/organization-logo/application.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/uploads/core/storage-service.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/uploads/providers/blob/client.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/uploads/providers/google-cloud-storage/client.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/uploads/providers/s3/client.test.ts": { + "TS2345": 7 + }, + "apps/sim/lib/uploads/server/heic.test.ts": { + "TS7016": 1 + }, + "apps/sim/lib/uploads/server/metadata.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/uploads/upload-session/service.test.ts": { + "TS18048": 4, + "TS2339": 2, + "TS2345": 1, + "TS2493": 3, + "TS2532": 1 + }, + "apps/sim/lib/uploads/utils/fetch-external-url.server.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/uploads/utils/model-input.test.ts": { + "TS2339": 1, + "TS2345": 1, + "TS2739": 1, + "TS2741": 1 + }, + "apps/sim/lib/uploads/utils/user-file-base64.server.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/users/account-deletion.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/users/application/authorized-apps.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/users/application/preferences.test.ts": { + "TS18048": 1, + "TS2493": 1 + }, + "apps/sim/lib/webhooks/deploy.test.ts": { + "TS2740": 1 + }, + "apps/sim/lib/webhooks/polling/google-calendar.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/webhooks/polling/rss.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/webhooks/processor.test.ts": { + "TS2322": 2, + "TS2740": 4 + }, + "apps/sim/lib/webhooks/providers/ashby.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/webhooks/providers/bitbucket.test.ts": { + "TS2698": 1, + "TS7053": 1 + }, + "apps/sim/lib/webhooks/providers/checkr.test.ts": { + "TS2339": 4 + }, + "apps/sim/lib/webhooks/providers/emailbison.test.ts": { + "TS2344": 1, + "TS2722": 2 + }, + "apps/sim/lib/webhooks/providers/github.test.ts": { + "TS2339": 1 + }, + "apps/sim/lib/webhooks/providers/gmail.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/webhooks/providers/grain.test.ts": { + "TS2344": 1 + }, + "apps/sim/lib/webhooks/providers/granola.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/webhooks/providers/microsoft-teams.test.ts": { + "TS2339": 2 + }, + "apps/sim/lib/webhooks/providers/quickbooks.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/webhooks/providers/slack.test.ts": { + "TS2531": 1, + "TS2739": 6 + }, + "apps/sim/lib/webhooks/providers/twilio.test.ts": { + "TS2353": 1, + "TS2739": 1 + }, + "apps/sim/lib/webhooks/providers/whatsapp.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/webhooks/providers/zoho-desk.test.ts": { + "TS2739": 1 + }, + "apps/sim/lib/webhooks/slack-execution-stream.test.ts": { + "TS2339": 1, + "TS2550": 1, + "TS2741": 4 + }, + "apps/sim/lib/workflows/application/list-workflow-runs.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/application/operations.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/workflows/application/read-workflow-graph.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/application/read-workflow-lint-refs.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/application/replace-workflow-state.test.ts": { + "TS2322": 4 + }, + "apps/sim/lib/workflows/application/resolve-workflow-outputs.test.ts": { + "TS2322": 3 + }, + "apps/sim/lib/workflows/application/run-workflow-from-copilot.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/blocks/canvas-sentence-validation.test.ts": { + "TS2741": 6 + }, + "apps/sim/lib/workflows/comparison/compare.test.ts": { + "TS2739": 1, + "TS2741": 14 + }, + "apps/sim/lib/workflows/comparison/format-description.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/comparison/normalize.test.ts": { + "TS2322": 2, + "TS2741": 1 + }, + "apps/sim/lib/workflows/comparison/redact.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/workflows/custom-blocks/child-execution.test.ts": { + "TS2339": 5 + }, + "apps/sim/lib/workflows/dynamic-handle-topology.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/workflows/editing/operations.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/workflows/editing/validation.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/executor/execute-service.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/workflows/executor/execute-workflow.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/workflows/executor/execution-core.test.ts": { + "TS2352": 2, + "TS2739": 5 + }, + "apps/sim/lib/workflows/executor/execution-status.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/workflows/executor/human-in-the-loop-manager.test.ts": { + "TS2493": 2, + "TS2554": 2 + }, + "apps/sim/lib/workflows/migrations/subblock-migrations.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/operations/export-workflow.test.ts": { + "TS18047": 1, + "TS7053": 1 + }, + "apps/sim/lib/workflows/operations/import-export-roundtrip.test.ts": { + "TS2339": 1, + "TS2352": 1 + }, + "apps/sim/lib/workflows/persistence/deployment-operations.test.ts": { + "TS2493": 1 + }, + "apps/sim/lib/workflows/persistence/duplicate.test.ts": { + "TS2493": 1 + }, + "apps/sim/lib/workflows/persistence/persist-block-access-gate.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/workflows/persistence/utils.test.ts": { + "TS2493": 2 + }, + "apps/sim/lib/workflows/references/dependent-reconfigs.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/references/import-configuration.test.ts": { + "TS2345": 3, + "TS2353": 1 + }, + "apps/sim/lib/workflows/references/import-plan.test.ts": { + "TS2345": 7 + }, + "apps/sim/lib/workflows/references/manifest.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/workflows/references/remap-references.test.ts": { + "TS2820": 1 + }, + "apps/sim/lib/workflows/response-security.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/sanitization/subblocks.test.ts": { + "TS2352": 1 + }, + "apps/sim/lib/workflows/search-replace/indexer.test.ts": { + "TS2322": 29 + }, + "apps/sim/lib/workflows/search-replace/replacements.test.ts": { + "TS2322": 6 + }, + "apps/sim/lib/workflows/streaming/nested-output-options.test.ts": { + "TS2769": 1 + }, + "apps/sim/lib/workflows/streaming/resolve-output-selectors.test.ts": { + "TS2322": 1 + }, + "apps/sim/lib/workflows/streaming/streaming.test.ts": { + "TS2741": 1 + }, + "apps/sim/lib/workflows/subblocks/visibility.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/workspace-events/rules.test.ts": { + "TS2353": 1 + }, + "apps/sim/lib/workspace-files/application/download-workspace-file-items.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/workspace-files/application/edit-workspace-file-content.test.ts": { + "TS2345": 1, + "TS2741": 1 + }, + "apps/sim/lib/workspace-files/application/file-versions.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/workspace-files/application/list-workspace-files.test.ts": { + "TS2322": 2 + }, + "apps/sim/lib/workspace-files/application/operations.test.ts": { + "TS2345": 2 + }, + "apps/sim/lib/workspace-files/application/read-stored-workspace-file-record-by-key.test.ts": { + "TS2322": 1, + "TS2339": 1 + }, + "apps/sim/lib/workspace-files/application/update-workspace-file-content.test.ts": { + "TS2345": 3 + }, + "apps/sim/lib/workspace-files/page-document.server.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/workspace-files/queries.test.ts": { + "TS2488": 1 + }, + "apps/sim/lib/workspace-files/search/admission.test.ts": { + "TS2550": 1 + }, + "apps/sim/lib/workspace-files/search/dispatcher.test.ts": { + "TS2345": 1, + "TS2493": 4, + "TS2550": 1, + "TS7031": 1 + }, + "apps/sim/lib/workspace-files/search/regex.test.ts": { + "TS2550": 1 + }, + "apps/sim/lib/workspace-files/search/repository.test.ts": { + "TS2493": 1, + "TS2550": 1 + }, + "apps/sim/lib/workspaces/admin-move.test.ts": { + "TS2493": 1 + }, + "apps/sim/lib/workspaces/application/manage-permissions.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/workspaces/application/remove-member.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/workspaces/create.test.ts": { + "TS2345": 1 + }, + "apps/sim/lib/workspaces/policy.test.ts": { + "TS2345": 4 + }, + "apps/sim/lib/workspaces/public-queries.test.ts": { + "TS2352": 1, + "TS2493": 1 + }, + "apps/sim/providers/__fixtures__/anthropic/fixtures.test.ts": { + "TS2339": 1, + "TS2345": 7 + }, + "apps/sim/providers/anthropic/core.test.ts": { + "TS2353": 3, + "TS2740": 5 + }, + "apps/sim/providers/anthropic/streaming-tool-loop.test.ts": { + "TS4104": 1 + }, + "apps/sim/providers/anthropic/utils.test.ts": { + "TS2345": 1 + }, + "apps/sim/providers/attachments.test.ts": { + "TS2769": 2 + }, + "apps/sim/providers/azure-openai/index.test.ts": { + "TS2741": 2 + }, + "apps/sim/providers/baseten/index.test.ts": { + "TS2741": 1 + }, + "apps/sim/providers/bedrock/index.test.ts": { + "TS2345": 2, + "TS2353": 3 + }, + "apps/sim/providers/bedrock/streaming-tool-loop.test.ts": { + "TS2339": 1 + }, + "apps/sim/providers/conversation-generation.test.ts": { + "TS2345": 1 + }, + "apps/sim/providers/conversation-smoke.live.test.ts": { + "TS18048": 2 + }, + "apps/sim/providers/conversation-summary.test.ts": { + "TS2345": 1 + }, + "apps/sim/providers/deepseek/index.test.ts": { + "TS2353": 1 + }, + "apps/sim/providers/fireworks/index.test.ts": { + "TS2741": 1 + }, + "apps/sim/providers/gemini/core.streaming.test.ts": { + "TS2353": 3 + }, + "apps/sim/providers/gemini/core.test.ts": { + "TS2353": 3, + "TS2741": 1 + }, + "apps/sim/providers/groq/index.test.ts": { + "TS18046": 1, + "TS2345": 1, + "TS2353": 1, + "TS2739": 2 + }, + "apps/sim/providers/index.test.ts": { + "TS2322": 4, + "TS2339": 2, + "TS2353": 4, + "TS2741": 3 + }, + "apps/sim/providers/kie/index.test.ts": { + "TS2353": 1 + }, + "apps/sim/providers/litellm/index.test.ts": { + "TS7006": 2 + }, + "apps/sim/providers/mistral/index.test.ts": { + "TS2339": 6, + "TS2345": 2, + "TS2352": 1 + }, + "apps/sim/providers/nebius/index.live.test.ts": { + "TS2339": 1 + }, + "apps/sim/providers/ollama/index.test.ts": { + "TS2339": 4, + "TS7006": 2 + }, + "apps/sim/providers/openai-compat/streaming-tool-loop.test.ts": { + "TS2345": 1, + "TS2352": 1, + "TS2353": 1, + "TS2493": 1 + }, + "apps/sim/providers/openai/core.response-status.test.ts": { + "TS18046": 1, + "TS2353": 1 + }, + "apps/sim/providers/openrouter/index.test.ts": { + "TS18046": 1 + }, + "apps/sim/providers/runtime-context.test.ts": { + "TS2554": 7 + }, + "apps/sim/providers/settled-tool-streams.test.ts": { + "TS2322": 2, + "TS2345": 1, + "TS2353": 1 + }, + "apps/sim/providers/specialist-reasoning.test.ts": { + "TS2322": 1, + "TS2345": 1, + "TS2739": 1 + }, + "apps/sim/providers/streaming-execution.test.ts": { + "TS2322": 4 + }, + "apps/sim/providers/together/index.test.ts": { + "TS18046": 1, + "TS2741": 1 + }, + "apps/sim/providers/transport.test.ts": { + "TS2339": 1 + }, + "apps/sim/providers/utils.test.ts": { + "TS2345": 2, + "TS2353": 2, + "TS2554": 20 + }, + "apps/sim/providers/vllm/index.test.ts": { + "TS18046": 1, + "TS2339": 8 + }, + "apps/sim/providers/xai/billing.test.ts": { + "TS2353": 3 + }, + "apps/sim/providers/xai/index.test.ts": { + "TS18046": 1, + "TS2322": 1, + "TS2353": 1 + }, + "apps/sim/serializer/private-inputs.test.ts": { + "TS2352": 1 + }, + "apps/sim/stores/reset-all-stores.test.ts": { + "TS2345": 1 + }, + "apps/sim/stores/terminal/console/store.test.ts": { + "TS2322": 1 + }, + "apps/sim/stores/undo-redo/utils.test.ts": { + "TS2345": 1 + }, + "apps/sim/stores/workflows/workflow/store.test.ts": { + "TS2339": 1 + }, + "apps/sim/tools/ashby/ashby.live.test.ts": { + "TS2345": 25 + }, + "apps/sim/tools/ashby/ashby.test.ts": { + "TS2339": 5, + "TS2345": 57 + }, + "apps/sim/tools/assistant-execution.test.ts": { + "TS2554": 2 + }, + "apps/sim/tools/binary-downloads.test.ts": { + "TS2345": 1, + "TS2554": 1 + }, + "apps/sim/tools/bitbucket/pipelines.test.ts": { + "TS2322": 1, + "TS2352": 1 + }, + "apps/sim/tools/circleback/circleback.test.ts": { + "TS2352": 4 + }, + "apps/sim/tools/cloudflare/cloudflare.test.ts": { + "TS2339": 44, + "TS2352": 1, + "TS7053": 5 + }, + "apps/sim/tools/databricks/databricks.test.ts": { + "TS2532": 1 + }, + "apps/sim/tools/datadog/datadog.test.ts": { + "TS2349": 2 + }, + "apps/sim/tools/daytona/sandbox_path_safety.test.ts": { + "TS2352": 1 + }, + "apps/sim/tools/dynatrace/dynatrace.test.ts": { + "TS2322": 16 + }, + "apps/sim/tools/enrow-hosting.test.ts": { + "TS2345": 8, + "TS2352": 3 + }, + "apps/sim/tools/falai-hosting.test.ts": { + "TS2739": 2 + }, + "apps/sim/tools/file-message-operation-security.test.ts": { + "TS2345": 2 + }, + "apps/sim/tools/file-message-operations.test.ts": { + "TS2322": 2 + }, + "apps/sim/tools/file-message-provider-clients.test.ts": { + "TS2345": 1 + }, + "apps/sim/tools/file/search.test.ts": { + "TS18048": 1, + "TS2722": 1 + }, + "apps/sim/tools/github/branch_protection_and_workflow_runs.test.ts": { + "TS2352": 1 + }, + "apps/sim/tools/github/create_pr_review.test.ts": { + "TS18048": 1, + "TS2339": 1 + }, + "apps/sim/tools/github/list_review_threads.test.ts": { + "TS2322": 3 + }, + "apps/sim/tools/gitlab/access.test.ts": { + "TS2349": 5 + }, + "apps/sim/tools/gitlab/groups.test.ts": { + "TS2349": 7 + }, + "apps/sim/tools/gmail/read.test.ts": { + "TS2741": 1 + }, + "apps/sim/tools/harmonic/harmonic.test.ts": { + "TS2345": 1, + "TS2739": 5, + "TS2741": 8 + }, + "apps/sim/tools/hunter/hunter.test.ts": { + "TS2352": 2 + }, + "apps/sim/tools/index.test.ts": { + "TS2339": 2, + "TS2345": 3, + "TS2550": 1, + "TS2741": 1, + "TS7031": 1 + }, + "apps/sim/tools/jotform/jotform.test.ts": { + "TS2352": 15 + }, + "apps/sim/tools/knowledge/knowledge.test.ts": { + "TS2322": 2, + "TS2339": 6 + }, + "apps/sim/tools/linkedin/share_post.test.ts": { + "TS2345": 5 + }, + "apps/sim/tools/llm/chat.test.ts": { + "TS2739": 1 + }, + "apps/sim/tools/logfire/get_trace.test.ts": { + "TS2349": 1 + }, + "apps/sim/tools/managed_agent/list_events.test.ts": { + "TS2352": 3 + }, + "apps/sim/tools/managed_agent/respond_tool_confirmation.test.ts": { + "TS2741": 2 + }, + "apps/sim/tools/microsoft_ad/add_user_app_role_assignment.test.ts": { + "TS2352": 1 + }, + "apps/sim/tools/microsoft_ad/list_user_devices.test.ts": { + "TS2352": 1 + }, + "apps/sim/tools/microsoft_dynamics_365/dynamics_crm.test.ts": { + "TS2339": 2, + "TS2532": 2 + }, + "apps/sim/tools/modal/call_function.test.ts": { + "TS2345": 4 + }, + "apps/sim/tools/modal/chat_completion.test.ts": { + "TS2741": 1 + }, + "apps/sim/tools/model-input-selectors.test.ts": { + "TS2739": 2 + }, + "apps/sim/tools/nested-model-input-adapters.test.ts": { + "TS2345": 1, + "TS2739": 2 + }, + "apps/sim/tools/netsuite/netsuite.test.ts": { + "TS18048": 1 + }, + "apps/sim/tools/notion/responses.test.ts": { + "TS2532": 3 + }, + "apps/sim/tools/okta/tools.test.ts": { + "TS2345": 17, + "TS2349": 7 + }, + "apps/sim/tools/opaque-model-input-selectors.test.ts": { + "TS2722": 4 + }, + "apps/sim/tools/params.test.ts": { + "TS2345": 5 + }, + "apps/sim/tools/pitchbook/pitchbook.test.ts": { + "TS2532": 3 + }, + "apps/sim/tools/quickbooks/api_accuracy.test.ts": { + "TS2339": 4, + "TS2349": 1, + "TS2677": 1, + "TS2769": 4 + }, + "apps/sim/tools/quickbooks/purchasing_utils.test.ts": { + "TS2345": 3, + "TS2741": 1, + "TS2820": 1 + }, + "apps/sim/tools/quickbooks/sales_utils.test.ts": { + "TS2345": 5, + "TS2349": 2, + "TS2741": 12 + }, + "apps/sim/tools/semrush/semrush.test.ts": { + "TS2345": 5 + }, + "apps/sim/tools/serper/search.test.ts": { + "TS2352": 1 + }, + "apps/sim/tools/servicenow/servicenow.test.ts": { + "TS2345": 13, + "TS7053": 1 + }, + "apps/sim/tools/slack/agent_sessions.test.ts": { + "TS2349": 1 + }, + "apps/sim/tools/slack/canvas.test.ts": { + "TS2739": 13 + }, + "apps/sim/tools/slack/list_channels.test.ts": { + "TS2353": 3 + }, + "apps/sim/tools/slack_lists/operations.test.ts": { + "TS2345": 2 + }, + "apps/sim/tools/snowflake/sql.test.ts": { + "TS18048": 3 + }, + "apps/sim/tools/snowflake/utils.test.ts": { + "TS18048": 2, + "TS2339": 1, + "TS2741": 16, + "TS7006": 1 + }, + "apps/sim/tools/splunk/requests.test.ts": { + "TS2345": 3, + "TS2349": 5, + "TS2352": 1 + }, + "apps/sim/tools/sqs/contract-guards.test.ts": { + "TS18048": 14 + }, + "apps/sim/tools/square/idempotency.test.ts": { + "TS18046": 4 + }, + "apps/sim/tools/table/response.test.ts": { + "TS7053": 1 + }, + "apps/sim/tools/tinyfish/tinyfish.test.ts": { + "TS2352": 2 + }, + "apps/sim/tools/vercel/edge_config_path_safety.test.ts": { + "TS2322": 4 + }, + "apps/sim/tools/whatsapp/whatsapp.test.ts": { + "TS2349": 1 + }, + "apps/sim/tools/zoho_desk/list_tickets.test.ts": { + "TS2352": 2 + }, + "apps/sim/tools/zoho_desk/update_ticket.test.ts": { + "TS2352": 1 + }, + "apps/sim/triggers/greenhouse/utils.test.ts": { + "TS2739": 2 + }, + "apps/sim/triggers/vercel/utils.test.ts": { + "TS2739": 1 + } +} diff --git a/scripts/check-test-types.test.ts b/scripts/check-test-types.test.ts new file mode 100644 index 00000000000..d85e95332b4 --- /dev/null +++ b/scripts/check-test-types.test.ts @@ -0,0 +1,378 @@ +import { spawnSync } from 'node:child_process' +import { + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs' +import path from 'node:path' +import { + compareCounts, + countErrors, + parseCompilerOutput, + parseCounts, + shrinkBaseline, +} from '@scripts/check-test-types' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' + +const ROOT = '/repo' +const APP = '/repo/apps/sim' + +function counts(output: string) { + return countErrors(parseCompilerOutput(output, APP, ROOT).errors) +} + +describe('parseCompilerOutput', () => { + it.each([ + { + name: 'a route group and a dynamic segment stay in the path', + output: "app/(landing)/[slug]/page.test.tsx(12,3): error TS2322: Type 'a' is not 'b'.", + expected: { 'apps/sim/app/(landing)/[slug]/page.test.tsx': { TS2322: 1 } }, + }, + { + name: 'a file outside the app resolves against where tsc ran', + output: '../../packages/testing/src/mocks/db.ts(4,1): error TS2307: Cannot find module.', + expected: { 'packages/testing/src/mocks/db.ts': { TS2307: 1 } }, + }, + { + name: 'an absolute path is made repo-relative', + output: '/repo/apps/sim/lib/a.test.ts(1,1): error TS2345: Bad argument.', + expected: { 'apps/sim/lib/a.test.ts': { TS2345: 1 } }, + }, + { + name: 'indented continuation lines belong to the error above, and codes count apart', + output: [ + "lib/a.test.ts(3,5): error TS2322: Type '{ a: 1 }' is not assignable to type 'B'.", + " Property 'b' is missing in type '{ a: 1 }' but required in type 'B'.", + ' lib/b.ts(9,2): error TS2322: quoted inside a message chain', + 'lib/a.test.ts(8,1): error TS2554: Expected 1 arguments, but got 0.', + 'lib/a.test.ts(9,1): error TS2554: Expected 1 arguments, but got 0.', + ].join('\n'), + expected: { 'apps/sim/lib/a.test.ts': { TS2322: 1, TS2554: 2 } }, + }, + { + name: 'CRLF output and blank lines', + output: 'lib/a.test.ts(1,1): error TS1: x\r\n\r\nlib/b.test.ts(2,2): error TS2: y\r\n', + expected: { 'apps/sim/lib/a.test.ts': { TS1: 1 }, 'apps/sim/lib/b.test.ts': { TS2: 1 } }, + }, + { + name: 'a message that itself quotes a location', + output: "lib/a.test.ts(1,1): error TS2300: Duplicate of 'lib/b.ts(2,2): error TS1: z'.", + expected: { 'apps/sim/lib/a.test.ts': { TS2300: 1 } }, + }, + ])('$name', ({ output, expected }) => { + expect(counts(output)).toEqual(expected) + }) + + it.each([ + ['a global diagnostic with no file', "error TS5083: Cannot read file '/repo/tsconfig.json'."], + ['a compiler crash', 'panic: runtime error: invalid memory address'], + ['a location whose category is not error', 'lib/a.test.ts(1,1): warning TS1: x'], + ])('leaves %s unplaced instead of counting it as zero errors', (_name, line) => { + const parsed = parseCompilerOutput(`lib/a.test.ts(1,1): error TS1: x\n${line}`, APP, ROOT) + expect(parsed.unplaced).toEqual([line]) + expect(countErrors(parsed.errors)).toEqual({ 'apps/sim/lib/a.test.ts': { TS1: 1 } }) + }) + + it.each([ + ['Found 2 errors in 1 file.', 2], + ['Found 1 error in lib/a.test.ts:1', 1], + ])('reads the summary %j as the compiler’s total', (line, total) => { + expect(parseCompilerOutput(line, APP, ROOT)).toMatchObject({ + reportedTotal: total, + unplaced: [], + }) + }) +}) + +describe('parseCounts', () => { + it.each([ + ['an array', '[]'], + ['null', 'null'], + ['a flat per-file count', '{"a.test.ts": 3}'], + ['a file with no codes', '{"a.test.ts": {}}'], + ['a key that is not a TS code', '{"a.test.ts": {"2322": 1}}'], + ['a zero count', '{"a.test.ts": {"TS2322": 0}}'], + ['a negative count', '{"a.test.ts": {"TS2322": -1}}'], + ['a fractional count', '{"a.test.ts": {"TS2322": 1.5}}'], + ['a string count', '{"a.test.ts": {"TS2322": "3"}}'], + ])('rejects %s', (_name, json) => { + expect(() => parseCounts(json, 'baseline')).toThrow(/baseline/) + }) + + it('accepts per-file, per-code positive integer counts', () => { + expect(parseCounts('{"a.test.ts": {"TS2322": 3}}', 'baseline')).toEqual({ + 'a.test.ts': { TS2322: 3 }, + }) + }) +}) + +describe('compareCounts', () => { + it.each([ + { + name: 'a new file with errors regresses from zero', + current: { 'a.test.ts': { TS2322: 1 } }, + baseline: {}, + regressed: [{ file: 'a.test.ts', code: 'TS2322', count: 1, baseline: 0 }], + shrunk: [], + }, + { + name: 'a rising count regresses', + current: { 'a.test.ts': { TS2322: 4 } }, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [{ file: 'a.test.ts', code: 'TS2322', count: 4, baseline: 3 }], + shrunk: [], + }, + { + name: 'an equal count passes', + current: { 'a.test.ts': { TS2322: 3 } }, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [], + shrunk: [], + }, + { + name: 'a falling count is stale', + current: { 'a.test.ts': { TS2322: 2 } }, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [], + shrunk: [{ file: 'a.test.ts', code: 'TS2322', count: 2, baseline: 3 }], + }, + { + name: 'a file with no errors left is stale', + current: {}, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [], + shrunk: [{ file: 'a.test.ts', code: 'TS2322', count: 0, baseline: 3 }], + }, + { + name: 'a new code in a file whose total stays flat regresses', + current: { 'a.test.ts': { TS2322: 2, TS2345: 1 } }, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [{ file: 'a.test.ts', code: 'TS2345', count: 1, baseline: 0 }], + shrunk: [{ file: 'a.test.ts', code: 'TS2322', count: 2, baseline: 3 }], + }, + { + name: 'a fix in one file does not pay for a new error in another', + current: { 'a.test.ts': { TS2322: 2 }, 'b.test.ts': { TS2322: 1 } }, + baseline: { 'a.test.ts': { TS2322: 3 } }, + regressed: [{ file: 'b.test.ts', code: 'TS2322', count: 1, baseline: 0 }], + shrunk: [{ file: 'a.test.ts', code: 'TS2322', count: 2, baseline: 3 }], + }, + ])('$name', ({ current, baseline, regressed, shrunk }) => { + expect(compareCounts(current, baseline)).toEqual({ regressed, shrunk }) + }) +}) + +describe('shrinkBaseline', () => { + it('keeps lowered counts and never raises or admits a file or code', () => { + expect( + shrinkBaseline( + { + 'lower.test.ts': { TS1: 1 }, + 'higher.test.ts': { TS1: 9 }, + 'new.test.ts': { TS1: 2 }, + 'same.test.ts': { TS1: 4, TS2: 1 }, + }, + { + 'lower.test.ts': { TS1: 3 }, + 'higher.test.ts': { TS1: 5 }, + 'gone.test.ts': { TS1: 7 }, + 'same.test.ts': { TS1: 4 }, + } + ) + ).toEqual({ + 'higher.test.ts': { TS1: 5 }, + 'lower.test.ts': { TS1: 1 }, + 'same.test.ts': { TS1: 4 }, + }) + }) +}) + +/** + * Runs the real script on a saved compiler output. The fixture sits under the repository's + * node_modules so the copied script resolves its `@sim/*` imports, and holds its own baseline. + */ +describe('check-test-types command', () => { + const REPO = path.resolve(import.meta.dirname, '..') + const BASELINE = { + 'apps/sim/lib/a.test.ts': { TS2322: 2 }, + 'apps/sim/lib/b.test.ts': { TS2554: 1 }, + } + const UNCHANGED = [ + 'lib/a.test.ts(1,1): error TS2322: Type mismatch.', + 'lib/a.test.ts(2,1): error TS2322: Type mismatch.', + 'lib/b.test.ts(3,1): error TS2554: Expected 1 arguments, but got 0.', + ] + let fixture: string + + beforeEach(() => { + fixture = mkdtempSync(path.join(REPO, 'node_modules/.test-types-')) + mkdirSync(path.join(fixture, 'scripts')) + for (const file of ['scripts/check-test-types.ts', 'scripts/local-bin.ts']) { + copyFileSync(path.join(REPO, file), path.join(fixture, file)) + } + writeFileSync(baselineFile(), `${JSON.stringify(BASELINE, null, 2)}\n`) + }) + + afterEach(() => { + rmSync(fixture, { recursive: true, force: true }) + }) + + function baselineFile() { + return path.join(fixture, 'scripts/check-test-types.baseline.json') + } + + /** Runs on `lines` with the status a finished compile of them would have recorded. */ + function run(lines: string[], ...args: string[]) { + const errorCount = lines.filter((line) => line.includes(': error TS')).length + return runWithStatus(lines, { exitCode: errorCount ? 2 : 0, errorCount }, ...args) + } + + /** `status: null` leaves `status.json` out, as a compile that never finished would. */ + function runWithStatus(lines: string[], status: unknown, ...args: string[]) { + const diagnostics = path.join(fixture, 'diagnostics.txt') + writeFileSync(diagnostics, lines.length ? `${lines.join('\n')}\n` : '') + if (status !== null) { + writeFileSync(path.join(fixture, 'status.json'), JSON.stringify(status)) + } + return spawnSync( + 'bun', + [path.join(fixture, 'scripts/check-test-types.ts'), '--diagnostics', diagnostics, ...args], + { cwd: fixture, encoding: 'utf8' } + ) + } + + it('passes unchanged counts and reports them in the baseline’s shape', () => { + const result = run(UNCHANGED, '--report', 'report') + expect(result.status, result.stderr).toBe(0) + expect(JSON.parse(readFileSync(path.join(fixture, 'report/counts.json'), 'utf8'))).toEqual( + BASELINE + ) + }) + + it.each([ + { + name: 'a rising count', + lines: [...UNCHANGED, 'lib/a.test.ts(9,1): error TS2322: Another mismatch.'], + listed: 'apps/sim/lib/a.test.ts TS2322: 3 (baseline 2)', + printed: 'apps/sim/lib/a.test.ts:9:1 TS2322 Another mismatch.', + unrelated: 'apps/sim/lib/b.test.ts:3:1', + }, + { + name: 'a new code that replaces a fixed error', + lines: [UNCHANGED[0], UNCHANGED[2], 'lib/a.test.ts(9,1): error TS2345: Bad argument.'], + listed: 'apps/sim/lib/a.test.ts TS2345: 1 (baseline 0)', + printed: 'apps/sim/lib/a.test.ts:9:1 TS2345 Bad argument.', + unrelated: 'apps/sim/lib/a.test.ts:1:1 TS2322', + }, + { + name: 'a new file', + lines: [...UNCHANGED, 'lib/c.test.ts(1,1): error TS2304: Cannot find name.'], + listed: 'apps/sim/lib/c.test.ts TS2304: 1 (baseline 0)', + printed: 'apps/sim/lib/c.test.ts:1:1 TS2304 Cannot find name.', + unrelated: 'apps/sim/lib/a.test.ts:1:1', + }, + ])('fails on $name and prints only the new error', ({ lines, listed, printed, unrelated }) => { + const result = run(lines) + expect(result.status).toBe(1) + expect(result.stderr).toContain('gained type errors') + expect(result.stderr).toContain(listed) + expect(result.stderr).toContain(printed) + expect(result.stderr).not.toContain(unrelated) + }) + + it('fails on a dropped count until the baseline is updated', () => { + const result = run(UNCHANGED.slice(1)) + expect(result.status).toBe(1) + expect(result.stderr).toContain('apps/sim/lib/a.test.ts TS2322: 1 (baseline 2)') + expect(result.stderr).toContain('--update') + expect(result.stderr).not.toContain('gained type errors') + }) + + it('refuses to raise the baseline on --update and leaves it untouched', () => { + const before = readFileSync(baselineFile(), 'utf8') + const result = run( + [UNCHANGED[0], UNCHANGED[2], 'lib/a.test.ts(9,1): error TS2345: Bad argument.'], + '--update' + ) + expect(result.status).toBe(1) + expect(result.stderr).toContain('refused to raise the baseline') + expect(result.stderr).toContain('apps/sim/lib/a.test.ts TS2345: 1 (baseline 0)') + expect(readFileSync(baselineFile(), 'utf8')).toBe(before) + }) + + it('shrinks the baseline on --update', () => { + const result = run([UNCHANGED[0]], '--update') + expect(result.status, result.stderr).toBe(0) + expect(JSON.parse(readFileSync(baselineFile(), 'utf8'))).toEqual({ + 'apps/sim/lib/a.test.ts': { TS2322: 1 }, + }) + }) + + it.each([ + ['a global diagnostic', "error TS5083: Cannot read file 'tsconfig.json'."], + ['a crash', 'panic: runtime error'], + ])('fails on %s without writing counts or touching the baseline', (_name, line) => { + const before = readFileSync(baselineFile(), 'utf8') + const result = run([...UNCHANGED, line], '--update', '--report', 'report') + expect(result.status).toBe(1) + expect(result.stderr).toContain('not a located error') + expect(result.stderr).toContain(line) + expect(existsSync(path.join(fixture, 'report/counts.json'))).toBe(false) + expect(readFileSync(baselineFile(), 'utf8')).toBe(before) + }) + + it.each([ + { + name: 'empty diagnostics with no recorded status', + lines: [], + status: null, + message: 'status.json is missing', + }, + { + name: 'empty diagnostics from a compile that exited with errors', + lines: [], + status: { exitCode: 2, errorCount: 3 }, + message: 'tsc exited with 2 but 0 errors were parsed', + }, + { + name: 'errors from a compile that exited clean', + lines: UNCHANGED, + status: { exitCode: 0, errorCount: 3 }, + message: 'tsc exited with 0 but 3 errors were parsed', + }, + { + name: 'truncated diagnostics', + lines: UNCHANGED.slice(1), + status: { exitCode: 2, errorCount: 3 }, + message: 'holds 2 errors but its compile printed 3', + }, + { + name: 'a crashed compile’s exit code', + lines: UNCHANGED, + status: { exitCode: 134, errorCount: 3 }, + message: 'is not { "exitCode"', + }, + { + name: 'a status with no error count', + lines: UNCHANGED, + status: { exitCode: 2 }, + message: 'is not { "exitCode"', + }, + ])('fails on $name and never updates the baseline', ({ lines, status, message }) => { + const before = readFileSync(baselineFile(), 'utf8') + const result = runWithStatus(lines, status, '--update') + expect(result.status).toBe(1) + expect(result.stderr).toContain(message) + expect(readFileSync(baselineFile(), 'utf8')).toBe(before) + }) + + it('fails when the summary disagrees with the parsed errors', () => { + const result = run([...UNCHANGED, 'Found 4 errors in 2 files.']) + expect(result.status).toBe(1) + expect(result.stderr).toContain('tsc reported 4 errors but 3 were parsed') + }) +}) diff --git a/scripts/check-test-types.ts b/scripts/check-test-types.ts new file mode 100644 index 00000000000..21305efd94f --- /dev/null +++ b/scripts/check-test-types.ts @@ -0,0 +1,399 @@ +#!/usr/bin/env bun +/** + * Ratchets type errors in apps/sim's unit tests down, per file and per error code. + * + * `apps/sim/tsconfig.json` excludes `*.test.ts(x)`, so `bun run type-check` never sees the ~3.4k + * test files, and they carry thousands of type errors nobody is asked to fix today. Without a + * gate, every new test can add more, and a test whose mocks no longer match the code they stand + * in for type-checks as fine as one that does. This check runs the native compiler (the root + * `tsc`, which `check:native-typecheck` pins to TypeScript 7) on `apps/sim/tsconfig.tests.json`, + * the app's config with the tests left in, counts errors per file and TS code, and compares the + * counts with `scripts/check-test-types.baseline.json` (`{ file: { "TS2322": n } }`). + * + * - A (file, code) count that rises fails, including a file's first error and a new code in a + * baselined file, so fixing one error cannot pay for a different kind of error in that file. + * - A count that drops fails until the baseline is rewritten, so the baseline only shrinks. + * - Output the parser cannot place (a config error with no file, a compiler crash) fails + * outright: it would otherwise read as fewer errors. + * + * The key stops at the code on purpose: line and column move with every edit above an error, and + * messages print types (`Type '{ id: string; … }'`) that change when an unrelated source type or + * the compiler's type printer does, so either would fail pull requests that added no error. + * + * It type-checks the whole app (about a minute on a 4 vCPU runner), so it is not one of the + * `check:audits`: CI runs it in its own `test-types` job (.github/workflows/checks.yml). Fixing a + * finding never needs a local run: the failing step prints each new error. + * + * Flags: + * - `--report ` writes `diagnostics.txt` (the compiler's output), `status.json` (its exit + * code and how many errors it printed, written only once those agree), and `counts.json` (the + * counts, in the baseline's shape) to ``. CI uploads it as the `test-types` artifact when + * the job fails. + * - `--diagnostics ` reads such a `diagnostics.txt` instead of running the compiler, and + * requires the `status.json` beside it: an empty or truncated file must never read as fewer + * errors, so the parse has to match the recorded exit code and error count. + * - `--update` rewrites the baseline, refusing to raise any count. A missing baseline is restored + * from git, never regenerated. + * + * Shrink the baseline after a fix, from a failed CI run's artifact (no local compile): + * gh run download -n test-types -D + * bun run scripts/check-test-types.ts --diagnostics /diagnostics.txt --update + * + * Run: `bun run check:test-types` + */ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { isRecordLike, toRecord } from '@sim/utils/object' +import { compareStrings } from '@sim/utils/string' +import { localBin } from './local-bin' + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const APP_DIR = path.join(ROOT, 'apps/sim') +const TSCONFIG = 'tsconfig.tests.json' +const BASELINE = path.join(ROOT, 'scripts/check-test-types.baseline.json') +/** Per regressed (file, code), so one file that stopped resolving an import cannot flood the log. */ +const MAX_PRINTED = 25 + +/** Error count per TS code, per repo-relative file. */ +type Counts = Record> + +interface LocatedError { + code: string + /** The error's first line, rewritten with its repo-relative path. */ + text: string +} + +interface ParsedOutput { + /** Errors keyed by repo-relative file. */ + errors: Map + /** Top-level lines that are not a located error: a global diagnostic, a crash, a new format. */ + unplaced: string[] + /** The compiler's own `Found N errors` total, when it printed one. */ + reportedTotal: number | null +} + +/** `file(line,col): error TS1234: message`; lazy so a route group's `(name)` stays in the path. */ +const LOCATED_ERROR = /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.*)$/ +const SUMMARY = /^Found (\d+) errors?\b/ +const CODE = /^TS\d+$/ + +/** + * Parses `tsc --pretty false` output. Paths are resolved against `cwd` (where the compiler ran) + * and made relative to `root`, so counts match however the compiler printed them. Continuation + * lines of a multi-line message are indented and belong to the error above them. + */ +export function parseCompilerOutput(output: string, cwd: string, root: string): ParsedOutput { + const errors = new Map() + const unplaced: string[] = [] + let reportedTotal: number | null = null + for (const line of output.split(/\r?\n/)) { + if (line.trim() === '' || /^\s/.test(line)) continue + const located = LOCATED_ERROR.exec(line) + if (located) { + const [, rawFile, row, column, code, message] = located + const file = path.relative(root, path.resolve(cwd, rawFile)).split(path.sep).join('/') + const list = errors.get(file) ?? [] + list.push({ code, text: `${file}:${row}:${column} ${code} ${message}` }) + errors.set(file, list) + continue + } + const summary = SUMMARY.exec(line) + if (summary) { + reportedTotal = Number(summary[1]) + continue + } + unplaced.push(line) + } + return { errors, unplaced, reportedTotal } +} + +function sortedKeys(record: Record): Record { + return Object.fromEntries( + Object.keys(record) + .sort() + .map((key) => [key, record[key]]) + ) +} + +function sortedCounts(counts: Counts): Counts { + return Object.fromEntries( + Object.entries(sortedKeys(counts)).map(([file, codes]) => [file, sortedKeys(codes)]) + ) +} + +export function countErrors(errors: Map): Counts { + const counts: Counts = {} + for (const [file, list] of errors) { + const codes: Record = {} + for (const { code } of list) codes[code] = (codes[code] ?? 0) + 1 + counts[file] = codes + } + return sortedCounts(counts) +} + +function total(counts: Counts): number { + return Object.values(counts) + .flatMap((codes) => Object.values(codes)) + .reduce((sum, count) => sum + count, 0) +} + +/** Accepts only `{ file: { TSnnnn: positive integer } }` with no empty file entry. */ +export function parseCounts(json: string, source: string): Counts { + const value: unknown = JSON.parse(json) + if (!isRecordLike(value)) { + throw new Error(`${source} is not a JSON object of per-file, per-code counts`) + } + const counts: Counts = {} + for (const [file, codes] of Object.entries(value)) { + if (!isRecordLike(codes) || Object.keys(codes).length === 0) { + throw new Error(`${source}: ${file} must map TS codes to counts`) + } + counts[file] = {} + for (const [code, count] of Object.entries(codes)) { + if (!CODE.test(code) || typeof count !== 'number' || !Number.isInteger(count) || count < 1) { + throw new Error( + `${source}: ${file} ${code} has count ${JSON.stringify(count)}; expected TSnnnn: integer ≥ 1` + ) + } + counts[file][code] = count + } + } + return counts +} + +interface CountChange { + file: string + code: string + count: number + baseline: number +} + +interface Comparison { + /** (file, code) pairs above their baseline count, including pairs with no baseline entry. */ + regressed: CountChange[] + /** Baselined (file, code) pairs below their count, including pairs with no errors left. */ + shrunk: CountChange[] +} + +function pairs(counts: Counts): Array<[string, string, number]> { + return Object.entries(counts).flatMap(([file, codes]) => + Object.entries(codes).map(([code, count]): [string, string, number] => [file, code, count]) + ) +} + +export function compareCounts(current: Counts, baseline: Counts): Comparison { + const regressed = pairs(current) + .filter(([file, code, count]) => count > (baseline[file]?.[code] ?? 0)) + .map(([file, code, count]) => ({ file, code, count, baseline: baseline[file]?.[code] ?? 0 })) + const shrunk = pairs(baseline) + .filter(([file, code, count]) => (current[file]?.[code] ?? 0) < count) + .map(([file, code, count]) => ({ + file, + code, + count: current[file]?.[code] ?? 0, + baseline: count, + })) + const order = (a: CountChange, b: CountChange) => + compareStrings(a.file, b.file) || compareStrings(a.code, b.code) + return { regressed: regressed.sort(order), shrunk: shrunk.sort(order) } +} + +/** Per-(file, code) counts clamped to the baseline, so an update can only lower them. */ +export function shrinkBaseline(current: Counts, baseline: Counts): Counts { + const next: Counts = {} + for (const [file, code, count] of pairs(current)) { + const kept = Math.min(count, baseline[file]?.[code] ?? 0) + if (kept > 0) next[file] = { ...next[file], [code]: kept } + } + return sortedCounts(next) +} + +function flagValue(flag: string): string | null { + const index = process.argv.indexOf(flag) + if (index === -1) return null + const value = process.argv[index + 1] + if (!value || value.startsWith('--')) { + console.error(`✗ ${flag} needs a path`) + process.exit(1) + } + return path.resolve(value) +} + +function fail(lines: string[]): never { + for (const line of lines) console.error(line) + process.exit(1) +} + +/** Fails on any parsed output that would undercount; otherwise returns its counts. */ +function checkedCounts(parsed: ParsedOutput): Counts { + if (parsed.unplaced.length) { + fail([ + `✗ ${parsed.unplaced.length} line(s) of tsc output are not a located error; fix them first:`, + ...parsed.unplaced.slice(0, 40).map((line) => ` ${line}`), + ]) + } + const counts = countErrors(parsed.errors) + if (parsed.reportedTotal !== null && parsed.reportedTotal !== total(counts)) { + fail([`✗ tsc reported ${parsed.reportedTotal} errors but ${total(counts)} were parsed`]) + } + return counts +} + +/** What `--report` records about a compile, so a saved `diagnostics.txt` can be checked later. */ +interface CompileStatus { + exitCode: number + errorCount: number +} + +/** Exit 0 means no errors and 1 or 2 means some; any other pairing is a failed or partial run. */ +function checkExitCode(exitCode: number, found: number): void { + if ((exitCode === 0) !== (found === 0)) { + fail([`✗ tsc exited with ${exitCode} but ${found} errors were parsed`]) + } +} + +/** Runs the compiler on the tests config and returns its parsed output. */ +function compile(reportDir: string | null): { counts: Counts; errors: ParsedOutput['errors'] } { + const result = Bun.spawnSync([localBin('tsc'), '--noEmit', '--pretty', 'false', '-p', TSCONFIG], { + cwd: APP_DIR, + stdout: 'pipe', + stderr: 'pipe', + }) + const stdout = result.stdout.toString() + const stderr = result.stderr.toString() + if (reportDir) writeFileSync(path.join(reportDir, 'diagnostics.txt'), `${stdout}${stderr}`) + + // 0: no errors; 1 and 2: errors reported. Anything else, or a signal, is a crash. + if (result.signalCode || ![0, 1, 2].includes(result.exitCode)) { + fail([ + `✗ tsc exited with ${result.signalCode ? `signal ${result.signalCode}` : result.exitCode}:`, + stderr.trim() || stdout.trim().split('\n').slice(-40).join('\n'), + ]) + } + const parsed = parseCompilerOutput(stdout, APP_DIR, ROOT) + const counts = checkedCounts(parsed) + checkExitCode(result.exitCode, total(counts)) + if (reportDir) { + const status: CompileStatus = { exitCode: result.exitCode, errorCount: total(counts) } + writeFileSync(path.join(reportDir, 'status.json'), `${JSON.stringify(status, null, 2)}\n`) + } + return { counts, errors: parsed.errors } +} + +function readStatus(file: string): CompileStatus { + if (!existsSync(file)) { + fail([ + `✗ ${file} is missing, so the compile that wrote these diagnostics cannot be verified.`, + ' Use the whole test-types artifact of a run whose compile finished.', + ]) + } + const value: unknown = JSON.parse(readFileSync(file, 'utf8')) + const { exitCode, errorCount } = toRecord(value) + if ( + typeof exitCode !== 'number' || + ![0, 1, 2].includes(exitCode) || + typeof errorCount !== 'number' || + !Number.isInteger(errorCount) || + errorCount < 0 + ) { + fail([`✗ ${file} is not { "exitCode": 0 | 1 | 2, "errorCount": integer ≥ 0 }`]) + } + return { exitCode, errorCount } +} + +/** + * Parses a saved compiler output (the CI artifact's `diagnostics.txt`) without compiling, held + * to the same checks as a live compile plus the error count recorded beside it. + */ +function readDiagnostics(file: string): { counts: Counts; errors: ParsedOutput['errors'] } { + const status = readStatus(path.join(path.dirname(file), 'status.json')) + const parsed = parseCompilerOutput(readFileSync(file, 'utf8'), APP_DIR, ROOT) + const counts = checkedCounts(parsed) + checkExitCode(status.exitCode, total(counts)) + if (status.errorCount !== total(counts)) { + fail([ + `✗ ${file} holds ${total(counts)} errors but its compile printed ${status.errorCount}; ` + + 'it is truncated or from another run.', + ]) + } + return { counts, errors: parsed.errors } +} + +function main(): void { + const reportDir = flagValue('--report') + const diagnosticsFile = flagValue('--diagnostics') + const update = process.argv.includes('--update') + if (reportDir) mkdirSync(reportDir, { recursive: true }) + + const { counts: current, errors } = diagnosticsFile + ? readDiagnostics(diagnosticsFile) + : compile(reportDir) + if (reportDir) { + writeFileSync(path.join(reportDir, 'counts.json'), `${JSON.stringify(current, null, 2)}\n`) + } + + const baselinePath = path.relative(ROOT, BASELINE) + if (!existsSync(BASELINE)) { + fail([`✗ ${baselinePath} is missing. Restore it from git.`]) + } + const baseline = parseCounts(readFileSync(BASELINE, 'utf8'), baselinePath) + const { regressed, shrunk } = compareCounts(current, baseline) + + if (update) { + if (regressed.length) { + fail([ + `✗ refused to raise the baseline for ${regressed.length} (file, code) pair(s); fix them instead:`, + ...regressed.map((c) => ` ${c.file} ${c.code}: ${c.count} (baseline ${c.baseline})`), + ]) + } + const next = shrinkBaseline(current, baseline) + writeFileSync(BASELINE, `${JSON.stringify(next, null, 2)}\n`) + console.log(`Wrote ${baselinePath}: ${total(next)} errors in ${Object.keys(next).length} files`) + return + } + + if (regressed.length) { + console.error(`✗ ${regressed.length} (file, code) pair(s) gained type errors:`) + for (const change of regressed) { + console.error( + `\n ${change.file} ${change.code}: ${change.count} (baseline ${change.baseline})` + ) + const lines = (errors.get(change.file) ?? []).filter((error) => error.code === change.code) + for (const { text } of lines.slice(0, MAX_PRINTED)) console.error(` ${text}`) + if (lines.length > MAX_PRINTED) console.error(` … ${lines.length - MAX_PRINTED} more`) + } + console.error( + '\n Fix the types: a typed factory from @sim/testing, vi.mocked(fn), or a mock whose shape ' + + 'matches the real module. Never `as any` or a @ts-ignore/@ts-expect-error to quiet one, ' + + 'and never raise the baseline.' + ) + if (Object.keys(baseline).some((file) => !(file in current))) { + console.error( + ` If a regressed file is a baselined file you only moved (git mv), move its entry to the ` + + `new path in ${baselinePath}; its counts may not grow.` + ) + } + } + if (shrunk.length) { + console.error(`\n✗ ${shrunk.length} (file, code) pair(s) dropped below the baseline:`) + for (const change of shrunk) { + console.error( + ` ${change.file} ${change.code}: ${change.count} (baseline ${change.baseline})` + ) + } + console.error( + ' Shrink the baseline so they cannot creep back: bun run scripts/check-test-types.ts ' + + '--update, or without a local compile, from the failed CI run:\n' + + ' gh run download -n test-types -D && ' + + 'bun run scripts/check-test-types.ts --diagnostics /diagnostics.txt --update' + ) + } + if (regressed.length || shrunk.length) process.exit(1) + + console.log( + `✓ test type errors: ${total(current)} baselined in ${Object.keys(current).length} files` + ) +} + +if (import.meta.main) main() diff --git a/scripts/ci-gate.test.ts b/scripts/ci-gate.test.ts index f51bd7160b6..91347146b0a 100644 --- a/scripts/ci-gate.test.ts +++ b/scripts/ci-gate.test.ts @@ -14,6 +14,7 @@ type Job = | 'desktop-live' | 'lint' | 'test' + | 'test-types' | 'build' type Results = Partial> @@ -24,6 +25,7 @@ const GATED: Job[] = [ 'e2e-mobile', 'desktop-live', 'test', + 'test-types', 'build', ] const ALL_FALSE = { full: 'false', test: 'false', build: 'false', desktop_live: 'false' } @@ -108,7 +110,7 @@ describe('CI gate', () => { name: 'a skip whose flag is differently cased', outputs: { ...ALL_FALSE, test: 'False' }, results: skipGated, - reported: ['test: skipped'], + reported: ['test-types: skipped', 'test: skipped'], }, { name: 'a skip whose flag is empty', @@ -133,6 +135,7 @@ describe('CI gate', () => { 'e2e-mobile: skipped', 'e2e: skipped', 'integration: skipped', + 'test-types: skipped', 'test: skipped', ], }, @@ -147,6 +150,7 @@ describe('CI gate', () => { 'e2e-mobile: skipped', 'e2e: skipped', 'integration: skipped', + 'test-types: skipped', 'test: skipped', ], }, @@ -162,6 +166,7 @@ describe('CI gate', () => { 'e2e-mobile: skipped', 'e2e: skipped', 'integration: skipped', + 'test-types: skipped', 'test: skipped', ], }, diff --git a/scripts/run-audits.ts b/scripts/run-audits.ts index 11f3ee4b00a..4af4ed171e8 100644 --- a/scripts/run-audits.ts +++ b/scripts/run-audits.ts @@ -24,6 +24,7 @@ const EXCLUDED: Record = { 'check:audits': 'this runner', 'check:migrations': 'diffs against a git base ref (origin/staging by default)', 'check:api-validation': 'superseded by the :strict variant, which this runner does run', + 'check:test-types': 'type-checks all of apps/sim with its tests; its own `test-types` CI job', } const ROOT = path.resolve(import.meta.dir, '..')