@tokeflow_com/connector-sdk
v0.5.0
Published
Tokeflow PSP connector contract: stateless-translator interface, minor-unit money helpers, zod runtime schemas.
Readme
@tokeflow_com/connector-sdk
The versioned contract for Tokeflow payment connectors. A connector is a stateless translator for one PSP: it builds requests, interprets responses/errors/webhooks, converts currency units, and verifies webhook signatures. Everything else — persistence, queues, events, state machines, refund reconciliation, credential storage, vault dispatch, retries and cascade — lives in the Tokeflow orchestrator and is deliberately out of reach.
The contract is PaymentConnector (see src/connector.ts); every type it
references ships from this package, alongside zod runtime schemas
(xSchema for each data type X) used by the conformance suite.
Install
npm install @tokeflow_com/connector-sdkThen bind the conformance suite — it is the definition of done for any connector built against this contract:
import { describeConformance } from '@tokeflow_com/connector-sdk/testing';
describeConformance('my-psp', () => makeSubject());Invariants
These are the contract's spine. A connector that violates any of them fails certification regardless of how well it otherwise works.
Minor units everywhere at the boundary. Every amount crossing the
PaymentConnectorboundary is an integer in minor units (cents/centavos), in both directions. Conversion to/from the PSP's wire unit happens INSIDE the connector, driven bycapabilities.providerAmountUnit, using the helpers shipped in this package (toProviderAmount/fromProviderAmount). Never reimplement the conversion.Unknown discipline. Every mutating operation's outcome union has an
unknownarm. Post-send ambiguity on a write — timeout, connection reset, 5xx after dispatch — MUST surface asstatus: 'unknown'(withRAIL_TIMEOUTwhere applicable), never'failed', and never a throw. This is the double-charge guard.getTransactionStatusreturns{ status: 'unknown' }when the lookup itself fails; it never throws.Host-supplied idempotency; deterministic event IDs.
idempotencyKeyis always provided by the orchestrator — connectors forward it to the PSP on every mutating call and never generate their own. WebhookproviderEventIdmust be deterministic for a given delivery (noDate.now()/random fallbacks) — deduplication depends on it.Statelessness. No DB, no queues, no environment variables, no global mutable state, no direct observability SDKs — use
ctx.logger. Rotated credentials persist only viactx.persistCredentials. Honorctx.signalon every outbound call. Never log or persist card ciphertexts or webhook secrets.
Layout
| Module | Contents |
|---|---|
| money | MinorUnits, unit-conversion helpers, currency decimal tables |
| errors | 12-code ConnectorErrorCode taxonomy, ConnectorError |
| context | ConnectorContext, ConnectorLogger |
| capabilities | ConnectorCapabilities |
| outcomes | PaymentOutcome, CaptureOutcome, VoidOutcome, RefundOutcome, StatusLookup |
| webhook | ConnectorWebhookEvent (14 kinds), WebhookVerification |
| vault | VaultProxyRequest, VaultCardCiphertext |
| inputs | ChargeInput, MitChargeInput, PayerDetails, customer/payment-method inputs |
| connector | PaymentConnector — the contract |
