{
  "slug": "toss-payments-postgresql",
  "name": "@gj-kit/toss-payments-postgresql",
  "version": "0.5.1",
  "description": "PostgreSQL stores, migrations, webhook inbox, and encryption seams for @gj-kit/toss-payments.",
  "homepage": "https://gj-kit.github.io/gj-kit/packages/toss-payments-postgresql/",
  "repository": "git+https://github.com/gj-kit/gj-kit.git",
  "license": "MIT",
  "engines": {
    "node": ">=20"
  },
  "peerDependencies": {
    "@gj-kit/toss-payments": "^0.5.0 || ^0.6.0",
    "@nestjs/common": "^10 || ^11",
    "reflect-metadata": "^0.1.13 || ^0.2",
    "rxjs": "^7"
  },
  "peerDependenciesMeta": {
    "@nestjs/common": {
      "optional": true
    },
    "reflect-metadata": {
      "optional": true
    },
    "rxjs": {
      "optional": true
    }
  },
  "entries": [
    {
      "subpath": ".",
      "id": "root",
      "declarationTarget": "./dist/index.d.cts",
      "symbols": [
        {
          "name": "advisoryLockKey",
          "slug": "advisory-lock-key",
          "kind": "function",
          "declaration": "/**\n * FNV-1a 64bit — advisory lock 키 파생 (문서화된 고정 알고리즘, 설계 §4).\n *\n * `pg_advisory_xact_lock(bigint)`은 **signed** int8을 받으므로 unsigned 64bit 해시를\n * `BigInt.asIntN(64, ...)`으로 2의 보수 재해석해 int8 범위에 맞춘다 — 값의 비트는\n * 동일하고 표기만 음수가 될 수 있다. 파라미터는 문자열로 보낸다(드라이버들의 BigInt\n * 직렬화 지원이 제각각이고, PostgreSQL이 함수 시그니처로 타입을 추론한다).\n */\ndeclare function advisoryLockKey(schema: string): bigint;",
          "sourceDocumentation": "FNV-1a 64bit — advisory lock 키 파생 (문서화된 고정 알고리즘, 설계 §4).\n\n`pg_advisory_xact_lock(bigint)`은 **signed** int8을 받으므로 unsigned 64bit 해시를\n`BigInt.asIntN(64, ...)`으로 2의 보수 재해석해 int8 범위에 맞춘다 — 값의 비트는\n동일하고 표기만 음수가 될 수 있다. 파라미터는 문자열로 보낸다(드라이버들의 BigInt\n직렬화 지원이 제각각이고, PostgreSQL이 함수 시그니처로 타입을 추론한다)."
        },
        {
          "name": "Aes256GcmSensitiveValueProtectorOptions",
          "slug": "aes256-gcm-sensitive-value-protector-options",
          "kind": "interface",
          "declaration": "interface Aes256GcmSensitiveValueProtectorOptions {\n    /**\n     * 32-byte AES-256 key — a `Uint8Array`/`Buffer` of exactly 32 bytes or a 64-character hex\n     * string. The host generates it (for example `openssl rand -hex 32`), stores it in its secret\n     * manager, and owns rotation. The bytes are copied at construction; mutating the caller's\n     * buffer afterwards has no effect.\n     */\n    readonly key: Uint8Array | string;\n    /**\n     * Optional nonsecret key identifier written to the envelope as `kid` and bound into the AAD.\n     * Rows encrypted under a different `kid` (or without one) are rejected with\n     * `'key-id-mismatch'` before any decryption, which lets a host route old rows to a\n     * previous-key protector during rotation. 1–128 characters.\n     */\n    readonly keyId?: string;\n}"
        },
        {
          "name": "CleanupResult",
          "slug": "cleanup-result",
          "kind": "interface",
          "declaration": "interface CleanupResult {\n    /** webhook_dedupe에서 삭제된 completed 행 수. */\n    readonly dedupeDeleted: number;\n    /** cancel_retries에서 삭제된 만료 행 수. */\n    readonly cancelRetriesDeleted: number;\n}"
        },
        {
          "name": "createAes256GcmSensitiveValueProtector",
          "slug": "create-aes256-gcm-sensitive-value-protector",
          "kind": "function",
          "declaration": "/**\n * Builds a `SensitiveValueProtector` that seals values with AES-256-GCM, a fresh random\n * 12-byte IV per `encrypt`, and the seam context bound as AAD.\n *\n * The host keeps key custody and rotation: this function never generates, persists, or\n * rotates keys. Because the IV is random, NIST SP 800-38D §8.3 caps a single key at 2^32\n * `encrypt` invocations — rotate to a new `keyId` well before that; the library does not\n * count. Key/config misuse throws `TypeError` synchronously at construction; `encrypt`\n * rejects with `TypeError` for non-string or ill-formed UTF-16 plaintext (lone surrogates\n * would otherwise be silently replaced with U+FFFD and fail to round-trip); undecryptable\n * rows reject with `SensitiveValueProtectorError` (`code` is the contract).\n */\ndeclare function createAes256GcmSensitiveValueProtector(options: Aes256GcmSensitiveValueProtectorOptions): SensitiveValueProtector;",
          "sourceDocumentation": "Builds a `SensitiveValueProtector` that seals values with AES-256-GCM, a fresh random\n12-byte IV per `encrypt`, and the seam context bound as AAD.\n\nThe host keeps key custody and rotation: this function never generates, persists, or\nrotates keys. Because the IV is random, NIST SP 800-38D §8.3 caps a single key at 2^32\n`encrypt` invocations — rotate to a new `keyId` well before that; the library does not\ncount. Key/config misuse throws `TypeError` synchronously at construction; `encrypt`\nrejects with `TypeError` for non-string or ill-formed UTF-16 plaintext (lone surrogates\nwould otherwise be silently replaced with U+FFFD and fail to round-trip); undecryptable\nrows reject with `SensitiveValueProtectorError` (`code` is the contract)."
        },
        {
          "name": "createOpaqueAdvisoryLockKey",
          "slug": "create-opaque-advisory-lock-key",
          "kind": "function",
          "declaration": "/**\n * 앱이 만든 HMAC/blind-index를 opaque lock key로 명시적으로 표시한다.\n *\n * 이 함수는 HMAC을 생성하거나 원본 식별자를 보호하지 않는다. 앱의 key management와\n * canonicalization은 앱 소유이다. empty/비정상적으로 큰 입력만 fail-fast로 거부하며,\n * 오류 메시지에는 전달된 값을 포함하지 않는다.\n */\ndeclare function createOpaqueAdvisoryLockKey(value: string): OpaqueAdvisoryLockKey;",
          "sourceDocumentation": "앱이 만든 HMAC/blind-index를 opaque lock key로 명시적으로 표시한다.\n\n이 함수는 HMAC을 생성하거나 원본 식별자를 보호하지 않는다. 앱의 key management와\ncanonicalization은 앱 소유이다. empty/비정상적으로 큰 입력만 fail-fast로 거부하며,\n오류 메시지에는 전달된 값을 포함하지 않는다."
        },
        {
          "name": "createPgAuditSink",
          "slug": "create-pg-audit-sink",
          "kind": "function",
          "declaration": "declare function createPgAuditSink(sql: SqlExecutor, options?: PgStoreOptions): PgAuditSink;"
        },
        {
          "name": "createPgBillingKeyStore",
          "slug": "create-pg-billing-key-store",
          "kind": "function",
          "declaration": "/**\n * BillingKeyStore의 조건부 delete는 protected payload를 같은 transaction에서 복호화·비교해야\n * 한다. 따라서 `withConnection` 없는 SqlExecutor는 지원하지 않고 SqlClient가 필수다.\n */\ndeclare function createPgBillingKeyStore(sql: SqlClient, options: PgSensitiveStoreOptions): PgBillingKeyStore;",
          "sourceDocumentation": "BillingKeyStore의 조건부 delete는 protected payload를 같은 transaction에서 복호화·비교해야\n한다. 따라서 `withConnection` 없는 SqlExecutor는 지원하지 않고 SqlClient가 필수다."
        },
        {
          "name": "createPgCancelRetryStore",
          "slug": "create-pg-cancel-retry-store",
          "kind": "function",
          "declaration": "/**\n * CancelRetryStore PostgreSQL 구현 (설계 §3.4).\n *\n * 코어 계약의 핵심 불변식:\n * - `CancelRetryRecord.bodyJson`은 **멱등 재생의 바이트 계약**이다 — 재시도 시 동일\n *   멱등키 + 동일 바이트를 다시 보내야 한다. 그래서 record_json 컬럼은 jsonb가 아니라\n *   **text**다: JSON.stringify한 record 전체를 보호한 뒤 text로 저장하고 JSON.parse\n *   왕복해 문자열 필드를 무손실 복원한다. jsonb 정규화(NUL 거부, 이스케이프/키 정렬\n *   변형)는 원문을 바꿀 위험이 있어 사용하지 않는다.\n * - 멱등키 15일 TTL — 삭제는 cleanup()(팩토리) 소관이며 이 스토어는 지우지 않는다.\n * - ⚠ record에는 환불 계좌 정보가 평문으로 들어올 수 있다. 레코드 전체를 보호기에\n *   넘긴 뒤 저장하며, 어떤 에러 메시지에도 record 내용을 싣지 않는다.\n */\ndeclare function createPgCancelRetryStore(sql: SqlExecutor, options: PgSensitiveStoreOptions): CancelRetryStore;",
          "sourceDocumentation": "CancelRetryStore PostgreSQL 구현 (설계 §3.4).\n\n코어 계약의 핵심 불변식:\n- `CancelRetryRecord.bodyJson`은 **멱등 재생의 바이트 계약**이다 — 재시도 시 동일\n  멱등키 + 동일 바이트를 다시 보내야 한다. 그래서 record_json 컬럼은 jsonb가 아니라\n  **text**다: JSON.stringify한 record 전체를 보호한 뒤 text로 저장하고 JSON.parse\n  왕복해 문자열 필드를 무손실 복원한다. jsonb 정규화(NUL 거부, 이스케이프/키 정렬\n  변형)는 원문을 바꿀 위험이 있어 사용하지 않는다.\n- 멱등키 15일 TTL — 삭제는 cleanup()(팩토리) 소관이며 이 스토어는 지우지 않는다.\n- ⚠ record에는 환불 계좌 정보가 평문으로 들어올 수 있다. 레코드 전체를 보호기에\n  넘긴 뒤 저장하며, 어떤 에러 메시지에도 record 내용을 싣지 않는다."
        },
        {
          "name": "createPgDepositSecretStore",
          "slug": "create-pg-deposit-secret-store",
          "kind": "function",
          "declaration": "/**\n * DepositSecretStore PostgreSQL 구현 (설계 §3.2).\n *\n * 코어 계약의 핵심 불변식:\n * - `saveSecret`은 **upsert 시맨틱 계약**이다(코어 TSDoc) — 기존 수동 저장과 병용해도\n *   이중 저장이 무해해야 한다.\n * - 한 객체가 confirm측 자동 저장 + 웹훅측 getSecret 대조 양쪽에 배선된다 — 저장 누락\n *   → DEPOSIT_CALLBACK 전부 unknown-order 거부가 되는 사고를 구조로 막는 §3.1 seam.\n * - ⚠ secret 값은 어떤 에러 메시지·로그에도 싣지 않는다.\n */\ndeclare function createPgDepositSecretStore(sql: SqlExecutor, options: PgSensitiveStoreOptions): DepositSecretStore;",
          "sourceDocumentation": "DepositSecretStore PostgreSQL 구현 (설계 §3.2).\n\n코어 계약의 핵심 불변식:\n- `saveSecret`은 **upsert 시맨틱 계약**이다(코어 TSDoc) — 기존 수동 저장과 병용해도\n  이중 저장이 무해해야 한다.\n- 한 객체가 confirm측 자동 저장 + 웹훅측 getSecret 대조 양쪽에 배선된다 — 저장 누락\n  → DEPOSIT_CALLBACK 전부 unknown-order 거부가 되는 사고를 구조로 막는 §3.1 seam.\n- ⚠ secret 값은 어떤 에러 메시지·로그에도 싣지 않는다."
        },
        {
          "name": "createPgOpaqueAdvisoryLocks",
          "slug": "create-pg-opaque-advisory-locks",
          "kind": "function",
          "declaration": "/**\n * PostgreSQL advisory transaction lock factory.\n *\n * `BEGIN → pg_advisory_xact_lock → callback → COMMIT`은 SqlClient가 보장하는 하나의\n * connection에서 실행된다. callback 또는 lock/commit이 실패하면 best-effort ROLLBACK 후\n * 원래 오류를 그대로 rethrow한다. `pg_advisory_xact_lock`은 commit/rollback과 함께 자동\n * 해제되므로 session-level lock 누수 경로가 없다.\n */\ndeclare function createPgOpaqueAdvisoryLocks(sql: SqlClient, options?: PgOpaqueAdvisoryLocksOptions): PgOpaqueAdvisoryLocks;",
          "sourceDocumentation": "PostgreSQL advisory transaction lock factory.\n\n`BEGIN → pg_advisory_xact_lock → callback → COMMIT`은 SqlClient가 보장하는 하나의\nconnection에서 실행된다. callback 또는 lock/commit이 실패하면 best-effort ROLLBACK 후\n원래 오류를 그대로 rethrow한다. `pg_advisory_xact_lock`은 commit/rollback과 함께 자동\n해제되므로 session-level lock 누수 경로가 없다."
        },
        {
          "name": "createPgOrderStore",
          "slug": "create-pg-order-store",
          "kind": "function",
          "declaration": "declare function createPgOrderStore(sql: SqlExecutor, options?: PgStoreOptions): OrderStore;"
        },
        {
          "name": "createPgWebhookDedupeStore",
          "slug": "create-pg-webhook-dedupe-store",
          "kind": "function",
          "declaration": "declare function createPgWebhookDedupeStore(sql: SqlExecutor, options?: PgWebhookDedupeStoreOptions): WebhookDedupeStore;"
        },
        {
          "name": "createPgWebhookInboxStore",
          "slug": "create-pg-webhook-inbox-store",
          "kind": "function",
          "declaration": "declare function createPgWebhookInboxStore(sql: SqlExecutor, options?: PgStoreOptions): WebhookInboxStore;"
        },
        {
          "name": "createSensitiveValueContext",
          "slug": "create-sensitive-value-context",
          "kind": "function",
          "declaration": "/** 내부 스토어가 불변 context를 만들기 위한 단일 경로. */\ndeclare function createSensitiveValueContext(purpose: SensitiveValuePurpose, recordId: string): SensitiveValueContext;",
          "sourceDocumentation": "내부 스토어가 불변 context를 만들기 위한 단일 경로."
        },
        {
          "name": "createTossPaymentsPostgres",
          "slug": "create-toss-payments-postgres",
          "kind": "function",
          "declaration": "declare function createTossPaymentsPostgres(options: TossPaymentsPostgresOptions): TossPaymentsPostgres;"
        },
        {
          "name": "DEFAULT_SCHEMA",
          "slug": "default-schema",
          "kind": "constant",
          "declaration": "DEFAULT_SCHEMA = \"toss_payments\"",
          "sourceDocumentation": "기본 스키마 이름 (설계 §3)."
        },
        {
          "name": "fromPgPool",
          "slug": "from-pg-pool",
          "kind": "function",
          "declaration": "/**\n * pg Pool → SqlClient 어댑터 (설계 §2).\n *\n * `withConnection`은 connect → fn → release를 정확히 1회 보장한다. fn이 throw하면\n * `release(err)`로 커넥션을 **폐기**한다 — 실패한 트랜잭션·advisory lock이 걸린 세션이\n * 풀로 되돌아가 다음 사용자를 오염시키는 사고를 막는다(BEGIN 잔존이 대표 사례).\n */\ndeclare function fromPgPool(pool: PgPoolLike): SqlClient;",
          "sourceDocumentation": "pg Pool → SqlClient 어댑터 (설계 §2).\n\n`withConnection`은 connect → fn → release를 정확히 1회 보장한다. fn이 throw하면\n`release(err)`로 커넥션을 **폐기**한다 — 실패한 트랜잭션·advisory lock이 걸린 세션이\n풀로 되돌아가 다음 사용자를 오염시키는 사고를 막는다(BEGIN 잔존이 대표 사례)."
        },
        {
          "name": "IDENTIFIER_PATTERN",
          "slug": "identifier-pattern",
          "kind": "constant",
          "declaration": "IDENTIFIER_PATTERN: RegExp",
          "sourceDocumentation": "PostgreSQL 비인용 식별자 규칙의 보수적 부분집합 — 소문자·숫자·언더스코어, 최대 63자."
        },
        {
          "name": "isSensitiveValueProtectorError",
          "slug": "is-sensitive-value-protector-error",
          "kind": "function",
          "declaration": "/**\n * Structural type guard — ESM/CJS dual loading can split class identity, so `instanceof`\n * is unreliable (same reasoning as `isTossPostgresError`).\n */\ndeclare function isSensitiveValueProtectorError(value: unknown): value is SensitiveValueProtectorError;",
          "sourceDocumentation": "Structural type guard — ESM/CJS dual loading can split class identity, so `instanceof`\nis unreliable (same reasoning as `isTossPostgresError`)."
        },
        {
          "name": "isTossPostgresError",
          "slug": "is-toss-postgres-error",
          "kind": "function",
          "declaration": "/**\n * 타입 가드 — `instanceof` 대신 구조 판정을 쓴다.\n *\n * 근거: ESM/CJS dual-package 이중 로드 시 클래스 정체성이 갈라져 `instanceof`가\n * 거짓 음성을 낸다(toss-payments-nestjs가 토큰에 `Symbol.for`를 쓰는 것과 같은 이유).\n * name + code 화이트리스트 판정은 로드 경로와 무관하게 안정적이다.\n */\ndeclare function isTossPostgresError(value: unknown): value is TossPostgresError;",
          "sourceDocumentation": "타입 가드 — `instanceof` 대신 구조 판정을 쓴다.\n\n근거: ESM/CJS dual-package 이중 로드 시 클래스 정체성이 갈라져 `instanceof`가\n거짓 음성을 낸다(toss-payments-nestjs가 토큰에 `Symbol.for`를 쓰는 것과 같은 이유).\nname + code 화이트리스트 판정은 로드 경로와 무관하게 안정적이다."
        },
        {
          "name": "migrate",
          "slug": "migrate",
          "kind": "function",
          "declaration": "/**\n * 마이그레이션 실행 (설계 §4 절차).\n *\n * 1. BEGIN\n * 2. pg_advisory_xact_lock — 동시 부팅 인스턴스 직렬화 (트랜잭션 종료 시 자동 해제)\n * 3. CREATE SCHEMA IF NOT EXISTS + 버전 테이블 toss_pg_migrations IF NOT EXISTS\n * 4. 미적용 id만 순서대로 실행 + 버전 테이블 INSERT\n * 5. COMMIT (실패 시 ROLLBACK 후 'migration-failed'로 감싸 rethrow — cause 보존)\n */\ndeclare function migrate(sql: SqlClient, options?: MigrateOptions): Promise<MigrationResult>;",
          "sourceDocumentation": "마이그레이션 실행 (설계 §4 절차).\n\n1. BEGIN\n2. pg_advisory_xact_lock — 동시 부팅 인스턴스 직렬화 (트랜잭션 종료 시 자동 해제)\n3. CREATE SCHEMA IF NOT EXISTS + 버전 테이블 toss_pg_migrations IF NOT EXISTS\n4. 미적용 id만 순서대로 실행 + 버전 테이블 INSERT\n5. COMMIT (실패 시 ROLLBACK 후 'migration-failed'로 감싸 rethrow — cause 보존)"
        },
        {
          "name": "MigrateOptions",
          "slug": "migrate-options",
          "kind": "interface",
          "declaration": "interface MigrateOptions {\n    /** 기본 'toss_payments'. `/^[a-z_][a-z0-9_]{0,62}$/` 위반 시 즉시 throw. */\n    readonly schema?: string;\n}"
        },
        {
          "name": "MigrationResult",
          "slug": "migration-result",
          "kind": "interface",
          "declaration": "interface MigrationResult {\n    /** 이번 호출이 실제 적용한 마이그레이션 id (적용 순서). */\n    readonly applied: readonly string[];\n    /** 버전 테이블에 이미 기록돼 있어 건너뛴 id — 멱등 재실행의 증거. */\n    readonly skipped: readonly string[];\n}"
        },
        {
          "name": "OpaqueAdvisoryLockKey",
          "slug": "opaque-advisory-lock-key",
          "kind": "type",
          "declaration": "type OpaqueAdvisoryLockKey = string & {\n    readonly [opaqueAdvisoryLockKeyBrand]: 'OpaqueAdvisoryLockKey';\n};"
        },
        {
          "name": "PgAuditSink",
          "slug": "pg-audit-sink",
          "kind": "interface",
          "declaration": "/**\n * AuditSink PostgreSQL 구현 (설계 §3.6).\n *\n * 코어 계약의 핵심 불변식(core/audit.ts TSDoc):\n * - `record()`는 코어가 **await하지 않는다**(fire-and-forget) — audit 오류가 결제\n *   경로의 지연·실패에 영향을 주지 않는다. insert 실패는 코어\n *   `AuditOptions.onSinkError`로만 통지되므로 여기서 추가 통지 채널을 만들지 않는다.\n * - 동일 id 재호출은 `ON CONFLICT (id) DO NOTHING`으로 멱등 — id는 crypto.randomUUID,\n *   시도 1건 = 엔트리 1건.\n * - entry는 코어 redaction 통과본이다(Authorization은 구조적 부재) — 이 스토어는\n *   내용을 다시 만지지 않고 통짜 jsonb로 보존한다.\n * - createFileAuditSink의 다중 프로세스 한계를 대체하는 것이 존재 이유 — 다중 인스턴스\n *   동시 insert에 안전하다(PK 충돌만 무시).\n *\n * v1은 즉시 INSERT(배치 없음) — 코어가 비동기 fire-and-forget이라 결제 경로 지연이\n * 없고, in-flight Set + `flush()`로 graceful shutdown 시 유실을 막는다.\n */\n/** flush 가능한 AuditSink — graceful shutdown 훅(예: Nest onApplicationShutdown). */\ninterface PgAuditSink extends AuditSink {\n    /**\n     * 코어 계약(`void | Promise<void>`)의 반환을 `Promise<void>`로 협착 선언한다 —\n     * 이 구현은 항상 Promise를 반환하므로(즉시 INSERT), 소비자가 flush/셧다운 코드에서\n     * `.catch()`를 바로 걸 수 있게 한다. 반환 공변이라 `AuditSink` 대입성은 유지된다.\n     */\n    record(entry: AuditEntry): Promise<void>;\n    /** 호출 시점까지 시작된(및 flush 중 새로 시작된) 모든 insert의 정착을 기다린다. 실패는 삼킨다. */\n    flush(): Promise<void>;\n}",
          "sourceDocumentation": "flush 가능한 AuditSink — graceful shutdown 훅(예: Nest onApplicationShutdown)."
        },
        {
          "name": "PgBillingKeyMutation",
          "slug": "pg-billing-key-mutation",
          "kind": "interface",
          "declaration": "/**\n * BillingKeyStore PostgreSQL 구현 (설계 §3.3).\n *\n * 코어 계약의 핵심 불변식:\n * - 토스에 빌링키 조회 API가 없다 — **저장 실패 = 복구 불가**. 이 테이블이 유일한\n *   보관 수단이므로 save는 드라이버 에러를 감추지 않고 그대로 던진다(코어가 감쌈).\n * - `save`는 upsert(customer_key)다 — issue/import 양쪽에서 호출되는 계약이고 코어가\n *   교체 정책을 규정하지 않으므로 최신 발급본을 유지한다.\n * - `billing_key`에는 BillingKeyRecord 전체의 보호된 JSON 문자열만 쓴다. `card`와\n *   `transfers`까지 함께 보호해 계좌번호 등 부수 메타데이터가 jsonb에 평문으로 남지\n *   않게 한다. method/issued_at은 운영 조회용 비밀이 아닌 최소 메타데이터로만 남긴다.\n * - ⚠ 보안 불변식(코어 stores.ts): 어떤 에러 메시지에도 billing_key 값을 싣지 않고,\n *   customerKey와 billingKey를 같은 문자열(로그 한 줄)에 함께 두지 않는다 — 토스의\n *   빌링 보안 모델이 이 쌍의 분리에 의존한다. 이 파일의 메시지는 둘 다 싣지 않는다.\n */\n/**\n * `withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n *\n * 핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n * `pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n * 되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다.\n */\ninterface PgBillingKeyMutation {\n    readonly customerKey: BillingKeyRecord['customerKey'];\n    find(): Promise<BillingKeyRecord | null>;\n    save(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<void>;\n    /**\n     * 현재 raw billing key와 일치할 때만 삭제한다. 무조건 삭제 API는 의도적으로 없다.\n     */\n    delete(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 저장 당시의 nonsecret operationId fingerprint가 예상 operationId와 같은지 확인한다.\n     * callback 내부에서만 쓰며 raw operationId/fingerprint 어느 것도 반환하지 않는다.\n     */\n    isCurrentOperationId(operationId: string): Promise<boolean>;\n    deleteIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "`withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n\n핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n`pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다."
        },
        {
          "name": "PgBillingKeySnapshot",
          "slug": "pg-billing-key-snapshot",
          "kind": "interface",
          "declaration": "/**\n * Opaque previous snapshot returned by `replaceAndGetPrevious`.\n *\n * Only `record` is readable, for recovery or display. Passing the original snapshot object\n * back to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\n * The fingerprint and the trusted record are linked only through a module-private\n * `WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\n * registry identity and the lifecycle fence is intentionally false after such a restore.\n */\ninterface PgBillingKeySnapshot {\n    readonly record: BillingKeyRecord;\n}",
          "sourceDocumentation": "Opaque previous snapshot returned by `replaceAndGetPrevious`.\n\nOnly `record` is readable, for recovery or display. Passing the original snapshot object\nback to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\nThe fingerprint and the trusted record are linked only through a module-private\n`WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\nregistry identity and the lifecycle fence is intentionally false after such a restore."
        },
        {
          "name": "PgBillingKeyStore",
          "slug": "pg-billing-key-store",
          "kind": "interface",
          "declaration": "/**\n * PostgreSQL이 제공하는 BillingKeyStore 확장.\n *\n * 코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n * 지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\n * fence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n *\n * `replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\n * customerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\n * compare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\n * issuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n * 잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다.\n */\ninterface PgBillingKeyStore extends BillingKeyStore {\n    /**\n     * customerKey별 PostgreSQL advisory transaction lock을 callback 전체에 유지한다.\n     *\n     * 같은 customerKey의 generic 저장과 앱 projection을 순서대로 끝내야 할 때의\n     * cross-instance fence다. 모든 경쟁 issuance/deletion/compensation이 이 API를 사용해야\n     * 한다. callback 성공 시 commit, throw 시 generic billing key 변경은 rollback된다.\n     * callback 안에서는 전달된 mutation handle만 사용하고 바깥 store를 재호출하지 않는다.\n     */\n    withMutationLock<T>(customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * opaque lifecycle lock과 customerKey mutation lock을 **같은 PostgreSQL connection과\n     * transaction**에서 `opaque → customer` 순서로 획득한다.\n     *\n     * credential issuance/revocation/compensation처럼 host lifecycle과 generic billing-key\n     * mutation을 함께 직렬화해야 할 때의 유일한 composable API다. callback은 두 lock을 모두\n     * 얻은 뒤에만 기존 customer-bound mutation handle을 받는다. callback 안에서는 handle만\n     * 사용하고 `opaqueLocks.withLock` 또는 outer billing store를 재진입하지 않는다.\n     *\n     * `opaqueLocks.withLock(key, () => withMutationLock(...))`처럼 두 public API를 중첩하면\n     * 서로 다른 `withConnection`을 열어 pool max=1에서 self-deadlock할 수 있고, 한\n     * transaction이라는 보장도 잃는다. 모든 결합 경로의 global lock order는 이 메서드가\n     * 강제하는 **opaque → customer**다.\n     */\n    withOpaqueMutationLock<T>(opaqueKey: OpaqueAdvisoryLockKey, customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * record를 저장하고, 같은 트랜잭션에서 잠근 직전 snapshot을 반환한다.\n     *\n     * 단일 generic write의 snapshot/보상에는 `find()` 뒤 `save()`보다 안전하다. 다만 앱\n     * projection까지 순서 보장이 필요하면 이 단독 메서드가 아니라 `withMutationLock` 안의\n     * 같은 이름 메서드를 사용한다. 그 callback 안에서 반환된 snapshot(첫 발급이면 null)을\n     * 이후 `replaceIfBillingKeyMatches(record.billingKey, previous)`에 전달하면 현재 값이\n     * 여전히 record일 때만 원자 복원/삭제할 수 있다. snapshot 원본을 그대로 넘기면 prior\n     * operation fingerprint까지 보존한다.\n     */\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 행을 삭제한다.\n     *\n     * 행이 없거나 현재 키가 다르면 false이고, 보호 payload 손상/복호화 실패는 숨기지 않고\n     * throw한다. false는 삭제되지 않았다는 안전한 결과이지 저장소 장애를 뜻하지 않는다.\n     */\n    deleteIfBillingKeyMatches(request: BillingKeyDeleteRequest): Promise<boolean>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 replacement로 교체한다.\n     *\n     * `replacement`가 null이면 조건부 삭제다. 보상 경로에서는 발급 직후 저장한 새 키를\n     * expected로, 이전 snapshot(또는 첫 발급이면 null)을 replacement로 전달한다. replacement의\n     * customerKey는 첫 인자와 반드시 같아야 한다.\n     */\n    replaceIfBillingKeyMatches(customerKey: BillingKeyRecord['customerKey'], expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "PostgreSQL이 제공하는 BillingKeyStore 확장.\n\n코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\nfence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n\n`replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\ncustomerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\ncompare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\nissuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다."
        },
        {
          "name": "PgOpaqueAdvisoryLocks",
          "slug": "pg-opaque-advisory-locks",
          "kind": "interface",
          "declaration": "/**\n * lifecycle work를 short-lived PostgreSQL advisory transaction lock 아래 실행하는 표면.\n *\n * callback에 SQL session을 전달하지 않는다. 이 API의 목적은 host DB transaction/worker\n * lifecycle의 **순서화**이며, 다른 ORM connection의 transaction과 2PC 원자성을 만들지\n * 않는다. callback은 local durable work만 수행하고 provider/HTTP 같은 긴 network I/O는\n * 넣지 않아야 한다. callback 안에서 같은 key로 이 facility를 재진입하면 다른 connection이\n * 바깥 transaction의 xact lock을 기다려 self-deadlock하므로, 연관 작업은 한 callback에 둔다.\n */\ninterface PgOpaqueAdvisoryLocks {\n    withLock<T>(key: OpaqueAdvisoryLockKey, operation: () => T | Promise<T>): Promise<T>;\n}",
          "sourceDocumentation": "lifecycle work를 short-lived PostgreSQL advisory transaction lock 아래 실행하는 표면.\n\ncallback에 SQL session을 전달하지 않는다. 이 API의 목적은 host DB transaction/worker\nlifecycle의 **순서화**이며, 다른 ORM connection의 transaction과 2PC 원자성을 만들지\n않는다. callback은 local durable work만 수행하고 provider/HTTP 같은 긴 network I/O는\n넣지 않아야 한다. callback 안에서 같은 key로 이 facility를 재진입하면 다른 connection이\n바깥 transaction의 xact lock을 기다려 self-deadlock하므로, 연관 작업은 한 callback에 둔다."
        },
        {
          "name": "PgOpaqueAdvisoryLocksOptions",
          "slug": "pg-opaque-advisory-locks-options",
          "kind": "interface",
          "declaration": "/** 개별 factory 사용 시 aggregate와 같은 schema namespace를 선택하는 옵션. */\ninterface PgOpaqueAdvisoryLocksOptions {\n    /** 기본 `'toss_payments'`. aggregate는 자신의 검증된 schema를 자동 전달한다. */\n    readonly schema?: string;\n}",
          "sourceDocumentation": "개별 factory 사용 시 aggregate와 같은 schema namespace를 선택하는 옵션."
        },
        {
          "name": "PgPoolClientLike",
          "slug": "pg-pool-client-like",
          "kind": "interface",
          "declaration": "/** `pool.connect()`가 내주는 커넥션의 필요 부분만 — pg.PoolClient가 구조 대입된다. */\ninterface PgPoolClientLike {\n    query(text: string, values?: readonly unknown[]): Promise<PgQueryResultLike>;\n    /** truthy err 전달 시 커넥션 폐기(pg 시맨틱) — 트랜잭션 잔존 상태 재사용 방지. */\n    release(err?: unknown): void;\n}",
          "sourceDocumentation": "`pool.connect()`가 내주는 커넥션의 필요 부분만 — pg.PoolClient가 구조 대입된다."
        },
        {
          "name": "PgPoolLike",
          "slug": "pg-pool-like",
          "kind": "interface",
          "declaration": "/**\n * `pg.Pool`이 그대로 대입되는 구조적 타입 — `query(text, values)`와\n * `connect()`만 요구한다. pg를 import하지 않으므로 런타임·타입 의존성 모두 0.\n */\ninterface PgPoolLike {\n    query(text: string, values?: readonly unknown[]): Promise<PgQueryResultLike>;\n    connect(): Promise<PgPoolClientLike>;\n}",
          "sourceDocumentation": "`pg.Pool`이 그대로 대입되는 구조적 타입 — `query(text, values)`와\n`connect()`만 요구한다. pg를 import하지 않으므로 런타임·타입 의존성 모두 0."
        },
        {
          "name": "PgQueryResultLike",
          "slug": "pg-query-result-like",
          "kind": "interface",
          "declaration": "/** pg QueryResult의 필요 부분만 — `rows: any[]`가 그대로 구조 대입된다. */\ninterface PgQueryResultLike {\n    readonly rows: readonly SqlRow[];\n}",
          "sourceDocumentation": "pg QueryResult의 필요 부분만 — `rows: any[]`가 그대로 구조 대입된다."
        },
        {
          "name": "PgSensitiveStoreOptions",
          "slug": "pg-sensitive-store-options",
          "kind": "interface",
          "declaration": "/** schema + 필수 민감값 보호기를 함께 받는 세 민감 스토어의 옵션 표면. */\ninterface PgSensitiveStoreOptions extends PgStoreOptions {\n    readonly sensitiveValueProtector: SensitiveValueProtector;\n}",
          "sourceDocumentation": "schema + 필수 민감값 보호기를 함께 받는 세 민감 스토어의 옵션 표면."
        },
        {
          "name": "PgStoreOptions",
          "slug": "pg-store-options",
          "kind": "interface",
          "declaration": "/**\n * OrderStore PostgreSQL 구현 — 금액 대조의 단일 진실 공급원 (설계 §3.1).\n *\n * 코어 계약의 핵심 불변식:\n * - `saveOrder`는 **insert-only + 동일값 재저장 무해**다. 조용한 upsert로 원본 금액을\n *   덮으면 confirm의 금액 대조 검증 전체가 무력화된다 — 다른 값 재저장은\n *   `order-conflict`로 throw하고, 동일값 재시도(네트워크 재시도 등)는 멱등하게 성공한다.\n *   동일값 판정은 **대조 원본인 amount·currency·orderName만** 본다 — createdAt은 코어\n *   createOrder가 호출마다 clock()으로 새로 찍으므로(confirm.ts), 비교에 넣으면\n *   소비자 orderId 재제출(더블클릭 등)이 항상 conflict가 되어 멱등 보장이 도달\n *   불가능해진다. 최초 저장본의 createdAt이 유지된다.\n * - `createdAt`은 코어가 string으로 준 원문을 text로 왕복 보존한다(재직렬화 손실 금지).\n * - pg 드라이버는 bigint를 string으로 반환한다 — `loadOrder`는 Number 변환 후\n *   `Number.isSafeInteger` 검증을 통과한 값만 내보낸다(정밀도 손실 거부).\n */\ninterface PgStoreOptions {\n    /** 기본 'toss_payments'. `/^[a-z_][a-z0-9_]{0,62}$/` 위반 시 즉시 throw. */\n    readonly schema?: string;\n}",
          "sourceDocumentation": "OrderStore PostgreSQL 구현 — 금액 대조의 단일 진실 공급원 (설계 §3.1).\n\n코어 계약의 핵심 불변식:\n- `saveOrder`는 **insert-only + 동일값 재저장 무해**다. 조용한 upsert로 원본 금액을\n  덮으면 confirm의 금액 대조 검증 전체가 무력화된다 — 다른 값 재저장은\n  `order-conflict`로 throw하고, 동일값 재시도(네트워크 재시도 등)는 멱등하게 성공한다.\n  동일값 판정은 **대조 원본인 amount·currency·orderName만** 본다 — createdAt은 코어\n  createOrder가 호출마다 clock()으로 새로 찍으므로(confirm.ts), 비교에 넣으면\n  소비자 orderId 재제출(더블클릭 등)이 항상 conflict가 되어 멱등 보장이 도달\n  불가능해진다. 최초 저장본의 createdAt이 유지된다.\n- `createdAt`은 코어가 string으로 준 원문을 text로 왕복 보존한다(재직렬화 손실 금지).\n- pg 드라이버는 bigint를 string으로 반환한다 — `loadOrder`는 Number 변환 후\n  `Number.isSafeInteger` 검증을 통과한 값만 내보낸다(정밀도 손실 거부)."
        },
        {
          "name": "PgWebhookDedupeStoreOptions",
          "slug": "pg-webhook-dedupe-store-options",
          "kind": "interface",
          "declaration": "/**\n * WebhookDedupeStore PostgreSQL 구현 (설계 §3.5).\n *\n * 코어 계약의 핵심 불변식(verifier.ts TSDoc):\n * - **claim은 원자적이어야 한다** — 조회 후 생성하는 2단계 구현은 TOCTOU 레이스라\n *   금지. 그래서 INSERT ... ON CONFLICT DO UPDATE + CTE **단일 문**으로 전이한다.\n * - processing 레코드는 lease 만료 후 재점유 가능해야 한다(crash-recovery).\n * - completed에는 토스의 최장 재전송 기간보다 긴 TTL(권장 5일)을 적용한다 —\n *   TTL 삭제는 cleanup()(팩토리) 소관이며 이 스토어는 지우지 않는다.\n * - `complete`는 비즈니스 핸들러의 내구적 처리 완료 후에만, `release`는 처리 실패 시\n *   재전송 재점유를 위해 호출된다 — release는 completed 행을 절대 지우지 않는다.\n * - ⚠ 알려진 계약 한계: 코어 `release(dedupeKey)`에는 소유 토큰(fencing token)이\n *   없다 — lease 만료 후 다른 워커가 재점유한 뒤에 도착한 원래 워커의 늦은 release가\n *   새 claim의 processing 행을 지울 수 있는 창이 이론상 존재한다(이후 재전송이\n *   'claimed'를 받아 동시 처리 창이 열림). 스토어 구현만으로는 어느 워커의 release인지\n *   판별할 수 없어 이 계층에서 완전 차단이 불가능하다(코어 계약 보완 후보). 실전\n *   완화책은 `dedupe.leaseSeconds`(기본 60)를 핸들러 최대 처리 시간보다 길게 잡는 것.\n */\ninterface PgWebhookDedupeStoreOptions extends PgStoreOptions {\n    /** processing 행의 crash-recovery lease(초). 기본 60. */\n    readonly leaseSeconds?: number;\n}",
          "sourceDocumentation": "WebhookDedupeStore PostgreSQL 구현 (설계 §3.5).\n\n코어 계약의 핵심 불변식(verifier.ts TSDoc):\n- **claim은 원자적이어야 한다** — 조회 후 생성하는 2단계 구현은 TOCTOU 레이스라\n  금지. 그래서 INSERT ... ON CONFLICT DO UPDATE + CTE **단일 문**으로 전이한다.\n- processing 레코드는 lease 만료 후 재점유 가능해야 한다(crash-recovery).\n- completed에는 토스의 최장 재전송 기간보다 긴 TTL(권장 5일)을 적용한다 —\n  TTL 삭제는 cleanup()(팩토리) 소관이며 이 스토어는 지우지 않는다.\n- `complete`는 비즈니스 핸들러의 내구적 처리 완료 후에만, `release`는 처리 실패 시\n  재전송 재점유를 위해 호출된다 — release는 completed 행을 절대 지우지 않는다.\n- ⚠ 알려진 계약 한계: 코어 `release(dedupeKey)`에는 소유 토큰(fencing token)이\n  없다 — lease 만료 후 다른 워커가 재점유한 뒤에 도착한 원래 워커의 늦은 release가\n  새 claim의 processing 행을 지울 수 있는 창이 이론상 존재한다(이후 재전송이\n  'claimed'를 받아 동시 처리 창이 열림). 스토어 구현만으로는 어느 워커의 release인지\n  판별할 수 없어 이 계층에서 완전 차단이 불가능하다(코어 계약 보완 후보). 실전\n  완화책은 `dedupe.leaseSeconds`(기본 60)를 핸들러 최대 처리 시간보다 길게 잡는 것."
        },
        {
          "name": "renderMigrationSql",
          "slug": "render-migration-sql",
          "kind": "function",
          "declaration": "/**\n * 자체 마이그레이션 도구(Flyway/dbmate 등) 사용자용 전체 스크립트 (설계 §4).\n *\n * migrate()와 **동일한 SQL**을 주석 헤더와 함께 이어 붙인 순수 문자열이다 —\n * 단, 버전 테이블(toss_pg_migrations) 관리 문은 제외한다(버전 관리는 외부 도구 소관).\n */\ndeclare function renderMigrationSql(options?: MigrateOptions): string;",
          "sourceDocumentation": "자체 마이그레이션 도구(Flyway/dbmate 등) 사용자용 전체 스크립트 (설계 §4).\n\nmigrate()와 **동일한 SQL**을 주석 헤더와 함께 이어 붙인 순수 문자열이다 —\n단, 버전 테이블(toss_pg_migrations) 관리 문은 제외한다(버전 관리는 외부 도구 소관)."
        },
        {
          "name": "SENSITIVE_VALUE_PURPOSE",
          "slug": "sensitive-value-purpose",
          "kind": "constant",
          "declaration": "SENSITIVE_VALUE_PURPOSE: {\n    readonly billingKey: \"billing-key\";\n    readonly depositSecret: \"deposit-secret\";\n    readonly cancelRetryRecord: \"cancel-retry-record\";\n}",
          "sourceDocumentation": "이 패키지가 보호하는 값의 용도. 보호기 구현은 이 값을 AAD에 반드시 포함해야 한다."
        },
        {
          "name": "SensitiveValueContext",
          "slug": "sensitive-value-context",
          "kind": "interface",
          "declaration": "/**\n * 보호기 호출마다 전달되는 AAD 결속 정보.\n *\n * `recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n * 암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n * 포함해야 한다.\n */\ninterface SensitiveValueContext {\n    readonly purpose: SensitiveValuePurpose;\n    readonly recordId: string;\n}",
          "sourceDocumentation": "보호기 호출마다 전달되는 AAD 결속 정보.\n\n`recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n포함해야 한다."
        },
        {
          "name": "SensitiveValueProtector",
          "slug": "sensitive-value-protector",
          "kind": "interface",
          "declaration": "/**\n * 앱이 소유하는 비동기 민감값 보호기.\n *\n * AES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n * 들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n * 하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n * 평문을 포함하지 않아야 한다.\n *\n * 이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\n * ASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\n * AES-256-GCM 보호기는 `TypeError`로 거부한다.\n */\ninterface SensitiveValueProtector {\n    encrypt(plaintext: string, context: SensitiveValueContext): Promise<string>;\n    decrypt(ciphertext: string, context: SensitiveValueContext): Promise<string>;\n}",
          "sourceDocumentation": "앱이 소유하는 비동기 민감값 보호기.\n\nAES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n평문을 포함하지 않아야 한다.\n\n이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\nASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\nAES-256-GCM 보호기는 `TypeError`로 거부한다."
        },
        {
          "name": "SensitiveValueProtectorError",
          "slug": "sensitive-value-protector-error",
          "kind": "class",
          "declaration": "/**\n * Error thrown by `createAes256GcmSensitiveValueProtector().decrypt`.\n *\n * `code` is the public contract; the message is not. Messages never contain key material,\n * plaintext, or ciphertext. Use `isSensitiveValueProtectorError` instead of `instanceof`.\n */\ndeclare class SensitiveValueProtectorError extends Error {\n    readonly name = \"SensitiveValueProtectorError\";\n    readonly code: SensitiveValueProtectorErrorCode;\n    constructor(code: SensitiveValueProtectorErrorCode, message: string);\n}",
          "sourceDocumentation": "Error thrown by `createAes256GcmSensitiveValueProtector().decrypt`.\n\n`code` is the public contract; the message is not. Messages never contain key material,\nplaintext, or ciphertext. Use `isSensitiveValueProtectorError` instead of `instanceof`."
        },
        {
          "name": "SensitiveValueProtectorErrorCode",
          "slug": "sensitive-value-protector-error-code",
          "kind": "type",
          "declaration": "/** Stable failure codes of the reference AES-256-GCM protector. */\ntype SensitiveValueProtectorErrorCode = \n/** The stored string is not a `{ v: 1, alg: 'A256GCM', … }` envelope this protector produced. */\n'invalid-envelope'\n/** The envelope names a different `kid` than this protector's `keyId` (or one side has none). */\n | 'key-id-mismatch'\n/** Wrong key, ciphertext moved to another purpose/recordId, or tampered bytes — not distinguished. */\n | 'authentication-failed';",
          "sourceDocumentation": "Stable failure codes of the reference AES-256-GCM protector."
        },
        {
          "name": "SensitiveValuePurpose",
          "slug": "sensitive-value-purpose--type",
          "kind": "type",
          "declaration": "type SensitiveValuePurpose = (typeof SENSITIVE_VALUE_PURPOSE)[keyof typeof SENSITIVE_VALUE_PURPOSE];"
        },
        {
          "name": "SqlClient",
          "slug": "sql-client",
          "kind": "interface",
          "declaration": "interface SqlClient extends SqlExecutor {\n    /**\n     * 단일 세션에 고정된 실행기로 fn을 실행한다 — migrate()·billing-key mutation lock·opaque\n     * lifecycle advisory lock의 transaction이 풀의 서로 다른 커넥션으로 흩어지지 않기 위한 요구다.\n     */\n    withConnection<T>(fn: (session: SqlExecutor) => Promise<T>): Promise<T>;\n}"
        },
        {
          "name": "SqlExecutor",
          "slug": "sql-executor",
          "kind": "interface",
          "declaration": "interface SqlExecutor {\n    /** `$1, $2` 위치 파라미터 규약(PostgreSQL 프로토콜). 실패는 그대로 throw. */\n    query(text: string, params?: readonly unknown[]): Promise<SqlResult>;\n}"
        },
        {
          "name": "SqlResult",
          "slug": "sql-result",
          "kind": "interface",
          "declaration": "interface SqlResult {\n    readonly rows: readonly SqlRow[];\n}"
        },
        {
          "name": "SqlRow",
          "slug": "sql-row",
          "kind": "interface",
          "declaration": "/**\n * SqlClient seam — 이 패키지의 유일한 드라이버 접점 (설계 §2).\n *\n * `pg`는 peer조차 아니다: 타입 import까지 금지하고 구조적 타입 {@link PgPoolLike}만\n * 소비한다. TypeORM/Prisma/postgres.js 사용자는 {@link SqlClient}를 직접 구현한다.\n *\n * 계약 요점:\n * - `$1, $2` 위치 파라미터 규약(PostgreSQL 프로토콜). 실패는 그대로 throw —\n *   드라이버 에러를 감싸지 않는다(errors.ts 원칙).\n * - `rowCount`에 의존하지 않는다 — 존재 판정은 전부 RETURNING/SELECT의 rows로 한다\n *   (드라이버 간 이식성: rowCount 노출 형태가 제각각이다).\n * - `withConnection`은 migrate()·PostgreSQL billing-key mutation lock·opaque lifecycle\n *   advisory lock의 트랜잭션이 풀의 서로 다른 커넥션으로 흩어지지 않게 한다. 일반\n *   스토어 경로는 단일 문이지만 lock callback은 이 세션을 유지한다.\n */\ninterface SqlRow {\n    readonly [column: string]: unknown;\n}",
          "sourceDocumentation": "SqlClient seam — 이 패키지의 유일한 드라이버 접점 (설계 §2).\n\n`pg`는 peer조차 아니다: 타입 import까지 금지하고 구조적 타입 {@link PgPoolLike}만\n소비한다. TypeORM/Prisma/postgres.js 사용자는 {@link SqlClient}를 직접 구현한다.\n\n계약 요점:\n- `$1, $2` 위치 파라미터 규약(PostgreSQL 프로토콜). 실패는 그대로 throw —\n  드라이버 에러를 감싸지 않는다(errors.ts 원칙).\n- `rowCount`에 의존하지 않는다 — 존재 판정은 전부 RETURNING/SELECT의 rows로 한다\n  (드라이버 간 이식성: rowCount 노출 형태가 제각각이다).\n- `withConnection`은 migrate()·PostgreSQL billing-key mutation lock·opaque lifecycle\n  advisory lock의 트랜잭션이 풀의 서로 다른 커넥션으로 흩어지지 않게 한다. 일반\n  스토어 경로는 단일 문이지만 lock callback은 이 세션을 유지한다."
        },
        {
          "name": "TossPaymentsPostgres",
          "slug": "toss-payments-postgres",
          "kind": "interface",
          "declaration": "interface TossPaymentsPostgres {\n    readonly orders: OrderStore;\n    readonly depositSecrets: DepositSecretStore;\n    /**\n     * 코어 BillingKeyStore + PostgreSQL conditional compare-and-mutate 확장.\n     *\n     * `deleteIfBillingKeyMatches`/`replaceIfBillingKeyMatches`는 stale BILLING_DELETED와\n     * projection 보상 경합에서 무조건 delete/save 대신 사용하는 원자적 API다.\n     */\n    readonly billingKeys: PgBillingKeyStore;\n    readonly cancelRetries: CancelRetryStore;\n    readonly webhookDedupe: WebhookDedupeStore;\n    readonly audit: AuditSink & {\n        flush(): Promise<void>;\n    };\n    readonly inbox: WebhookInboxStore;\n    /**\n     * 앱이 만든 nonsecret HMAC/blind-index key로 짧은 host lifecycle을 인스턴스 간\n     * 순서화하는 PostgreSQL advisory transaction lock facility.\n     *\n     * 이 API는 다른 ORM connection의 transaction과 2PC 원자성을 만들지 않는다. provider\n     * network I/O가 아니라 local durable finalization만 callback에 넣어야 한다.\n     */\n    readonly opaqueLocks: PgOpaqueAdvisoryLocks;\n    /** 명시 호출 전용 — 부팅 시 자동 실행 없음. `app.listen` 전에 await하는 것이 골든 패스. */\n    migrate(): Promise<MigrationResult>;\n    /**\n     * TTL 행 정리 — 명시 호출 전용(자동 타이머 없음). audit_entries·webhook_inbox·\n     * orders·deposit_secrets는 지우지 않는다 — 보관 정책은 소비자 책임.\n     */\n    cleanup(): Promise<CleanupResult>;\n}"
        },
        {
          "name": "TossPaymentsPostgresOptions",
          "slug": "toss-payments-postgres-options",
          "kind": "interface",
          "declaration": "/**\n * createTossPaymentsPostgres — 스토어 집합체 팩토리 (설계 §5) + cleanup (설계 §6).\n *\n * 팩토리는 **순수 조립**이다 — 즉시 DB 접속이 없고 첫 쿼리가 첫 접점이다. 스키마\n * 식별자 검증만 조립 시점에 수행해 잘못된 설정을 즉시 드러낸다(fail-fast).\n * 부팅 시 자동 DDL도, 자동 cleanup 타이머도 없다 — 모든 옵션 기본 꺼짐 원칙.\n */\ninterface TossPaymentsPostgresOptions {\n    readonly sql: SqlClient;\n    /**\n     * billing key·deposit secret·cancel retry record의 필수 at-rest 보호기.\n     *\n     * 기본값은 없다. 평문 개발 DB를 의도적으로 써야 할 때만\n     * `unsafePlaintextSensitiveValueProtector`를 명시해 전달한다. 보호기는 `purpose`와\n     * `recordId`를 AAD에 결속해야 한다.\n     */\n    readonly sensitiveValueProtector: SensitiveValueProtector;\n    /** 기본 'toss_payments'. `/^[a-z_][a-z0-9_]{0,62}$/` 위반 시 조립 시점에 throw. */\n    readonly schema?: string;\n    readonly dedupe?: {\n        /** processing 행의 crash-recovery lease(초). 기본 60. */\n        readonly leaseSeconds?: number;\n        /**\n         * completed 행의 TTL(초). 기본 432_000(5일) — 코어 TSDoc \"토스 최장 재전송\n         * 기간보다 긴 TTL, 권장 5일\". 삭제는 cleanup() 호출 시에만 일어난다.\n         */\n        readonly completedTtlSeconds?: number;\n    };\n    readonly retention?: {\n        /**\n         * cancel_retries 보존 일수. 기본 15 — 토스 멱등키 유효기간과 일치.\n         * **양의 정수**여야 한다(cleanup SQL의 make_interval days 파라미터가 int) —\n         * 소수는 조립 시점에 TypeError로 거부된다.\n         */\n        readonly cancelRetryDays?: number;\n    };\n}",
          "sourceDocumentation": "createTossPaymentsPostgres — 스토어 집합체 팩토리 (설계 §5) + cleanup (설계 §6).\n\n팩토리는 **순수 조립**이다 — 즉시 DB 접속이 없고 첫 쿼리가 첫 접점이다. 스키마\n식별자 검증만 조립 시점에 수행해 잘못된 설정을 즉시 드러낸다(fail-fast).\n부팅 시 자동 DDL도, 자동 cleanup 타이머도 없다 — 모든 옵션 기본 꺼짐 원칙."
        },
        {
          "name": "TossPostgresError",
          "slug": "toss-postgres-error",
          "kind": "class",
          "declaration": "/** 이 패키지가 직접 판정한 실패 전용 에러 — code가 공개 계약이다(메시지는 아니다). */\ndeclare class TossPostgresError extends Error {\n    readonly name = \"TossPostgresError\";\n    readonly code: TossPostgresErrorCode;\n    constructor(code: TossPostgresErrorCode, message: string, options?: {\n        readonly cause?: unknown;\n    });\n}",
          "sourceDocumentation": "이 패키지가 직접 판정한 실패 전용 에러 — code가 공개 계약이다(메시지는 아니다)."
        },
        {
          "name": "TossPostgresErrorCode",
          "slug": "toss-postgres-error-code",
          "kind": "type",
          "declaration": "/**\n * 에러 모델 — 이 패키지가 스스로 만든 실패만 감싼다 (설계 §5).\n *\n * 코어 계약상 스토어는 **throw**하고, 코어가 store-failure Err로 감싼다(cause 체인 동봉).\n * 따라서 여기의 원칙은 둘뿐이다:\n * - 드라이버 에러는 감싸지 않고 그대로 통과시킨다 — cause 체인·드라이버 고유 필드\n *   (SQLSTATE 등)를 보존해야 소비자가 재시도/알림 정책을 세울 수 있다.\n * - 이 패키지가 직접 판정한 실패(식별자 위반·주문 충돌·안전하지 않은 금액·행 손상·\n *   마이그레이션 실패)만 안정적인 code를 가진 {@link TossPostgresError}로 던진다.\n *\n * ⚠ 보안 불변식: 어떤 에러 메시지에도 secret·billingKey 값을 싣지 않는다.\n * billingKey와 customerKey를 같은 문자열에 함께 두지 않는다(코어 stores.ts ⚠ 준수).\n */\ntype TossPostgresErrorCode = \n/** 스키마 식별자가 `/^[a-z_][a-z0-9_]{0,62}$/` 위반 — SQL 보간 유일 지점의 봉쇄. */\n'invalid-identifier'\n/** saveOrder가 이미 저장된 orderId에 **다른 값**으로 재저장 시도 — 금액 대조 원본 보호. */\n | 'order-conflict'\n/** bigint 컬럼 값이 Number.isSafeInteger 범위를 벗어남 — 금액 정밀도 손실 거부. */\n | 'unsafe-amount'\n/** DB 행이 코어 계약 형태로 복원 불가(타입/유니언 위반·JSON 손상) — 조용한 오염 전파 거부. */\n | 'invalid-row'\n/** migrate() 실패 — ROLLBACK 후 원인은 cause 체인으로 보존된다. */\n | 'migration-failed';",
          "sourceDocumentation": "에러 모델 — 이 패키지가 스스로 만든 실패만 감싼다 (설계 §5).\n\n코어 계약상 스토어는 **throw**하고, 코어가 store-failure Err로 감싼다(cause 체인 동봉).\n따라서 여기의 원칙은 둘뿐이다:\n- 드라이버 에러는 감싸지 않고 그대로 통과시킨다 — cause 체인·드라이버 고유 필드\n  (SQLSTATE 등)를 보존해야 소비자가 재시도/알림 정책을 세울 수 있다.\n- 이 패키지가 직접 판정한 실패(식별자 위반·주문 충돌·안전하지 않은 금액·행 손상·\n  마이그레이션 실패)만 안정적인 code를 가진 {@link TossPostgresError}로 던진다.\n\n⚠ 보안 불변식: 어떤 에러 메시지에도 secret·billingKey 값을 싣지 않는다.\nbillingKey와 customerKey를 같은 문자열에 함께 두지 않는다(코어 stores.ts ⚠ 준수)."
        },
        {
          "name": "unsafePlaintextSensitiveValueProtector",
          "slug": "unsafe-plaintext-sensitive-value-protector",
          "kind": "constant",
          "declaration": "unsafePlaintextSensitiveValueProtector: SensitiveValueProtector",
          "sourceDocumentation": "테스트·일회성 개발 DB 전용의 명시적 평문 opt-in.\n\n이 값을 넘기지 않으면 팩토리와 민감 스토어 팩토리는 조립 시점에 거부한다. 즉, 평문\n저장은 숨은 기본값이 아니라 호출 코드에서 보이는 의도적인 선택이다. 프로덕션에는\n절대 사용하지 말고 KMS/AEAD 기반 `SensitiveValueProtector`를 제공해야 한다."
        },
        {
          "name": "WebhookInboxStore",
          "slug": "webhook-inbox-store",
          "kind": "interface",
          "declaration": "/**\n * 웹훅 inbox — 이벤트 원문 보존 (설계 §3.7).\n *\n * 코어 `WebhookDedupeStore.claim`에는 이벤트 메타가 전달되지 않으므로, inbox는 스토어\n * seam이 아니라 **`WebhookHandlers`를 감싸는 헬퍼**다(코어 계약 무변경). 불변식:\n * - 사업 이벤트 1건 = 1행(dedupe_key PK). 재전송은 deliveries 증가로 관측된다.\n * - record는 핸들러 **앞**에서 실행한다 — 핸들러가 실패해도 수신 사실은 남는다\n *   (감사·재처리 목적).\n * - record 실패 기본 동작은 **삼키고 onRecordError 통지**다(AuditSink 선례 — 관측\n *   계층이 웹훅 가용성을 볼모로 잡지 않는다). `failOnRecordError: true`면 throw →\n *   어댑터 500 → 토스 재전송(inbox를 내구 계약으로 쓰는 소비자용).\n * - 저장 전 이벤트의 모든 깊이 credential/secret/billingKey/authKey/token/password/card/\n *   account 계열 키를 마스킹한다 — provider payload는 새 필드와 중첩 raw를 포함할 수\n *   있고 이 테이블은 cleanup() 대상이 아니라 무기한 보존된다. 핸들러에는 원본을\n *   그대로 주되 저장본만 별도 객체로 마스킹한다.\n */\n/** 수동 기록 표면 — `withWebhookInbox`가 내부에서 쓰는 것과 동일한 단일 메서드. */\ninterface WebhookInboxStore {\n    record(webhook: AcceptedWebhook): Promise<void>;\n}",
          "sourceDocumentation": "수동 기록 표면 — `withWebhookInbox`가 내부에서 쓰는 것과 동일한 단일 메서드."
        },
        {
          "name": "withWebhookInbox",
          "slug": "with-webhook-inbox",
          "kind": "function",
          "declaration": "/**\n * handlers의 각 콜백을 record → inner 순서로 감싼 `WebhookHandlers`를 반환한다.\n *\n * 배선된 핸들러 키만 감싼다 — 키 집합이 변하지 않으므로 코어 어댑터의 \"핸들러 없는\n * 이벤트\" 처리 동작(무시)도 그대로 보존된다. 콜백은 `handlers`를 수신자(this)로\n * 호출한다 — 코어 어댑터의 메서드 호출(`handlers.onX?.(w)`)과 동일한 시맨틱이라,\n * `this`를 참조하는 객체 리터럴/클래스 인스턴스 핸들러가 래핑 후에도 깨지지 않는다.\n */\ndeclare function withWebhookInbox(inbox: WebhookInboxStore, handlers: WebhookHandlers, options?: WithWebhookInboxOptions): WebhookHandlers;",
          "sourceDocumentation": "handlers의 각 콜백을 record → inner 순서로 감싼 `WebhookHandlers`를 반환한다.\n\n배선된 핸들러 키만 감싼다 — 키 집합이 변하지 않으므로 코어 어댑터의 \"핸들러 없는\n이벤트\" 처리 동작(무시)도 그대로 보존된다. 콜백은 `handlers`를 수신자(this)로\n호출한다 — 코어 어댑터의 메서드 호출(`handlers.onX?.(w)`)과 동일한 시맨틱이라,\n`this`를 참조하는 객체 리터럴/클래스 인스턴스 핸들러가 래핑 후에도 깨지지 않는다."
        },
        {
          "name": "WithWebhookInboxOptions",
          "slug": "with-webhook-inbox-options",
          "kind": "interface",
          "declaration": "interface WithWebhookInboxOptions {\n    /**\n     * record 실패 통지(기본 동작: 삼킴). 이벤트 본문 대신 meta만 전달한다 —\n     * 통지 콜백이 로그로 흘러도 이벤트 payload가 함께 새지 않게. 이 콜백의 throw도 삼켜진다.\n     */\n    readonly onRecordError?: (cause: unknown, meta: WebhookMeta) => void;\n    /** true면 record 실패를 그대로 throw — 어댑터 500 → 토스 재전송. 기본 false. */\n    readonly failOnRecordError?: boolean;\n}"
        }
      ]
    },
    {
      "subpath": "./nestjs",
      "id": "nestjs",
      "declarationTarget": "./dist/nestjs.d.cts",
      "symbols": [
        {
          "name": "InjectTossPaymentsPostgres",
          "slug": "inject-toss-payments-postgres",
          "kind": "constant",
          "declaration": "InjectTossPaymentsPostgres: () => ParameterDecorator",
          "sourceDocumentation": "스토어 집합체 주입 데코레이터.\n\n```ts\nconstructor("
        },
        {
          "name": "PgBillingKeyMutation",
          "slug": "pg-billing-key-mutation",
          "kind": "interface",
          "declaration": "/**\n * BillingKeyStore PostgreSQL 구현 (설계 §3.3).\n *\n * 코어 계약의 핵심 불변식:\n * - 토스에 빌링키 조회 API가 없다 — **저장 실패 = 복구 불가**. 이 테이블이 유일한\n *   보관 수단이므로 save는 드라이버 에러를 감추지 않고 그대로 던진다(코어가 감쌈).\n * - `save`는 upsert(customer_key)다 — issue/import 양쪽에서 호출되는 계약이고 코어가\n *   교체 정책을 규정하지 않으므로 최신 발급본을 유지한다.\n * - `billing_key`에는 BillingKeyRecord 전체의 보호된 JSON 문자열만 쓴다. `card`와\n *   `transfers`까지 함께 보호해 계좌번호 등 부수 메타데이터가 jsonb에 평문으로 남지\n *   않게 한다. method/issued_at은 운영 조회용 비밀이 아닌 최소 메타데이터로만 남긴다.\n * - ⚠ 보안 불변식(코어 stores.ts): 어떤 에러 메시지에도 billing_key 값을 싣지 않고,\n *   customerKey와 billingKey를 같은 문자열(로그 한 줄)에 함께 두지 않는다 — 토스의\n *   빌링 보안 모델이 이 쌍의 분리에 의존한다. 이 파일의 메시지는 둘 다 싣지 않는다.\n */\n/**\n * `withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n *\n * 핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n * `pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n * 되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다.\n */\ninterface PgBillingKeyMutation {\n    readonly customerKey: BillingKeyRecord['customerKey'];\n    find(): Promise<BillingKeyRecord | null>;\n    save(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<void>;\n    /**\n     * 현재 raw billing key와 일치할 때만 삭제한다. 무조건 삭제 API는 의도적으로 없다.\n     */\n    delete(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 저장 당시의 nonsecret operationId fingerprint가 예상 operationId와 같은지 확인한다.\n     * callback 내부에서만 쓰며 raw operationId/fingerprint 어느 것도 반환하지 않는다.\n     */\n    isCurrentOperationId(operationId: string): Promise<boolean>;\n    deleteIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "`withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n\n핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n`pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다."
        },
        {
          "name": "PgBillingKeySnapshot",
          "slug": "pg-billing-key-snapshot",
          "kind": "interface",
          "declaration": "/**\n * Opaque previous snapshot returned by `replaceAndGetPrevious`.\n *\n * Only `record` is readable, for recovery or display. Passing the original snapshot object\n * back to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\n * The fingerprint and the trusted record are linked only through a module-private\n * `WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\n * registry identity and the lifecycle fence is intentionally false after such a restore.\n */\ninterface PgBillingKeySnapshot {\n    readonly record: BillingKeyRecord;\n}",
          "sourceDocumentation": "Opaque previous snapshot returned by `replaceAndGetPrevious`.\n\nOnly `record` is readable, for recovery or display. Passing the original snapshot object\nback to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\nThe fingerprint and the trusted record are linked only through a module-private\n`WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\nregistry identity and the lifecycle fence is intentionally false after such a restore."
        },
        {
          "name": "PgBillingKeyStore",
          "slug": "pg-billing-key-store",
          "kind": "interface",
          "declaration": "/**\n * PostgreSQL이 제공하는 BillingKeyStore 확장.\n *\n * 코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n * 지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\n * fence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n *\n * `replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\n * customerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\n * compare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\n * issuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n * 잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다.\n */\ninterface PgBillingKeyStore extends BillingKeyStore {\n    /**\n     * customerKey별 PostgreSQL advisory transaction lock을 callback 전체에 유지한다.\n     *\n     * 같은 customerKey의 generic 저장과 앱 projection을 순서대로 끝내야 할 때의\n     * cross-instance fence다. 모든 경쟁 issuance/deletion/compensation이 이 API를 사용해야\n     * 한다. callback 성공 시 commit, throw 시 generic billing key 변경은 rollback된다.\n     * callback 안에서는 전달된 mutation handle만 사용하고 바깥 store를 재호출하지 않는다.\n     */\n    withMutationLock<T>(customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * opaque lifecycle lock과 customerKey mutation lock을 **같은 PostgreSQL connection과\n     * transaction**에서 `opaque → customer` 순서로 획득한다.\n     *\n     * credential issuance/revocation/compensation처럼 host lifecycle과 generic billing-key\n     * mutation을 함께 직렬화해야 할 때의 유일한 composable API다. callback은 두 lock을 모두\n     * 얻은 뒤에만 기존 customer-bound mutation handle을 받는다. callback 안에서는 handle만\n     * 사용하고 `opaqueLocks.withLock` 또는 outer billing store를 재진입하지 않는다.\n     *\n     * `opaqueLocks.withLock(key, () => withMutationLock(...))`처럼 두 public API를 중첩하면\n     * 서로 다른 `withConnection`을 열어 pool max=1에서 self-deadlock할 수 있고, 한\n     * transaction이라는 보장도 잃는다. 모든 결합 경로의 global lock order는 이 메서드가\n     * 강제하는 **opaque → customer**다.\n     */\n    withOpaqueMutationLock<T>(opaqueKey: OpaqueAdvisoryLockKey, customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * record를 저장하고, 같은 트랜잭션에서 잠근 직전 snapshot을 반환한다.\n     *\n     * 단일 generic write의 snapshot/보상에는 `find()` 뒤 `save()`보다 안전하다. 다만 앱\n     * projection까지 순서 보장이 필요하면 이 단독 메서드가 아니라 `withMutationLock` 안의\n     * 같은 이름 메서드를 사용한다. 그 callback 안에서 반환된 snapshot(첫 발급이면 null)을\n     * 이후 `replaceIfBillingKeyMatches(record.billingKey, previous)`에 전달하면 현재 값이\n     * 여전히 record일 때만 원자 복원/삭제할 수 있다. snapshot 원본을 그대로 넘기면 prior\n     * operation fingerprint까지 보존한다.\n     */\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 행을 삭제한다.\n     *\n     * 행이 없거나 현재 키가 다르면 false이고, 보호 payload 손상/복호화 실패는 숨기지 않고\n     * throw한다. false는 삭제되지 않았다는 안전한 결과이지 저장소 장애를 뜻하지 않는다.\n     */\n    deleteIfBillingKeyMatches(request: BillingKeyDeleteRequest): Promise<boolean>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 replacement로 교체한다.\n     *\n     * `replacement`가 null이면 조건부 삭제다. 보상 경로에서는 발급 직후 저장한 새 키를\n     * expected로, 이전 snapshot(또는 첫 발급이면 null)을 replacement로 전달한다. replacement의\n     * customerKey는 첫 인자와 반드시 같아야 한다.\n     */\n    replaceIfBillingKeyMatches(customerKey: BillingKeyRecord['customerKey'], expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "PostgreSQL이 제공하는 BillingKeyStore 확장.\n\n코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\nfence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n\n`replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\ncustomerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\ncompare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\nissuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다."
        },
        {
          "name": "PgSensitiveStoreOptions",
          "slug": "pg-sensitive-store-options",
          "kind": "interface",
          "declaration": "/** schema + 필수 민감값 보호기를 함께 받는 세 민감 스토어의 옵션 표면. */\ninterface PgSensitiveStoreOptions extends PgStoreOptions {\n    readonly sensitiveValueProtector: SensitiveValueProtector;\n}",
          "sourceDocumentation": "schema + 필수 민감값 보호기를 함께 받는 세 민감 스토어의 옵션 표면."
        },
        {
          "name": "SensitiveValueContext",
          "slug": "sensitive-value-context",
          "kind": "interface",
          "declaration": "/**\n * 보호기 호출마다 전달되는 AAD 결속 정보.\n *\n * `recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n * 암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n * 포함해야 한다.\n */\ninterface SensitiveValueContext {\n    readonly purpose: SensitiveValuePurpose;\n    readonly recordId: string;\n}",
          "sourceDocumentation": "보호기 호출마다 전달되는 AAD 결속 정보.\n\n`recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n포함해야 한다."
        },
        {
          "name": "SensitiveValueProtector",
          "slug": "sensitive-value-protector",
          "kind": "interface",
          "declaration": "/**\n * 앱이 소유하는 비동기 민감값 보호기.\n *\n * AES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n * 들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n * 하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n * 평문을 포함하지 않아야 한다.\n *\n * 이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\n * ASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\n * AES-256-GCM 보호기는 `TypeError`로 거부한다.\n */\ninterface SensitiveValueProtector {\n    encrypt(plaintext: string, context: SensitiveValueContext): Promise<string>;\n    decrypt(ciphertext: string, context: SensitiveValueContext): Promise<string>;\n}",
          "sourceDocumentation": "앱이 소유하는 비동기 민감값 보호기.\n\nAES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n평문을 포함하지 않아야 한다.\n\n이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\nASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\nAES-256-GCM 보호기는 `TypeError`로 거부한다."
        },
        {
          "name": "SensitiveValuePurpose",
          "slug": "sensitive-value-purpose",
          "kind": "type",
          "declaration": "type SensitiveValuePurpose = (typeof SENSITIVE_VALUE_PURPOSE)[keyof typeof SENSITIVE_VALUE_PURPOSE];"
        },
        {
          "name": "TOSS_PAYMENTS_POSTGRES",
          "slug": "toss-payments-postgres",
          "kind": "constant",
          "declaration": "TOSS_PAYMENTS_POSTGRES: unique symbol",
          "sourceDocumentation": "{@link import ('../factory').TossPaymentsPostgres} 집합체가 바인딩되는 토큰."
        },
        {
          "name": "TossPaymentsPostgres",
          "slug": "toss-payments-postgres--interface",
          "kind": "interface",
          "declaration": "interface TossPaymentsPostgres {\n    readonly orders: OrderStore;\n    readonly depositSecrets: DepositSecretStore;\n    /**\n     * 코어 BillingKeyStore + PostgreSQL conditional compare-and-mutate 확장.\n     *\n     * `deleteIfBillingKeyMatches`/`replaceIfBillingKeyMatches`는 stale BILLING_DELETED와\n     * projection 보상 경합에서 무조건 delete/save 대신 사용하는 원자적 API다.\n     */\n    readonly billingKeys: PgBillingKeyStore;\n    readonly cancelRetries: CancelRetryStore;\n    readonly webhookDedupe: WebhookDedupeStore;\n    readonly audit: AuditSink & {\n        flush(): Promise<void>;\n    };\n    readonly inbox: WebhookInboxStore;\n    /**\n     * 앱이 만든 nonsecret HMAC/blind-index key로 짧은 host lifecycle을 인스턴스 간\n     * 순서화하는 PostgreSQL advisory transaction lock facility.\n     *\n     * 이 API는 다른 ORM connection의 transaction과 2PC 원자성을 만들지 않는다. provider\n     * network I/O가 아니라 local durable finalization만 callback에 넣어야 한다.\n     */\n    readonly opaqueLocks: PgOpaqueAdvisoryLocks;\n    /** 명시 호출 전용 — 부팅 시 자동 실행 없음. `app.listen` 전에 await하는 것이 골든 패스. */\n    migrate(): Promise<MigrationResult>;\n    /**\n     * TTL 행 정리 — 명시 호출 전용(자동 타이머 없음). audit_entries·webhook_inbox·\n     * orders·deposit_secrets는 지우지 않는다 — 보관 정책은 소비자 책임.\n     */\n    cleanup(): Promise<CleanupResult>;\n}"
        },
        {
          "name": "TossPaymentsPostgresModule",
          "slug": "toss-payments-postgres-module",
          "kind": "class",
          "declaration": "declare class TossPaymentsPostgresModule {\n    /** 동기 조립 — `{ provide: TOSS_PAYMENTS_POSTGRES, useValue: createTossPaymentsPostgres(options) }`. */\n    static forRoot(options: TossPaymentsPostgresModuleOptions): DynamicModule;\n    /**\n     * 비동기 조립 — 골든 패스는 코어 모듈과의 연쇄다:\n     *\n     * ```ts\n     * TossPaymentsModule.forRootAsync({\n     *   imports: [TossPaymentsPostgresModule.forRootAsync({ ... })],\n     *   inject: [TOSS_PAYMENTS_POSTGRES],\n     *   useFactory: (pg: TossPaymentsPostgres) =>\n     *     defineTossPaymentsConfig({ secretKey, orders: pg.orders, ... }),\n     * })\n     * ```\n     */\n    static forRootAsync(options: TossPaymentsPostgresModuleAsyncOptions): DynamicModule;\n}"
        },
        {
          "name": "TossPaymentsPostgresModuleAsyncOptions",
          "slug": "toss-payments-postgres-module-async-options",
          "kind": "interface",
          "declaration": "/** forRootAsync 옵션 — pg Pool 등을 Nest 프로바이더(inject)로 받아 조립하는 경로. */\ninterface TossPaymentsPostgresModuleAsyncOptions {\n    readonly imports?: DynamicModule['imports'];\n    /** useFactory 파라미터로 주입할 프로바이더 토큰. 예: [ConfigService, PG_POOL] */\n    readonly inject?: readonly InjectionToken[];\n    /** 반환값에는 필수 `sensitiveValueProtector`를 포함한다. */\n    readonly useFactory: (...deps: readonly any[]) => TossPaymentsPostgresOptions | Promise<TossPaymentsPostgresOptions>;\n    /** 기본 true. 모듈 경계를 엄격히 유지하려면 false를 명시한다. */\n    readonly global?: boolean;\n}",
          "sourceDocumentation": "forRootAsync 옵션 — pg Pool 등을 Nest 프로바이더(inject)로 받아 조립하는 경로."
        },
        {
          "name": "TossPaymentsPostgresModuleOptions",
          "slug": "toss-payments-postgres-module-options",
          "kind": "interface",
          "declaration": "/**\n * forRoot 옵션 — 팩토리 옵션 + Nest 모듈 스코프.\n *\n * `sensitiveValueProtector`는 팩토리에서 상속한 필수 값이다. Nest 배선도 raw billing\n * key·deposit secret·cancel retry를 평문 기본값으로 만들 수 없다.\n */\ninterface TossPaymentsPostgresModuleOptions extends TossPaymentsPostgresOptions {\n    /** 기본 true — 영속화 집합체는 전역 싱글턴이 자연스러운 단위다(모듈마다 재조립 금지). */\n    readonly global?: boolean;\n}",
          "sourceDocumentation": "forRoot 옵션 — 팩토리 옵션 + Nest 모듈 스코프.\n\n`sensitiveValueProtector`는 팩토리에서 상속한 필수 값이다. Nest 배선도 raw billing\nkey·deposit secret·cancel retry를 평문 기본값으로 만들 수 없다."
        },
        {
          "name": "TossPaymentsPostgresOptions",
          "slug": "toss-payments-postgres-options",
          "kind": "interface",
          "declaration": "/**\n * createTossPaymentsPostgres — 스토어 집합체 팩토리 (설계 §5) + cleanup (설계 §6).\n *\n * 팩토리는 **순수 조립**이다 — 즉시 DB 접속이 없고 첫 쿼리가 첫 접점이다. 스키마\n * 식별자 검증만 조립 시점에 수행해 잘못된 설정을 즉시 드러낸다(fail-fast).\n * 부팅 시 자동 DDL도, 자동 cleanup 타이머도 없다 — 모든 옵션 기본 꺼짐 원칙.\n */\ninterface TossPaymentsPostgresOptions {\n    readonly sql: SqlClient;\n    /**\n     * billing key·deposit secret·cancel retry record의 필수 at-rest 보호기.\n     *\n     * 기본값은 없다. 평문 개발 DB를 의도적으로 써야 할 때만\n     * `unsafePlaintextSensitiveValueProtector`를 명시해 전달한다. 보호기는 `purpose`와\n     * `recordId`를 AAD에 결속해야 한다.\n     */\n    readonly sensitiveValueProtector: SensitiveValueProtector;\n    /** 기본 'toss_payments'. `/^[a-z_][a-z0-9_]{0,62}$/` 위반 시 조립 시점에 throw. */\n    readonly schema?: string;\n    readonly dedupe?: {\n        /** processing 행의 crash-recovery lease(초). 기본 60. */\n        readonly leaseSeconds?: number;\n        /**\n         * completed 행의 TTL(초). 기본 432_000(5일) — 코어 TSDoc \"토스 최장 재전송\n         * 기간보다 긴 TTL, 권장 5일\". 삭제는 cleanup() 호출 시에만 일어난다.\n         */\n        readonly completedTtlSeconds?: number;\n    };\n    readonly retention?: {\n        /**\n         * cancel_retries 보존 일수. 기본 15 — 토스 멱등키 유효기간과 일치.\n         * **양의 정수**여야 한다(cleanup SQL의 make_interval days 파라미터가 int) —\n         * 소수는 조립 시점에 TypeError로 거부된다.\n         */\n        readonly cancelRetryDays?: number;\n    };\n}",
          "sourceDocumentation": "createTossPaymentsPostgres — 스토어 집합체 팩토리 (설계 §5) + cleanup (설계 §6).\n\n팩토리는 **순수 조립**이다 — 즉시 DB 접속이 없고 첫 쿼리가 첫 접점이다. 스키마\n식별자 검증만 조립 시점에 수행해 잘못된 설정을 즉시 드러낸다(fail-fast).\n부팅 시 자동 DDL도, 자동 cleanup 타이머도 없다 — 모든 옵션 기본 꺼짐 원칙."
        }
      ]
    },
    {
      "subpath": "./testing",
      "id": "testing",
      "declarationTarget": "./dist/testing.d.cts",
      "symbols": [
        {
          "name": "CleanupResult",
          "slug": "cleanup-result",
          "kind": "interface",
          "declaration": "interface CleanupResult {\n    /** webhook_dedupe에서 삭제된 completed 행 수. */\n    readonly dedupeDeleted: number;\n    /** cancel_retries에서 삭제된 만료 행 수. */\n    readonly cancelRetriesDeleted: number;\n}"
        },
        {
          "name": "createMemoryTossPaymentsPostgres",
          "slug": "create-memory-toss-payments-postgres",
          "kind": "function",
          "declaration": "declare function createMemoryTossPaymentsPostgres(options?: MemoryTossPaymentsPostgresOptions): MemoryTossPaymentsPostgres;"
        },
        {
          "name": "createOpaqueAdvisoryLockKey",
          "slug": "create-opaque-advisory-lock-key",
          "kind": "function",
          "declaration": "/**\n * 앱이 만든 HMAC/blind-index를 opaque lock key로 명시적으로 표시한다.\n *\n * 이 함수는 HMAC을 생성하거나 원본 식별자를 보호하지 않는다. 앱의 key management와\n * canonicalization은 앱 소유이다. empty/비정상적으로 큰 입력만 fail-fast로 거부하며,\n * 오류 메시지에는 전달된 값을 포함하지 않는다.\n */\ndeclare function createOpaqueAdvisoryLockKey(value: string): OpaqueAdvisoryLockKey;",
          "sourceDocumentation": "앱이 만든 HMAC/blind-index를 opaque lock key로 명시적으로 표시한다.\n\n이 함수는 HMAC을 생성하거나 원본 식별자를 보호하지 않는다. 앱의 key management와\ncanonicalization은 앱 소유이다. empty/비정상적으로 큰 입력만 fail-fast로 거부하며,\n오류 메시지에는 전달된 값을 포함하지 않는다."
        },
        {
          "name": "isMemoryLockContractError",
          "slug": "is-memory-lock-contract-error",
          "kind": "function",
          "declaration": "/** Structural guard — `instanceof` is unreliable across ESM/CJS dual loading. */\ndeclare function isMemoryLockContractError(value: unknown): value is MemoryLockContractError;",
          "sourceDocumentation": "Structural guard — `instanceof` is unreliable across ESM/CJS dual loading."
        },
        {
          "name": "MemoryCleanupEvent",
          "slug": "memory-cleanup-event",
          "kind": "interface",
          "declaration": "interface MemoryCleanupEvent {\n    readonly type: 'cleanup';\n    readonly dedupeDeleted: number;\n    readonly cancelRetriesDeleted: number;\n}"
        },
        {
          "name": "MemoryLockAcquiredEvent",
          "slug": "memory-lock-acquired-event",
          "kind": "interface",
          "declaration": "interface MemoryLockAcquiredEvent {\n    readonly type: 'lock-acquired';\n    readonly api: MemoryLockApi;\n    readonly lock: MemoryLockClass;\n    readonly key: string;\n}"
        },
        {
          "name": "MemoryLockApi",
          "slug": "memory-lock-api",
          "kind": "type",
          "declaration": "/** Which public lock API an event belongs to. */\ntype MemoryLockApi = 'opaqueLocks.withLock' | 'billingKeys.withMutationLock' | 'billingKeys.withOpaqueMutationLock';",
          "sourceDocumentation": "Which public lock API an event belongs to."
        },
        {
          "name": "MemoryLockClass",
          "slug": "memory-lock-class",
          "kind": "type",
          "declaration": "/** Lock class — the PostgreSQL aggregate orders them `opaque` then `customer`. */\ntype MemoryLockClass = 'opaque' | 'customer';",
          "sourceDocumentation": "Lock class — the PostgreSQL aggregate orders them `opaque` then `customer`."
        },
        {
          "name": "MemoryLockContractError",
          "slug": "memory-lock-contract-error",
          "kind": "class",
          "declaration": "/**\n * Thrown by the in-memory aggregate where the PostgreSQL aggregate would deadlock or lose its\n * single-transaction guarantee. `code` is the contract; messages carry no keys or secrets.\n *\n * Nesting is detected through `AsyncLocalStorage`, so it is judged by where a lock API call is\n * *started*, not by whether the callback awaits it: a lock call launched inside a callback and\n * left un-awaited (for example a \"late webhook\" fired while the issuance callback still holds\n * the lock) is refused exactly like an awaited one, even though PostgreSQL with a pool larger\n * than one would queue it and serve it after the commit. This is the fake's deliberate stricter\n * direction — it cannot tell the two apart and the awaited form is a real self-deadlock. To model\n * a competing caller, start it from outside the callback after a \"started\" gate, as in the README\n * contention example. Work scheduled from a callback that runs *after* the callback settled\n * (timers, `setImmediate`) is not nesting and is served normally.\n */\ndeclare class MemoryLockContractError extends Error {\n    readonly name = \"MemoryLockContractError\";\n    readonly code: MemoryLockContractErrorCode;\n    constructor(code: MemoryLockContractErrorCode, message: string);\n}",
          "sourceDocumentation": "Thrown by the in-memory aggregate where the PostgreSQL aggregate would deadlock or lose its\nsingle-transaction guarantee. `code` is the contract; messages carry no keys or secrets.\n\nNesting is detected through `AsyncLocalStorage`, so it is judged by where a lock API call is\n*started*, not by whether the callback awaits it: a lock call launched inside a callback and\nleft un-awaited (for example a \"late webhook\" fired while the issuance callback still holds\nthe lock) is refused exactly like an awaited one, even though PostgreSQL with a pool larger\nthan one would queue it and serve it after the commit. This is the fake's deliberate stricter\ndirection — it cannot tell the two apart and the awaited form is a real self-deadlock. To model\na competing caller, start it from outside the callback after a \"started\" gate, as in the README\ncontention example. Work scheduled from a callback that runs *after* the callback settled\n(timers, `setImmediate`) is not nesting and is served normally."
        },
        {
          "name": "MemoryLockContractErrorCode",
          "slug": "memory-lock-contract-error-code",
          "kind": "type",
          "declaration": "/** Stable codes of lock-contract violations the fake refuses instead of deadlocking. */\ntype MemoryLockContractErrorCode = \n/** Re-acquiring a key already held by the surrounding callback — PostgreSQL would self-deadlock. */\n'reentrant-lock'\n/** Any public lock API called inside another lock callback — README forbids nesting; the fake refuses it. */\n | 'nested-lock-api'\n/**\n * A locked-mutation handle used after its callback settled. The PostgreSQL handle is bound to\n * a connection that was already committed/rolled back and released; the fake refuses rather\n * than silently dropping the write or applying it outside the lock.\n */\n | 'handle-outside-callback';",
          "sourceDocumentation": "Stable codes of lock-contract violations the fake refuses instead of deadlocking."
        },
        {
          "name": "MemoryLockReleasedEvent",
          "slug": "memory-lock-released-event",
          "kind": "interface",
          "declaration": "interface MemoryLockReleasedEvent {\n    readonly type: 'lock-released';\n    readonly api: MemoryLockApi;\n    readonly lock: MemoryLockClass;\n    readonly key: string;\n    /**\n     * `commit` when the callback returned — the handle's staged billing-key write of that\n     * customerKey became visible to lock-free reads; `rollback` when it threw — the staged write\n     * was discarded and was never visible outside the callback.\n     */\n    readonly outcome: 'commit' | 'rollback';\n}"
        },
        {
          "name": "MemoryLockRequestedEvent",
          "slug": "memory-lock-requested-event",
          "kind": "interface",
          "declaration": "interface MemoryLockRequestedEvent {\n    readonly type: 'lock-requested';\n    readonly api: MemoryLockApi;\n    readonly lock: MemoryLockClass;\n    /** The customerKey for `customer`; the nonsecret opaque key as given for `opaque`. */\n    readonly key: string;\n}"
        },
        {
          "name": "MemoryMigrateEvent",
          "slug": "memory-migrate-event",
          "kind": "interface",
          "declaration": "interface MemoryMigrateEvent {\n    readonly type: 'migrate';\n    readonly applied: readonly string[];\n    readonly skipped: readonly string[];\n}"
        },
        {
          "name": "MemoryStoreEvent",
          "slug": "memory-store-event",
          "kind": "interface",
          "declaration": "interface MemoryStoreEvent {\n    readonly type: 'store';\n    readonly store: MemoryStoreName;\n    /**\n     * Method name as invoked on that store or on the locked-mutation handle. Store methods that\n     * delegate to the handle (`billingKeys.save` / `delete` / `replaceAndGetPrevious` / the two\n     * conditional methods) are logged once, under the handle method of the same name — so the\n     * core `billingKeys.delete(request)` appears as `delete`, not `deleteIfBillingKeyMatches`.\n     */\n    readonly operation: string;\n    /** Lookup key only — orderId, customerKey, ticketId, dedupeKey, audit id. Never a secret. */\n    readonly recordId: string;\n    /**\n     * Boolean outcome of conditional operations, or a short outcome label — the claim state for\n     * `webhookDedupe.claim`, `inserted` / `idempotent` / `conflict` for `orders.saveOrder`,\n     * `inserted` / `duplicate` for `audit.record` (same-id re-calls are idempotent like the\n     * PostgreSQL sink's `ON CONFLICT (id) DO NOTHING`).\n     */\n    readonly result?: boolean | string;\n}"
        },
        {
          "name": "MemoryStoreName",
          "slug": "memory-store-name",
          "kind": "type",
          "declaration": "type MemoryStoreName = 'orders' | 'depositSecrets' | 'billingKeys' | 'cancelRetries' | 'webhookDedupe' | 'audit' | 'inbox';"
        },
        {
          "name": "MemoryTossPaymentsPostgres",
          "slug": "memory-toss-payments-postgres",
          "kind": "interface",
          "declaration": "/** `TossPaymentsPostgres` plus the test-only `recorded` view and `reset()`. */\ninterface MemoryTossPaymentsPostgres extends TossPaymentsPostgres {\n    readonly audit: PgAuditSink;\n    readonly recorded: MemoryTossPaymentsPostgresRecorded;\n    /** Clears every table, the migration ledger, lock bookkeeping, and `recorded`. Call between tests while no lock is held. */\n    reset(): void;\n}",
          "sourceDocumentation": "`TossPaymentsPostgres` plus the test-only `recorded` view and `reset()`."
        },
        {
          "name": "MemoryTossPaymentsPostgresEvent",
          "slug": "memory-toss-payments-postgres-event",
          "kind": "type",
          "declaration": "/** Ordered, readable record of everything the aggregate did — assert ordering against it. */\ntype MemoryTossPaymentsPostgresEvent = MemoryLockRequestedEvent | MemoryLockAcquiredEvent | MemoryLockReleasedEvent | MemoryStoreEvent | MemoryMigrateEvent | MemoryCleanupEvent;",
          "sourceDocumentation": "Ordered, readable record of everything the aggregate did — assert ordering against it."
        },
        {
          "name": "MemoryTossPaymentsPostgresOptions",
          "slug": "memory-toss-payments-postgres-options",
          "kind": "interface",
          "declaration": "interface MemoryTossPaymentsPostgresOptions {\n    /**\n     * At-rest protector applied exactly where the PostgreSQL stores apply it (billing key record,\n     * deposit secret, cancel retry record — same purpose/recordId context). Defaults to\n     * `unsafePlaintextSensitiveValueProtector`, which is acceptable only because this aggregate\n     * is a test double that never touches a database. Pass the protector your production wiring\n     * uses (for example `createAes256GcmSensitiveValueProtector`) to exercise AAD binding end to end.\n     */\n    readonly sensitiveValueProtector?: SensitiveValueProtector;\n    /** Validated like the PostgreSQL aggregate for configuration parity; state is per instance. */\n    readonly schema?: string;\n    readonly dedupe?: {\n        /** Crash-recovery lease of processing dedupe rows in seconds. Default 60. */\n        readonly leaseSeconds?: number;\n        /** Retention of completed dedupe rows in seconds, applied by `cleanup()`. Default 432_000 (5 days). */\n        readonly completedTtlSeconds?: number;\n    };\n    readonly retention?: {\n        /** Retention of cancel retry records in days, applied by `cleanup()`. Default 15. */\n        readonly cancelRetryDays?: number;\n    };\n    /**\n     * Clock in epoch milliseconds for dedupe leases and retention. Defaults to `Date.now`, so\n     * fake timers that patch `Date.now` work without configuration.\n     */\n    readonly now?: () => number;\n}"
        },
        {
          "name": "MemoryTossPaymentsPostgresRecorded",
          "slug": "memory-toss-payments-postgres-recorded",
          "kind": "interface",
          "declaration": "/** Test-only observation surface. All arrays are live views cleared by `reset()`. */\ninterface MemoryTossPaymentsPostgresRecorded {\n    readonly events: readonly MemoryTossPaymentsPostgresEvent[];\n    /**\n     * Audit entries in first-`record()` order, one per distinct `id` — the PostgreSQL sink has no\n     * read API. A second `record()` with an id already present is a no-op, mirroring the table's\n     * `ON CONFLICT (id) DO NOTHING`.\n     */\n    readonly auditEntries: readonly AuditEntry[];\n    /** Inbox rows in first-received order. */\n    readonly inbox: readonly MemoryWebhookInboxRow[];\n}",
          "sourceDocumentation": "Test-only observation surface. All arrays are live views cleared by `reset()`."
        },
        {
          "name": "MemoryWebhookInboxRow",
          "slug": "memory-webhook-inbox-row",
          "kind": "interface",
          "declaration": "/** Redacted inbox row — the PostgreSQL table has no read API, so the fake exposes it here. */\ninterface MemoryWebhookInboxRow {\n    readonly dedupeKey: string;\n    readonly transmissionId: string;\n    readonly transmissionTime: string | null;\n    readonly retriedCount: number;\n    readonly trust: AcceptedWebhook['trust'];\n    readonly eventType: string;\n    /** Stored form: same redaction/sanitization as `webhook_inbox.event` (JSON round-tripped). */\n    readonly event: unknown;\n    readonly deliveries: number;\n}",
          "sourceDocumentation": "Redacted inbox row — the PostgreSQL table has no read API, so the fake exposes it here."
        },
        {
          "name": "MigrationResult",
          "slug": "migration-result",
          "kind": "interface",
          "declaration": "interface MigrationResult {\n    /** 이번 호출이 실제 적용한 마이그레이션 id (적용 순서). */\n    readonly applied: readonly string[];\n    /** 버전 테이블에 이미 기록돼 있어 건너뛴 id — 멱등 재실행의 증거. */\n    readonly skipped: readonly string[];\n}"
        },
        {
          "name": "OpaqueAdvisoryLockKey",
          "slug": "opaque-advisory-lock-key",
          "kind": "type",
          "declaration": "type OpaqueAdvisoryLockKey = string & {\n    readonly [opaqueAdvisoryLockKeyBrand]: 'OpaqueAdvisoryLockKey';\n};"
        },
        {
          "name": "PgBillingKeyMutation",
          "slug": "pg-billing-key-mutation",
          "kind": "interface",
          "declaration": "/**\n * BillingKeyStore PostgreSQL 구현 (설계 §3.3).\n *\n * 코어 계약의 핵심 불변식:\n * - 토스에 빌링키 조회 API가 없다 — **저장 실패 = 복구 불가**. 이 테이블이 유일한\n *   보관 수단이므로 save는 드라이버 에러를 감추지 않고 그대로 던진다(코어가 감쌈).\n * - `save`는 upsert(customer_key)다 — issue/import 양쪽에서 호출되는 계약이고 코어가\n *   교체 정책을 규정하지 않으므로 최신 발급본을 유지한다.\n * - `billing_key`에는 BillingKeyRecord 전체의 보호된 JSON 문자열만 쓴다. `card`와\n *   `transfers`까지 함께 보호해 계좌번호 등 부수 메타데이터가 jsonb에 평문으로 남지\n *   않게 한다. method/issued_at은 운영 조회용 비밀이 아닌 최소 메타데이터로만 남긴다.\n * - ⚠ 보안 불변식(코어 stores.ts): 어떤 에러 메시지에도 billing_key 값을 싣지 않고,\n *   customerKey와 billingKey를 같은 문자열(로그 한 줄)에 함께 두지 않는다 — 토스의\n *   빌링 보안 모델이 이 쌍의 분리에 의존한다. 이 파일의 메시지는 둘 다 싣지 않는다.\n */\n/**\n * `withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n *\n * 핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n * `pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n * 되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다.\n */\ninterface PgBillingKeyMutation {\n    readonly customerKey: BillingKeyRecord['customerKey'];\n    find(): Promise<BillingKeyRecord | null>;\n    save(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<void>;\n    /**\n     * 현재 raw billing key와 일치할 때만 삭제한다. 무조건 삭제 API는 의도적으로 없다.\n     */\n    delete(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 저장 당시의 nonsecret operationId fingerprint가 예상 operationId와 같은지 확인한다.\n     * callback 내부에서만 쓰며 raw operationId/fingerprint 어느 것도 반환하지 않는다.\n     */\n    isCurrentOperationId(operationId: string): Promise<boolean>;\n    deleteIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey']): Promise<boolean>;\n    replaceIfBillingKeyMatches(expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "`withMutationLock` callback에만 전달되는 customerKey-고정 mutation handle.\n\n핸들은 lock을 잡은 customerKey 하나만 조작한다. callback 안에서 바깥\n`pg.billingKeys`를 다시 호출하면 다른 커넥션이 같은 advisory lock을 기다려 deadlock이\n되므로, 모든 billing key 작업은 이 handle을 통해 수행해야 한다."
        },
        {
          "name": "PgBillingKeySnapshot",
          "slug": "pg-billing-key-snapshot",
          "kind": "interface",
          "declaration": "/**\n * Opaque previous snapshot returned by `replaceAndGetPrevious`.\n *\n * Only `record` is readable, for recovery or display. Passing the original snapshot object\n * back to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\n * The fingerprint and the trusted record are linked only through a module-private\n * `WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\n * registry identity and the lifecycle fence is intentionally false after such a restore.\n */\ninterface PgBillingKeySnapshot {\n    readonly record: BillingKeyRecord;\n}",
          "sourceDocumentation": "Opaque previous snapshot returned by `replaceAndGetPrevious`.\n\nOnly `record` is readable, for recovery or display. Passing the original snapshot object\nback to `replaceIfBillingKeyMatches` also restores the nonsecret operation fingerprint.\nThe fingerprint and the trusted record are linked only through a module-private\n`WeakMap`, so JSON copies, spreads, manual reconstructions, or inheriting objects have no\nregistry identity and the lifecycle fence is intentionally false after such a restore."
        },
        {
          "name": "PgBillingKeyStore",
          "slug": "pg-billing-key-store",
          "kind": "interface",
          "declaration": "/**\n * PostgreSQL이 제공하는 BillingKeyStore 확장.\n *\n * 코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n * 지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\n * fence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n *\n * `replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\n * customerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\n * compare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\n * issuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n * 잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다.\n */\ninterface PgBillingKeyStore extends BillingKeyStore {\n    /**\n     * customerKey별 PostgreSQL advisory transaction lock을 callback 전체에 유지한다.\n     *\n     * 같은 customerKey의 generic 저장과 앱 projection을 순서대로 끝내야 할 때의\n     * cross-instance fence다. 모든 경쟁 issuance/deletion/compensation이 이 API를 사용해야\n     * 한다. callback 성공 시 commit, throw 시 generic billing key 변경은 rollback된다.\n     * callback 안에서는 전달된 mutation handle만 사용하고 바깥 store를 재호출하지 않는다.\n     */\n    withMutationLock<T>(customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * opaque lifecycle lock과 customerKey mutation lock을 **같은 PostgreSQL connection과\n     * transaction**에서 `opaque → customer` 순서로 획득한다.\n     *\n     * credential issuance/revocation/compensation처럼 host lifecycle과 generic billing-key\n     * mutation을 함께 직렬화해야 할 때의 유일한 composable API다. callback은 두 lock을 모두\n     * 얻은 뒤에만 기존 customer-bound mutation handle을 받는다. callback 안에서는 handle만\n     * 사용하고 `opaqueLocks.withLock` 또는 outer billing store를 재진입하지 않는다.\n     *\n     * `opaqueLocks.withLock(key, () => withMutationLock(...))`처럼 두 public API를 중첩하면\n     * 서로 다른 `withConnection`을 열어 pool max=1에서 self-deadlock할 수 있고, 한\n     * transaction이라는 보장도 잃는다. 모든 결합 경로의 global lock order는 이 메서드가\n     * 강제하는 **opaque → customer**다.\n     */\n    withOpaqueMutationLock<T>(opaqueKey: OpaqueAdvisoryLockKey, customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>;\n    /**\n     * record를 저장하고, 같은 트랜잭션에서 잠근 직전 snapshot을 반환한다.\n     *\n     * 단일 generic write의 snapshot/보상에는 `find()` 뒤 `save()`보다 안전하다. 다만 앱\n     * projection까지 순서 보장이 필요하면 이 단독 메서드가 아니라 `withMutationLock` 안의\n     * 같은 이름 메서드를 사용한다. 그 callback 안에서 반환된 snapshot(첫 발급이면 null)을\n     * 이후 `replaceIfBillingKeyMatches(record.billingKey, previous)`에 전달하면 현재 값이\n     * 여전히 record일 때만 원자 복원/삭제할 수 있다. snapshot 원본을 그대로 넘기면 prior\n     * operation fingerprint까지 보존한다.\n     */\n    replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 행을 삭제한다.\n     *\n     * 행이 없거나 현재 키가 다르면 false이고, 보호 payload 손상/복호화 실패는 숨기지 않고\n     * throw한다. false는 삭제되지 않았다는 안전한 결과이지 저장소 장애를 뜻하지 않는다.\n     */\n    deleteIfBillingKeyMatches(request: BillingKeyDeleteRequest): Promise<boolean>;\n    /**\n     * 현재 billing key가 `expectedBillingKey`와 같을 때만 replacement로 교체한다.\n     *\n     * `replacement`가 null이면 조건부 삭제다. 보상 경로에서는 발급 직후 저장한 새 키를\n     * expected로, 이전 snapshot(또는 첫 발급이면 null)을 replacement로 전달한다. replacement의\n     * customerKey는 첫 인자와 반드시 같아야 한다.\n     */\n    replaceIfBillingKeyMatches(customerKey: BillingKeyRecord['customerKey'], expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;\n}",
          "sourceDocumentation": "PostgreSQL이 제공하는 BillingKeyStore 확장.\n\n코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은\n지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey\nfence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.\n\n`replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서\ncustomerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time\ncompare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신\nissuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저\n잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다."
        },
        {
          "name": "PgOpaqueAdvisoryLocks",
          "slug": "pg-opaque-advisory-locks",
          "kind": "interface",
          "declaration": "/**\n * lifecycle work를 short-lived PostgreSQL advisory transaction lock 아래 실행하는 표면.\n *\n * callback에 SQL session을 전달하지 않는다. 이 API의 목적은 host DB transaction/worker\n * lifecycle의 **순서화**이며, 다른 ORM connection의 transaction과 2PC 원자성을 만들지\n * 않는다. callback은 local durable work만 수행하고 provider/HTTP 같은 긴 network I/O는\n * 넣지 않아야 한다. callback 안에서 같은 key로 이 facility를 재진입하면 다른 connection이\n * 바깥 transaction의 xact lock을 기다려 self-deadlock하므로, 연관 작업은 한 callback에 둔다.\n */\ninterface PgOpaqueAdvisoryLocks {\n    withLock<T>(key: OpaqueAdvisoryLockKey, operation: () => T | Promise<T>): Promise<T>;\n}",
          "sourceDocumentation": "lifecycle work를 short-lived PostgreSQL advisory transaction lock 아래 실행하는 표면.\n\ncallback에 SQL session을 전달하지 않는다. 이 API의 목적은 host DB transaction/worker\nlifecycle의 **순서화**이며, 다른 ORM connection의 transaction과 2PC 원자성을 만들지\n않는다. callback은 local durable work만 수행하고 provider/HTTP 같은 긴 network I/O는\n넣지 않아야 한다. callback 안에서 같은 key로 이 facility를 재진입하면 다른 connection이\n바깥 transaction의 xact lock을 기다려 self-deadlock하므로, 연관 작업은 한 callback에 둔다."
        },
        {
          "name": "SensitiveValueContext",
          "slug": "sensitive-value-context",
          "kind": "interface",
          "declaration": "/**\n * 보호기 호출마다 전달되는 AAD 결속 정보.\n *\n * `recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n * 암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n * 포함해야 한다.\n */\ninterface SensitiveValueContext {\n    readonly purpose: SensitiveValuePurpose;\n    readonly recordId: string;\n}",
          "sourceDocumentation": "보호기 호출마다 전달되는 AAD 결속 정보.\n\n`recordId`는 DB의 primary/lookup key와 동일하다(customerKey, orderId, ticketId).\n암호문 자체뿐 아니라 저장 위치도 인증하려면 `purpose`와 `recordId`를 둘 다 AAD에\n포함해야 한다."
        },
        {
          "name": "SensitiveValueProtector",
          "slug": "sensitive-value-protector",
          "kind": "interface",
          "declaration": "/**\n * 앱이 소유하는 비동기 민감값 보호기.\n *\n * AES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n * 들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n * 하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n * 평문을 포함하지 않아야 한다.\n *\n * 이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\n * ASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\n * AES-256-GCM 보호기는 `TypeError`로 거부한다.\n */\ninterface SensitiveValueProtector {\n    encrypt(plaintext: string, context: SensitiveValueContext): Promise<string>;\n    decrypt(ciphertext: string, context: SensitiveValueContext): Promise<string>;\n}",
          "sourceDocumentation": "앱이 소유하는 비동기 민감값 보호기.\n\nAES-GCM, envelope encryption, KMS 등을 선택할 수 있도록 crypto 의존성을 이 패키지에\n들이지 않는다. `encrypt`는 평문과 다른, DB에 안전하게 저장 가능한 문자열을 반환해야\n하고 `decrypt`는 같은 context에서만 원문을 복원해야 한다. 구현은 암호화 실패 메시지에\n평문을 포함하지 않아야 한다.\n\n이 패키지의 스토어가 넘기는 평문은 항상 well-formed UTF-16이다(JSON.stringify 출력 또는\nASCII secret). 구현은 비페어 서로게이트를 조용히 바꿔 봉하지 말고 거부해야 한다 — 레퍼런스\nAES-256-GCM 보호기는 `TypeError`로 거부한다."
        },
        {
          "name": "TossPaymentsPostgres",
          "slug": "toss-payments-postgres",
          "kind": "interface",
          "declaration": "interface TossPaymentsPostgres {\n    readonly orders: OrderStore;\n    readonly depositSecrets: DepositSecretStore;\n    /**\n     * 코어 BillingKeyStore + PostgreSQL conditional compare-and-mutate 확장.\n     *\n     * `deleteIfBillingKeyMatches`/`replaceIfBillingKeyMatches`는 stale BILLING_DELETED와\n     * projection 보상 경합에서 무조건 delete/save 대신 사용하는 원자적 API다.\n     */\n    readonly billingKeys: PgBillingKeyStore;\n    readonly cancelRetries: CancelRetryStore;\n    readonly webhookDedupe: WebhookDedupeStore;\n    readonly audit: AuditSink & {\n        flush(): Promise<void>;\n    };\n    readonly inbox: WebhookInboxStore;\n    /**\n     * 앱이 만든 nonsecret HMAC/blind-index key로 짧은 host lifecycle을 인스턴스 간\n     * 순서화하는 PostgreSQL advisory transaction lock facility.\n     *\n     * 이 API는 다른 ORM connection의 transaction과 2PC 원자성을 만들지 않는다. provider\n     * network I/O가 아니라 local durable finalization만 callback에 넣어야 한다.\n     */\n    readonly opaqueLocks: PgOpaqueAdvisoryLocks;\n    /** 명시 호출 전용 — 부팅 시 자동 실행 없음. `app.listen` 전에 await하는 것이 골든 패스. */\n    migrate(): Promise<MigrationResult>;\n    /**\n     * TTL 행 정리 — 명시 호출 전용(자동 타이머 없음). audit_entries·webhook_inbox·\n     * orders·deposit_secrets는 지우지 않는다 — 보관 정책은 소비자 책임.\n     */\n    cleanup(): Promise<CleanupResult>;\n}"
        },
        {
          "name": "unsafePlaintextSensitiveValueProtector",
          "slug": "unsafe-plaintext-sensitive-value-protector",
          "kind": "constant",
          "declaration": "unsafePlaintextSensitiveValueProtector: SensitiveValueProtector",
          "sourceDocumentation": "테스트·일회성 개발 DB 전용의 명시적 평문 opt-in.\n\n이 값을 넘기지 않으면 팩토리와 민감 스토어 팩토리는 조립 시점에 거부한다. 즉, 평문\n저장은 숨은 기본값이 아니라 호출 코드에서 보이는 의도적인 선택이다. 프로덕션에는\n절대 사용하지 말고 KMS/AEAD 기반 `SensitiveValueProtector`를 제공해야 한다."
        }
      ]
    }
  ]
}
