PgBillingKeyStore — @gj-kit/toss-payments-postgresql
@gj-kit/toss-payments-postgresql/nestjs에서 공개하는 interface입니다. package version 0.5.1의 release declaration을 그대로 표시합니다.
검증된 import 예제
섹션 제목: “검증된 import 예제”import { PgBillingKeyStore } from '@gj-kit/toss-payments-postgresql/nestjs';시그니처, 매개변수, 반환 타입
섹션 제목: “시그니처, 매개변수, 반환 타입”/** * PostgreSQL이 제공하는 BillingKeyStore 확장. * * 코어 `BillingKeyStore`도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은 * 지연된 `BILLING_DELETED`, projection 보상, 발급 후 host lifecycle을 같은 customerKey * fence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다. * * `replaceAndGetPrevious`와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서 * customerKey별 advisory lock → `SELECT … FOR UPDATE` → decrypt → constant-time * compare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신 * issuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저 * 잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다. */interface PgBillingKeyStore extends BillingKeyStore { /** * customerKey별 PostgreSQL advisory transaction lock을 callback 전체에 유지한다. * * 같은 customerKey의 generic 저장과 앱 projection을 순서대로 끝내야 할 때의 * cross-instance fence다. 모든 경쟁 issuance/deletion/compensation이 이 API를 사용해야 * 한다. callback 성공 시 commit, throw 시 generic billing key 변경은 rollback된다. * callback 안에서는 전달된 mutation handle만 사용하고 바깥 store를 재호출하지 않는다. */ withMutationLock<T>(customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>; /** * opaque lifecycle lock과 customerKey mutation lock을 **같은 PostgreSQL connection과 * transaction**에서 `opaque → customer` 순서로 획득한다. * * credential issuance/revocation/compensation처럼 host lifecycle과 generic billing-key * mutation을 함께 직렬화해야 할 때의 유일한 composable API다. callback은 두 lock을 모두 * 얻은 뒤에만 기존 customer-bound mutation handle을 받는다. callback 안에서는 handle만 * 사용하고 `opaqueLocks.withLock` 또는 outer billing store를 재진입하지 않는다. * * `opaqueLocks.withLock(key, () => withMutationLock(...))`처럼 두 public API를 중첩하면 * 서로 다른 `withConnection`을 열어 pool max=1에서 self-deadlock할 수 있고, 한 * transaction이라는 보장도 잃는다. 모든 결합 경로의 global lock order는 이 메서드가 * 강제하는 **opaque → customer**다. */ withOpaqueMutationLock<T>(opaqueKey: OpaqueAdvisoryLockKey, customerKey: BillingKeyRecord['customerKey'], operation: (mutation: PgBillingKeyMutation) => T | Promise<T>): Promise<T>; /** * record를 저장하고, 같은 트랜잭션에서 잠근 직전 snapshot을 반환한다. * * 단일 generic write의 snapshot/보상에는 `find()` 뒤 `save()`보다 안전하다. 다만 앱 * projection까지 순서 보장이 필요하면 이 단독 메서드가 아니라 `withMutationLock` 안의 * 같은 이름 메서드를 사용한다. 그 callback 안에서 반환된 snapshot(첫 발급이면 null)을 * 이후 `replaceIfBillingKeyMatches(record.billingKey, previous)`에 전달하면 현재 값이 * 여전히 record일 때만 원자 복원/삭제할 수 있다. snapshot 원본을 그대로 넘기면 prior * operation fingerprint까지 보존한다. */ replaceAndGetPrevious(record: BillingKeyRecord, options?: BillingKeySaveOptions): Promise<PgBillingKeySnapshot | null>; /** * 현재 billing key가 `expectedBillingKey`와 같을 때만 행을 삭제한다. * * 행이 없거나 현재 키가 다르면 false이고, 보호 payload 손상/복호화 실패는 숨기지 않고 * throw한다. false는 삭제되지 않았다는 안전한 결과이지 저장소 장애를 뜻하지 않는다. */ deleteIfBillingKeyMatches(request: BillingKeyDeleteRequest): Promise<boolean>; /** * 현재 billing key가 `expectedBillingKey`와 같을 때만 replacement로 교체한다. * * `replacement`가 null이면 조건부 삭제다. 보상 경로에서는 발급 직후 저장한 새 키를 * expected로, 이전 snapshot(또는 첫 발급이면 null)을 replacement로 전달한다. replacement의 * customerKey는 첫 인자와 반드시 같아야 한다. */ replaceIfBillingKeyMatches(customerKey: BillingKeyRecord['customerKey'], expectedBillingKey: BillingKeyRecord['billingKey'], replacement: BillingKeyRecord | PgBillingKeySnapshot | null): Promise<boolean>;}이 선언은 매개변수, optionality, 제네릭, 반환값, 공개 union/type 계약의 정본입니다. 호출 전 필요한 환경·권한·오류 경계는 패키지 Golden path와 이 subpath의 import 조건을 함께 확인하세요.
Release context
섹션 제목: “Release context”- 패키지:
@gj-kit/toss-payments-postgresql - 버전:
0.5.1 - 공개 entry:
./nestjs - 소스: GitHub
구현 주석
섹션 제목: “구현 주석”PostgreSQL이 제공하는 BillingKeyStore 확장.
코어 BillingKeyStore도 expected billing key를 받는 조건부 삭제를 강제한다. 이 확장은
지연된 BILLING_DELETED, projection 보상, 발급 후 host lifecycle을 같은 customerKey
fence 안에서 끝내야 하는 호출자를 위한 PostgreSQL 전용 API다.
replaceAndGetPrevious와 두 conditional 메서드는 하나의 커넥션/트랜잭션에서
customerKey별 advisory lock → SELECT … FOR UPDATE → decrypt → constant-time
compare → UPSERT/UPDATE/DELETE를 수행한다. 따라서 같은 customerKey의 더 최신
issuance가 먼저 저장됐다면 conditional 호출은 false를 반환하고, 이 호출이 먼저
잠갔다면 뒤의 issuance는 commit 뒤에 실행되어 최신 issuance를 보존한다.