{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
  "files": {
    "ignoreUnknown": false,
    // Vendored Pulumi provider SDKs are `pulumi package gen-sdk` output. Linting
    // them is not just noise — the import-extension autofix rewrites the
    // generated `require("./x")` calls to `require("./x.ts")`, which typechecks
    // but emits verbatim and throws MODULE_NOT_FOUND at runtime.
    "includes": [
      "**",
      "!!**/*.d.ts",
      "!!tmp",
      "!!**/*.txt",
      "!!.*",
      "!!coverage",
      "!!bun.lock",
      "!!packages/db/migrations-temp",
      "!!packages/pulumi/sdks",
      "!!node_modules",
      "!!dist",
      "!!packages/*/.next",
      "!!.next-e2e",
      "!!packages/*/.sst",
      "!!packages/*/.open-next",
      "!!packages/solana-services/test/fixtures/snapshots/devnet.json",
      "!!**/.next",
      "!!**/fpddir.txt",
      "!!**/FedACHdir.txt",
      "!!**/dist",
      "!!**/.next",
      "!!**/*.d.ts",
      "!!**/*.config.js",
      "!!packages/*/src/generators",
      "!!.sst",
      "!!**/sst.config.ts",
      // Static design/reference artifacts, not source: a raw export of hosted
      // email templates and a wireframe SVG. Nothing to lint or format here.
      "!!docs/email-templates/hosted-templates.2026-07-28.json",
      "!!docs/email-templates/admin-ui-wireframe.svg"
    ]
  },
  // Biome owns formatting for every language it supports: JS/TS/JSX/TSX,
  // JSON/JSONC, CSS and GraphQL. Prettier is scoped to the languages Biome
  // cannot format — SQL, Markdown and YAML — via `.prettierignore`. No file is
  // ever owned by both formatters.
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 80,
    "attributePosition": "auto",
    "bracketSameLine": false,
    "bracketSpacing": true,
    "expand": "auto",
    "useEditorconfig": true,
    "includes": ["**"]
  },
  "linter": {
    "enabled": true,
    "domains": {
      "next": "recommended",
      "project": "recommended",
      "react": "recommended",
      "tailwind": "recommended",
      "drizzle": "all",
      "test": "recommended"
    },
    "rules": {
      "preset": "recommended",
      "a11y": {
        "noStaticElementInteractions": "off",
        "useKeyWithClickEvents": "off"
      },
      "complexity": {
        "noAdjacentSpacesInRegex": "error",
        "noExtraBooleanCast": "error",
        "noUselessCatch": "error",
        "noUselessEscapeInRegex": "error",
        "noUselessThisAlias": "error",
        "noUselessTypeConstraint": "error",
        "noUselessConstructor": "off",
        "noArguments": "error",
        "useLiteralKeys": "off",
        "noExcessiveCognitiveComplexity": {
          "level": "info",
          "options": { "maxAllowedComplexity": 20 }
        },
        "noExcessiveLinesPerFunction": {
          "level": "info",
          "options": { "maxLines": 120 }
        }
      },
      "correctness": {
        "noConstAssign": "error",
        "noConstantCondition": "error",
        "noEmptyCharacterClassInRegex": "error",
        "noEmptyPattern": "error",
        "noGlobalObjectCalls": "error",
        "noInvalidBuiltinInstantiation": "error",
        "noInvalidConstructorSuper": "error",
        "noNonoctalDecimalEscape": "error",
        "noPrecisionLoss": "error",
        "noSelfAssign": "error",
        "noSetterReturn": "error",
        "noSwitchDeclarations": "error",
        "noUndeclaredVariables": "error",
        "noUnreachable": "error",
        "noUnreachableSuper": "error",
        "noUnsafeFinally": "error",
        "noUnsafeOptionalChaining": "error",
        "noUnusedLabels": "error",
        "noUnusedPrivateClassMembers": "error",

        "noUnusedVariables": {
          "level": "error",
          "options": {
            "ignoreRestSiblings": false
          }
        },
        "useIsNan": "error",
        "useValidForDirection": "error",
        "useValidTypeof": "error",
        "useYield": "error",
        "noUnusedImports": {
          "level": "error",
          "fix": "safe"
        },
        "useImportExtensions": "error",
        "noUndeclaredDependencies": "off",
        "noUnresolvedImports": "off"
      },
      "nursery": {
        "noFloatingPromises": "error",
        "noMisusedPromises": "error",
        "noUnsafePlusOperands": "error",
        "noDrizzleDeleteWithoutWhere": {
          "level": "error",
          "options": { "drizzleObjectName": ["db"] }
        },
        "noDrizzleUpdateWithoutWhere": {
          "level": "error",
          "options": { "drizzleObjectName": ["db"] }
        }
      },
      "style": {
        "noCommonJs": "error",
        "noNamespace": "error",
        "noNonNullAssertion": "warn",
        "useArrayLiterals": "error",
        "useAsConstAssertion": "error",
        "useConst": "error",
        "noNestedTernary": "off",
        "useExportType": "error",
        "useImportType": {
          "level": "error",
          "options": { "style": "auto" }
        },
        "noParameterAssign": "error",
        "useDefaultParameterLast": "error",
        "useEnumInitializers": "error",
        "useSelfClosingElements": "error",
        "useSingleVarDeclarator": "error",
        "noUnusedTemplateLiteral": "error",
        "useNumberNamespace": "error",
        "noInferrableTypes": "error",
        "noUselessElse": "error",
        "useNamingConvention": {
          "level": "warn",
          "options": {
            "strictCase": false,
            "conventions": [
              {
                "selector": { "kind": "typeLike" },
                "match": "_?(.*)",
                "formats": ["PascalCase"]
              },
              {
                "selector": { "kind": "enumMember" },
                "match": "_?(.*)",
                "formats": ["PascalCase"]
              },
              {
                "selector": { "kind": "typeParameter" },
                "match": "_?(.*)",
                "formats": ["PascalCase"]
              },
              {
                "selector": { "kind": "function" },
                "match": "_?(.*)",
                "formats": ["camelCase", "PascalCase"]
              },
              {
                "selector": { "kind": "classMethod" },
                "match": "_?(.*)",
                "formats": ["camelCase"]
              },
              {
                "selector": { "kind": "classGetter" },
                "match": "_?(.*)",
                "formats": ["camelCase"]
              },
              {
                "selector": { "kind": "classSetter" },
                "match": "_?(.*)",
                "formats": ["camelCase"]
              },
              {
                "selector": { "kind": "variable" },
                "match": "_?(.*)",
                "formats": ["camelCase", "CONSTANT_CASE", "PascalCase"]
              },
              {
                "selector": { "kind": "functionParameter" },
                "match": "_?(.*)",
                "formats": ["camelCase"]
              },
              {
                "selector": { "kind": "classProperty" },
                "match": "_?(.*)",
                "formats": ["camelCase", "CONSTANT_CASE"]
              },
              {
                "selector": { "kind": "objectLiteralProperty" },
                "match": ".*",
                "formats": ["snake_case"]
              },
              {
                // DB-row / external-API type annotations use snake_case field
                // names (e.g. `Record<string, { block_time: string }>`). Allow
                // snake_case on type properties without flagging camelCase ones.
                "selector": { "kind": "typeProperty" },
                "match": "_?(.*)",
                "formats": ["camelCase", "snake_case", "CONSTANT_CASE"]
              }
            ]
          }
        },
        "noExcessiveLinesPerFile": {
          "level": "info",
          "options": { "maxLines": 2000, "skipBlankLines": true }
        },
        "useErrorCause": "warn"
      },
      "suspicious": {
        "noConsole": { "level": "info", "fix": "none" },
        "noUnknownAtRules": "off",
        "noArrayIndexKey": "warn",
        "noAssignInExpressions": "error",
        "noAsyncPromiseExecutor": "error",
        "noCatchAssign": "error",
        "noClassAssign": "error",
        "noCompareNegZero": "error",
        "noConstantBinaryExpressions": "error",
        "noControlCharactersInRegex": "error",
        "noDoubleEquals": { "level": "error", "fix": "safe" },
        "noDebugger": "error",
        "noDuplicateCase": "error",
        "noDuplicateClassMembers": "error",
        "noDuplicateElseIf": "error",
        "noDuplicateObjectKeys": "error",
        "noDuplicateParameters": "error",
        "noEmptyBlockStatements": "warn",
        "noExplicitAny": "warn",
        "noExtraNonNullAssertion": "error",
        "noFallthroughSwitchClause": "error",
        "noFunctionAssign": "error",
        "noGlobalAssign": "error",
        "noImportAssign": "error",
        "noIrregularWhitespace": "error",
        "noMisleadingCharacterClass": "error",
        "noMisleadingInstantiator": "error",
        "noPrototypeBuiltins": "error",
        "noRedeclare": "error",
        "noShadowRestrictedNames": "error",
        "noSparseArray": "error",
        "noUnsafeDeclarationMerging": "error",
        "noUnsafeNegation": "error",
        "noUselessRegexBackrefs": "error",
        "noWith": "error",
        "useGetterReturn": "error",
        "useNamespaceKeyword": "error",
        "noNonNullAssertedOptionalChain": "error",
        "noTsIgnore": "error",
        "noShadow": "off",
        "noUndeclaredEnvVars": "warn",
        "noUnnecessaryConditions": "warn"
      }
    },
    "includes": ["**"]
  },
  "overrides": [
    {
      // Solana signing lives on `temporal-worker` and nowhere else
      // (docs/proposals/PROGRAM_DEPLOYS.md §2). `SolanaKeypairService` reads
      // 64-byte ed25519 secrets out of the `solana-keypairs` Doppler project,
      // which also holds the mintfx and escrow program upgrade authorities —
      // so any runtime that can construct it can upgrade program bytecode.
      //
      // A rule stated in a proposal decays; this one fails the build. The
      // negated patterns are the only places allowed to name the type:
      // solana-services itself (it defines and injects it), the `*Activities`
      // modules that run on the worker, and the worker's own bootstrap. Tests
      // are excluded because they construct fakes, never a real Doppler client.
      //
      // If you are here because this rule fired: the answer is a Temporal
      // workflow, not an exemption. See `mintfxAuthorityMutationWorkflow` for
      // the shape a page-triggered signature is supposed to take.
      "includes": [
        "**/*.ts",
        "**/*.tsx",
        "!packages/solana-services/**",
        "!packages/temporal-worker/**",
        "!**/*Activities.ts",
        "!**/*.test.ts",
        "!**/*.test.tsx"
      ],
      "linter": {
        "rules": {
          "style": {
            "noRestrictedImports": {
              "level": "error",
              "options": {
                "paths": {
                  "@cfxlabsinc/solana-services": {
                    "importNames": ["SolanaKeypairService"],
                    "message": "Solana signing belongs on temporal-worker (PROGRAM_DEPLOYS.md §2). Start a workflow instead of constructing a signer here."
                  }
                }
              }
            }
          }
        }
      }
    },
    {
      // Hookdeck transformations run inside Hookdeck's own sandbox, which
      // injects `addHandler` as a global and calls the handler with a
      // (request, context) pair whether or not the body uses context. They are
      // deployed as source text, so they cannot import or destructure their way
      // out of either.
      "includes": ["packages/hookdeck/pulumi/transformations/**"],
      "javascript": { "globals": ["addHandler"] },
      // Formatting is off, not merely relaxed. The provider diffs a
      // transformation's `code` as an exact string, so reformatting one — even
      // just quoting object keys differently — plans an update against live
      // Hookdeck. These files are kept byte-identical to what is deployed.
      "formatter": { "enabled": false },
      "linter": {
        "rules": {
          "correctness": {
            "noUnusedFunctionParameters": "off"
          },
          "suspicious": {
            "noConsole": "off"
          }
        }
      }
    },
    {
      // The Outpost bridge handler is inlined into the events Pulumi program
      // as a StringAsset, so it must stay dependency-free plain JavaScript.
      // `console` is its only route to CloudWatch, and in shadow mode that log
      // IS the Phase 1 rollout signal. Same category as the Hookdeck
      // transformations above. See docs/proposals/EVENT_BUS.md §8.8.
      "includes": ["packages/events/pulumi/handlers/**"],
      "linter": {
        "rules": {
          "suspicious": {
            "noConsole": "off"
          }
        }
      }
    },
    {
      // This test imports the `.mjs` handler above, which is typed by a
      // hand-written sibling `.d.mts`. `useImportExtensions` resolves that
      // declaration and "fixes" the specifier to `outpost-bridge.mjs.mts` — a
      // module that does not exist. The extension on disk is already correct.
      "includes": ["packages/events/test/outpostBridge.test.ts"],
      "linter": {
        "rules": {
          "correctness": {
            "useImportExtensions": "off"
          }
        }
      }
    },
    {
      "includes": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts"],
      "linter": {
        "rules": {
          "complexity": {
            "noExcessiveLinesPerFunction": "off"
          },
          "nursery": {},
          "style": {
            "noExcessiveLinesPerFile": "off"
          }
        }
      }
    },
    {
      "includes": ["**/env.ts"],
      "linter": {
        "rules": {
          "style": {
            "useNamingConvention": "off"
          }
        }
      }
    },
    {
      // RouteFusion's GraphQL API uses snake_case field names on the wire; the
      // hand-written request/result types must match the API verbatim (same
      // rationale as the env.ts override above for SCREAMING_SNAKE env vars).
      "includes": ["packages/clients/src/routefusion/**"],
      "linter": {
        "rules": {
          "style": {
            "useNamingConvention": "off"
          }
        }
      }
    }
  ],
  "javascript": {
    "formatter": {
      "enabled": true,
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSameLine": false,
      "quoteStyle": "double",
      "attributePosition": "auto",
      "bracketSpacing": true
    },
    "globals": ["Temporal"]
  },
  "html": {
    "formatter": { "enabled": false, "selfCloseVoidElements": "always" }
  },
  "css": {
    "parser": { "tailwindDirectives": true }
  },
  "assist": {
    "enabled": true,
    "actions": { "source": { "organizeImports": "on" } }
  }
}
