{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "knock-codes-types",
  "title": "Knock Codes Types",
  "description": "Shared config/defaults/label types used by every React block. Installed automatically — not meant to be added on its own.",
  "registryDependencies": [
    "https://knock.codes/r/react/knock-codes-core.json"
  ],
  "files": [
    {
      "path": "packages/react/types.ts",
      "content": "import type { VerifyFn } from \"../core/verify.ts\";\r\nimport type { StorageMode } from \"../core/storage.ts\";\r\nimport type { KnockCodesSession } from \"../core/session.ts\";\r\n\r\n/** Unset-prop defaults — change deliberately, they're part of the public contract. */\r\nexport const DEFAULT_TIMEOUT_MS = 1_800_000; // 30 minutes\r\nexport const ACTIVITY_WRITE_THROTTLE_MS = 1_000;\r\nexport const EXPIRY_POLL_INTERVAL_MS = 1_000;\r\n\r\n/** Configuration shared by `<KnockCodes>` and `useKnockCodes`. */\r\nexport interface KnockCodesConfig {\r\n  expectedHash?: string;\r\n  verify?: VerifyFn;\r\n  /** @default \"localStorage\" */\r\n  storage?: StorageMode;\r\n  /** @default \"knock-codes:session\" (src/core/storage.ts DEFAULT_STORAGE_KEY) */\r\n  storageKey?: string;\r\n  /** Session lifetime in ms. @default 1_800_000 (30 minutes) */\r\n  timeout?: number;\r\n  /** Sliding-timeout model: interaction rewrites expiry instead of a fixed TTL. @default false */\r\n  activityTracking?: boolean;\r\n}\r\n\r\n/**\r\n * `\"unknown\"`/omitted `VerifyResult` reasons collapse into `\"invalid\"` here —\r\n * the UI never distinguishes them from a plain wrong-code case.\r\n */\r\nexport type KnockCodesErrorReason = \"invalid\" | \"network\";\r\n\r\nexport interface KnockCodesError {\r\n  reason: KnockCodesErrorReason;\r\n}\r\n\r\n/** The unlock flow's state machine — `error` is an annotation on `idle`, not a fifth state. */\r\nexport type KnockCodesState = \"idle\" | \"submitting\" | \"unlocked\";\r\n\r\nexport interface UseKnockCodesResult {\r\n  state: KnockCodesState;\r\n  error: KnockCodesError | null;\r\n  session: KnockCodesSession | null;\r\n  /** No-ops (returns without calling the verify strategy) for an empty code. */\r\n  submit: (code: string) => Promise<void>;\r\n  logout: () => void;\r\n}\r\n\r\n/**\r\n * Every user-facing string, overridable for localization.\r\n * `<KnockCodes labels={...}>` merges these over `DEFAULT_LABELS`;\r\n * `useKnockCodes` is headless and never touches this type, since it\r\n * renders no strings itself.\r\n */\r\nexport interface KnockCodesLabels {\r\n  heading?: string;\r\n  subcopy?: string;\r\n  inputLabel?: string;\r\n  placeholder?: string;\r\n  submitLabel?: string;\r\n  submittingLabel?: string;\r\n  invalidErrorMessage?: string;\r\n  networkErrorMessage?: string;\r\n  showCodeLabel?: string;\r\n  hideCodeLabel?: string;\r\n}\r\n\r\nexport const DEFAULT_LABELS: Required<KnockCodesLabels> = {\r\n  heading: \"This page is protected\",\r\n  subcopy: \"Enter the access code to continue.\",\r\n  inputLabel: \"Access code\",\r\n  placeholder: \"Enter access code\",\r\n  submitLabel: \"Unlock\",\r\n  submittingLabel: \"Checking...\",\r\n  invalidErrorMessage: \"That code didn't work. Try again.\",\r\n  networkErrorMessage: \"Couldn't reach the server. Try again.\",\r\n  showCodeLabel: \"Show code\",\r\n  hideCodeLabel: \"Hide code\",\r\n};\r\n",
      "type": "registry:file",
      "target": "components/knock-codes/react/types.ts"
    }
  ],
  "type": "registry:block"
}