Custom store adapter
When the official PostgreSQL or Redis adapters are not used, GuildGateStores can be mapped to the application's data layer. The goal is not only to satisfy TypeScript signatures but also to preserve behavior under races.
Starting approach
- Inventory the ten
GuildGateStoresmembers. - Record atomicity and TTL requirements for every operation.
- Choose transaction, compare-and-set, and lease primitives from the backend.
- Run
runStoreContract()for shared behavior. - Add multi-worker race tests.
Prefer 1.1 behavior over compatibility fallback
Several methods are optional:
SessionStore.createIdempotencyStore.renewLockStore.acquireLeaseLockStore.renewAuditStore.listPageOutboxStore.claim
They are optional so older stores still compile. A production custom store should implement them to provide the 1.1.0 reliability behavior.
ORM boundary
An ORM upsert does not always provide the compare-and-set guarantee you need. Inspect generated SQL. If idempotency completion lacks reservation and state predicates, an old worker can corrupt a newer record.
TTL cleanup
Separate these behaviors:
- treat an expired record as invalid during reads
- physically remove records through retention or cleanup
A delayed cleanup job must not change security decisions; those must use the expiry value.
Serialization
Bound unknown fields such as audit changes, cache values, and idempotency responses. Reject or safely serialize circular objects, oversized payloads, and prototype-specific values before they reach the backend.
Transaction participation
For fail-closed audit and transactional outbox, a custom store must enlist in the action's transaction scope. Audit written on another connection is not atomic with the domain commit.
Contract test setup
import {
adapterContractVersion,
runStoreContract,
} from "@kavtuai/guildgate/contracts";
console.log(adapterContractVersion); // 1.1
const report = await runStoreContract(() => createIsolatedStores());
if (!report.passed) throw new Error("Store contract failed");
Application-specific tests:
- 50 concurrent rate-limit hits
- concurrent session creation for one user
- two lease owners at the expiry boundary
- late completion after reservation TTL
- audit records with the same timestamp at a cursor boundary
- outbox worker crash and claim recovery
- invalidation while a cache entry changes tags
Versioning
When publishing the store adapter separately, state its supported GuildGate adapter-contract version in package metadata and documentation. Do not mark it as 1.1 compatible before implementing the contract changes.