first commit
This commit is contained in:
104
docs/money/payment/payment-provider-square/README.md
Normal file
104
docs/money/payment/payment-provider-square/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# @suaveplan/payment-provider-square - Universal Square Payments API adapter for @suaveplan/payment. Ships SquareProvider (implements PaymentProvider with literal name "square"), SquareConfig (extends ApiKeyConfig with locationId, sandbox, apiVersion, randomId), and the Square-specific payment/refund mappers. Built on the @suaveplan/payment-providers foundation (httpRequest, composeAbortSignal, PAYMENT_PROVIDER_CODES, PaymentProviderError).
|
||||
|
||||
Universal Square Payments API adapter for `@suaveplan/payment`.
|
||||
Ships the `SquareProvider` class (implements the structural
|
||||
`PaymentProvider` contract with literal `name: "square"`), the
|
||||
`SquareConfig` interface (extends `ApiKeyConfig` from
|
||||
`@suaveplan/payment-providers` with the Square-specific `locationId`,
|
||||
`sandbox`, `apiVersion`, and `randomId` fields), and the
|
||||
Square-specific payment / refund mappers (`mapPayment`, `mapRefund`,
|
||||
`mapPaymentStatus`, `mapRefundStatus`).
|
||||
|
||||
Built on the `@suaveplan/payment-providers` foundation — every
|
||||
outbound HTTP call goes through `httpRequest`, which handles JSON
|
||||
serialisation, the per-call timeout signal, external `AbortSignal`
|
||||
composition, and typed `PaymentProviderError` raising.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [payment](./src/mapping/payment.md) — Translates between Square's `Payment` envelope (as returned by `POST /v2/payments`, `POST /v2/payments/{id}/complete`,…
|
||||
- [refund](./src/mapping/refund.md) — Translates Square's `Refund` envelope (as returned by `POST /v2/refunds`) into `@suaveplan/payment`'s `Refund` shape. T…
|
||||
- [square](./src/square/square.md) — `SquareProvider` is the Square Payments API adapter for `@suaveplan/payment`. It implements the structural `PaymentProv…
|
||||
- [square](./src/square/square.md) — `SquareProvider` is the Square Payments API adapter for `@suaveplan/payment`. It implements the structural `PaymentProv…
|
||||
- [types](./src/types/config.md) — Defines the configuration shape `SquareProvider` accepts and the three default constants the provider falls back to whe…
|
||||
- [config](./src/types/config.md) — Defines the configuration shape `SquareProvider` accepts and the three default constants the provider falls back to whe…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/payment-provider-square @suaveplan/payment-providers @suaveplan/payment
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import { ProviderRegistry } from "@suaveplan/payment-providers";
|
||||
import { SquareProvider } from "@suaveplan/payment-provider-square";
|
||||
import { PaymentEngine } from "@suaveplan/payment";
|
||||
|
||||
const registry = new ProviderRegistry();
|
||||
registry.register(
|
||||
new SquareProvider({
|
||||
apiKey: process.env.SQUARE_ACCESS_TOKEN ?? "",
|
||||
locationId: process.env.SQUARE_LOCATION_ID ?? "",
|
||||
})
|
||||
);
|
||||
|
||||
const engine = new PaymentEngine({ provider: registry.get("square") });
|
||||
|
||||
const intent = await engine.createIntent({
|
||||
amount: { amount: 5000n, currency: "USD" },
|
||||
});
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **`SquareProvider`** — full Square Payments API lifecycle
|
||||
(`createIntent`, `confirmIntent`, `captureIntent`, `cancelIntent`,
|
||||
`refund`, `getIntent`) with literal `name: "square"`.
|
||||
- **`SquareConfig`** — extends `ApiKeyConfig`; adds required
|
||||
`locationId` plus optional `sandbox`, `apiVersion`, `randomId`.
|
||||
- **Sandbox toggle** — `sandbox: true` flips the default base URL to
|
||||
`https://connect.squareupsandbox.com/v2`. Explicit `baseUrl`
|
||||
always wins.
|
||||
- **Pinned `Square-Version`** — defaults to `2024-01-18`; override via
|
||||
`apiVersion` to opt into a newer API surface.
|
||||
- **Injectable `randomId`** — fills missing `idempotency_key` fields
|
||||
on `CreatePayment` + `RefundPayment` calls. Tests pass a
|
||||
deterministic counter; production defaults to `crypto.randomUUID()`.
|
||||
- **Universal** — no `node:`, `bun:`, `fs`, `path`, `crypto`
|
||||
imports; runs on Node, Bun, browsers, and Web Workers.
|
||||
- **`PaymentProviderError`-only** — every failure surfaces as a
|
||||
typed `PaymentProviderError` via the foundation's `httpRequest`.
|
||||
- **100% test coverage** (Istanbul) + sibling `.md` per
|
||||
implementation file + 5 subpath exports.
|
||||
|
||||
## Modules
|
||||
|
||||
- [`src/square/square.md`](./src/square/square.md) — `SquareProvider`
|
||||
class and lifecycle methods.
|
||||
- [`src/types/config.md`](./src/types/config.md) — `SquareConfig`,
|
||||
`SQUARE_DEFAULT_BASE_URL`, `SQUARE_SANDBOX_BASE_URL`,
|
||||
`SQUARE_DEFAULT_API_VERSION`.
|
||||
- [`src/mapping/payment.md`](./src/mapping/payment.md) — `mapPayment`,
|
||||
`mapPaymentStatus`, `SquarePaymentDto`, `SquareMoney`, `SquareCard`.
|
||||
- [`src/mapping/refund.md`](./src/mapping/refund.md) — `mapRefund`,
|
||||
`mapRefundStatus`, `SquareRefundDto`.
|
||||
|
||||
## Related
|
||||
|
||||
- `@suaveplan/payment-providers` — `ProviderRegistry`,
|
||||
`definePaymentProvider`, `httpRequest`, `composeAbortSignal`,
|
||||
`PAYMENT_PROVIDER_CODES`, `PaymentProviderError`,
|
||||
`ApiKeyConfig`/`OAuthConfig`/`MerchantKeyConfig`,
|
||||
`FetchLike`/`RandomIdFn`/`NowFn`/`Base64EncodeFn`.
|
||||
- `@suaveplan/payment` — `PaymentEngine`, `WebhookVerifier`,
|
||||
`PaymentProvider` interface, the canonical `PaymentIntent` /
|
||||
`Refund` / `PaymentStatus` / `RefundStatus` shapes.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# Square payment mapping
|
||||
|
||||
## Purpose
|
||||
|
||||
Translates between Square's `Payment` envelope (as returned by
|
||||
`POST /v2/payments`, `POST /v2/payments/{id}/complete`,
|
||||
`POST /v2/payments/{id}/cancel`, and `GET /v2/payments/{id}`) and
|
||||
`@suaveplan/payment`'s `PaymentIntent` shape. Square's status values
|
||||
are upper-snake-case (`COMPLETED`, `APPROVED`, ...) while uses
|
||||
the lower-case `PaymentStatus` union; the mapping pins this contract
|
||||
in one place so the provider class stays focused on transport.
|
||||
|
||||
The mapper also captures the two implicit branches Square encodes via
|
||||
optional fields rather than dedicated states: `approved_money`
|
||||
present ↔ manual capture, `card_details` present ↔ card-shaped
|
||||
`PaymentMethod`.
|
||||
|
||||
## Features
|
||||
|
||||
- `mapPaymentStatus(squareStatus)` — exhaustive five-status map with a
|
||||
defensive `"failed"` fallback for forward-rolled API versions.
|
||||
- `mapPayment(p)` — full envelope-to-`PaymentIntent` shape including
|
||||
`capturedAmount` derivation (`p.total_money` on `COMPLETED`, `0n`
|
||||
otherwise), `captureMethod` derivation (`approved_money` ↔
|
||||
`"manual"`), and optional `PaymentMethod` derivation from
|
||||
`card_details`.
|
||||
- `SquareCard` / `SquareMoney` / `SquarePaymentDto` — typed views of
|
||||
the Square API envelope that downstream code can rely on instead of
|
||||
threading `unknown` through call sites.
|
||||
- Card-brand normalisation — Square returns brands upper-case; the
|
||||
mapper lower-cases and validates against the `CardBrand`
|
||||
union, falling back to `"unknown"` for non-canonical brands
|
||||
(Square gift cards, JCB sub-brands, etc.).
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
mapPayment,
|
||||
mapPaymentStatus,
|
||||
} from "@suaveplan/payment-provider-square";
|
||||
|
||||
mapPaymentStatus("COMPLETED"); // "captured"
|
||||
|
||||
const intent = mapPayment({
|
||||
id: "sq_pay_123",
|
||||
status: "COMPLETED",
|
||||
amount_money: { amount: 5000, currency: "USD" },
|
||||
total_money: { amount: 5000, currency: "USD" },
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
updated_at: "2026-01-01T00:00:00Z",
|
||||
});
|
||||
console.log(intent.status); // "captured"
|
||||
console.log(intent.capturedAmount.amount); // 5000n
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Map an authorized-but-not-captured payment with card metadata:
|
||||
|
||||
```ts
|
||||
import { mapPayment } from "@suaveplan/payment-provider-square";
|
||||
|
||||
const intent = mapPayment({
|
||||
id: "sq_pay_456",
|
||||
status: "APPROVED",
|
||||
amount_money: { amount: 9999, currency: "EUR" },
|
||||
total_money: { amount: 9999, currency: "EUR" },
|
||||
approved_money: { amount: 9999, currency: "EUR" },
|
||||
customer_id: "cust_42",
|
||||
note: "Pre-authorisation for hold",
|
||||
card_details: { card: { card_brand: "MASTERCARD", last_4: "4242" } },
|
||||
created_at: "2026-02-01T10:00:00Z",
|
||||
updated_at: "2026-02-01T10:00:00Z",
|
||||
});
|
||||
|
||||
console.log(intent.captureMethod); // "manual"
|
||||
console.log(intent.status); // "authorized"
|
||||
console.log(intent.capturedAmount.amount); // 0n
|
||||
console.log(intent.paymentMethod);
|
||||
// { id: "sq_card_sq_pay_456", type: "card", brand: "mastercard", last4: "4242" }
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `mapPaymentStatus(squareStatus: string): PaymentStatus`
|
||||
|
||||
Maps Square status → suaveplan status. Known mappings:
|
||||
|
||||
| Square | suaveplan |
|
||||
|---|---|
|
||||
| `APPROVED` | `"authorized"` |
|
||||
| `COMPLETED` | `"captured"` |
|
||||
| `CANCELED` | `"canceled"` |
|
||||
| `FAILED` | `"failed"` |
|
||||
| `PENDING` | `"pending"` |
|
||||
| _other_ | `"failed"` |
|
||||
|
||||
### `mapPayment(p: SquarePaymentDto): PaymentIntent`
|
||||
|
||||
Shape the envelope. `capturedAmount.amount` is
|
||||
`BigInt(p.total_money.amount)` when `p.status === "COMPLETED"`,
|
||||
otherwise `0n`. `captureMethod` is `"manual"` when `p.approved_money`
|
||||
is set. `paymentMethod` is set when `p.card_details` is present.
|
||||
`refundedAmount.amount` is `0n` (refund totals are tracked by
|
||||
`PaymentEngine`, not derived here). `refunds` is an empty array.
|
||||
|
||||
### Types
|
||||
|
||||
- `SquareMoney` — `{ amount: number; currency: string }`.
|
||||
- `SquareCard` — `{ card_brand: string; last_4: string }`.
|
||||
- `SquarePaymentDto` — the subset of Square's `Payment` envelope this
|
||||
package consumes.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The status map is frozen at module init so accidental mutation
|
||||
throws in strict mode.
|
||||
- The card-brand normaliser is intentionally conservative: any brand
|
||||
Square introduces that does not match the `CardBrand` union
|
||||
falls back to `"unknown"` so downstream code never receives an
|
||||
invalid discriminant.
|
||||
- `paymentMethod.id` is synthesised as `sq_card_<payment-id>` because
|
||||
Square does not expose a stable card-fingerprint on the inline
|
||||
`card_details.card` object. Consumers needing a true stable card id
|
||||
should hydrate it from Square's Cards API and overlay it.
|
||||
120
docs/money/payment/payment-provider-square/src/mapping/refund.md
Normal file
120
docs/money/payment/payment-provider-square/src/mapping/refund.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Square refund mapping
|
||||
|
||||
## Purpose
|
||||
|
||||
Translates Square's `Refund` envelope (as returned by
|
||||
`POST /v2/refunds`) into `@suaveplan/payment`'s `Refund` shape. The
|
||||
mapping is small but load-bearing: Square encodes refund lifecycle
|
||||
states as upper-snake-case strings while the `RefundStatus`
|
||||
union is lower-case, and Square's `reason` is a free-form string
|
||||
where the `RefundReason` union is a closed discriminator.
|
||||
|
||||
The reason mapping is intentionally narrow — Square never reports
|
||||
machine-readable reason codes, so any non-empty reason collapses to
|
||||
`"requested_by_customer"` and an absent / empty reason collapses to
|
||||
`"other"`. Consumers that need richer reason granularity must layer
|
||||
their own mapping on top.
|
||||
|
||||
## Features
|
||||
|
||||
- `mapRefundStatus(squareStatus)` — exhaustive three-state map
|
||||
(`COMPLETED`, `PENDING`, everything-else) with `"failed"` covering
|
||||
Square's `REJECTED` and `FAILED` plus any forward-rolled values.
|
||||
- `mapRefund(r)` — full envelope-to-`Refund` shape including bigint
|
||||
amount coercion and reason defaulting.
|
||||
- `SquareRefundDto` — typed view of the Square refund envelope.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
mapRefund,
|
||||
mapRefundStatus,
|
||||
} from "@suaveplan/payment-provider-square";
|
||||
|
||||
mapRefundStatus("COMPLETED"); // "succeeded"
|
||||
|
||||
const refund = mapRefund({
|
||||
id: "sq_ref_123",
|
||||
payment_id: "sq_pay_123",
|
||||
amount_money: { amount: 2000, currency: "USD" },
|
||||
status: "COMPLETED",
|
||||
created_at: "2026-01-02T00:00:00Z",
|
||||
reason: "Customer changed mind",
|
||||
});
|
||||
|
||||
console.log(refund.status); // "succeeded"
|
||||
console.log(refund.reason); // "requested_by_customer"
|
||||
console.log(refund.amount.amount); // 2000n
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Show all three branches in turn — including the reason fallback and
|
||||
the `REJECTED → "failed"` collapse:
|
||||
|
||||
```ts
|
||||
import { mapRefund } from "@suaveplan/payment-provider-square";
|
||||
|
||||
const base = {
|
||||
id: "sq_ref_a",
|
||||
payment_id: "sq_pay_a",
|
||||
amount_money: { amount: 500, currency: "GBP" },
|
||||
created_at: "2026-03-01T00:00:00Z",
|
||||
};
|
||||
|
||||
const pending = mapRefund({ ...base, status: "PENDING" });
|
||||
console.log(pending.status); // "pending"
|
||||
console.log(pending.reason); // "other" (no reason supplied)
|
||||
|
||||
const rejected = mapRefund({ ...base, status: "REJECTED", reason: "" });
|
||||
console.log(rejected.status); // "failed"
|
||||
console.log(rejected.reason); // "other" (empty string)
|
||||
|
||||
const succeeded = mapRefund({
|
||||
...base,
|
||||
status: "COMPLETED",
|
||||
reason: "duplicate charge",
|
||||
});
|
||||
console.log(succeeded.status); // "succeeded"
|
||||
console.log(succeeded.reason); // "requested_by_customer"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `mapRefundStatus(squareRefundStatus: string): RefundStatus`
|
||||
|
||||
| Square | suaveplan |
|
||||
|---|---|
|
||||
| `COMPLETED` | `"succeeded"` |
|
||||
| `PENDING` | `"pending"` |
|
||||
| _other_ (`REJECTED`, `FAILED`, ...) | `"failed"` |
|
||||
|
||||
### `mapRefund(r: SquareRefundDto): Refund`
|
||||
|
||||
Produces a `Refund` whose `amount` mirrors `r.amount_money` (with
|
||||
the amount widened to `bigint`), whose `status` comes from
|
||||
`mapRefundStatus`, whose `reason` is `"requested_by_customer"` when
|
||||
`r.reason` is a non-empty string and `"other"` otherwise, and whose
|
||||
`createdAt` is `r.created_at` verbatim. `paymentIntentId` is set to
|
||||
`r.payment_id`.
|
||||
|
||||
### Types
|
||||
|
||||
- `SquareRefundDto` — the subset of Square's `Refund` envelope this
|
||||
package consumes.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The reason fallback to `"other"` is deliberate: Square's free-form
|
||||
`reason` carries operational notes ("customer called", "fraud
|
||||
flagged by ops"), not the discriminated reasons suaveplan tracks.
|
||||
Treating any non-empty value as `"requested_by_customer"` matches
|
||||
the upstream package's behaviour verbatim.
|
||||
- `mapRefundStatus` is exported separately so callers consuming raw
|
||||
Square webhooks (where the refund envelope arrives outside an HTTP
|
||||
response) can reuse the same mapping logic without round-tripping
|
||||
through `mapRefund`.
|
||||
- `r.amount_money.amount` is coerced via `BigInt()`. Square uses
|
||||
smallest-unit integers, so the coercion is exact for every
|
||||
documented currency.
|
||||
175
docs/money/payment/payment-provider-square/src/square/square.md
Normal file
175
docs/money/payment/payment-provider-square/src/square/square.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# SquareProvider
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`SquareProvider` is the Square Payments API adapter for
|
||||
`@suaveplan/payment`. It implements the structural `PaymentProvider`
|
||||
contract with `name: "square"` (narrowed at the type level) and
|
||||
routes every outbound HTTP call through the
|
||||
`@suaveplan/payment-providers` foundation's `httpRequest`, which
|
||||
handles JSON serialisation, the per-call timeout signal, external
|
||||
`AbortSignal` composition, and typed `PaymentProviderError` raising.
|
||||
|
||||
The provider preserves the upstream `square.ts` surface verbatim — the
|
||||
six lifecycle methods (`createIntent`, `confirmIntent`, `captureIntent`,
|
||||
`cancelIntent`, `refund`, `getIntent`), the canonical request bodies,
|
||||
and the status mapping — while wiring the previously-hard-coded
|
||||
`globalThis.crypto.randomUUID()` call onto the foundation's injectable
|
||||
`RandomIdFn` seam. Tests pass a deterministic counter instead of
|
||||
monkey-patching `globalThis.fetch`.
|
||||
|
||||
## Features
|
||||
|
||||
- Implements `PaymentProvider` with literal `name: "square"`.
|
||||
- Sends `Authorization: Bearer <apiKey>` and `Square-Version` on every
|
||||
request (`Square-Version` defaults to `2024-01-18`; override via
|
||||
`SquareConfig.apiVersion`).
|
||||
- Sandbox toggle (`sandbox: true`) flips the default base URL to
|
||||
`https://connect.squareupsandbox.com/v2`; an explicit `baseUrl`
|
||||
always wins.
|
||||
- Idempotency keys filled from the injected `randomId` seam when the
|
||||
caller omits one — deterministic in tests, `crypto.randomUUID()` by
|
||||
default in production.
|
||||
- Multi-location merchants supported via the required
|
||||
`SquareConfig.locationId` field, sent as `location_id` on every
|
||||
`CreatePayment` body.
|
||||
- All errors raised as `PaymentProviderError` (foundation contract);
|
||||
the package itself never throws `Error` instances directly.
|
||||
- Universal — no `node:`, `bun:`, `fs`, `path`, `crypto` imports.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { SquareProvider } from "@suaveplan/payment-provider-square";
|
||||
|
||||
const square = new SquareProvider({
|
||||
apiKey: process.env.SQUARE_ACCESS_TOKEN ?? "",
|
||||
locationId: process.env.SQUARE_LOCATION_ID ?? "",
|
||||
});
|
||||
|
||||
const intent = await square.createIntent({
|
||||
amount: { amount: 5000n, currency: "USD" },
|
||||
description: "Order #123",
|
||||
});
|
||||
|
||||
const captured = await square.captureIntent(intent.id);
|
||||
console.log(captured.status); // "captured"
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Inject deterministic seams (FetchLike + RandomIdFn) for testing,
|
||||
target the sandbox, pin the API version, and compose with an external
|
||||
`AbortSignal`:
|
||||
|
||||
```ts
|
||||
import type { FetchLike } from "@suaveplan/payment-providers";
|
||||
import { SquareProvider } from "@suaveplan/payment-provider-square";
|
||||
|
||||
const controller = new AbortController();
|
||||
const fakeFetch: FetchLike = async (url, init) => {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
payment: {
|
||||
id: "sq_pay_1",
|
||||
status: "COMPLETED",
|
||||
amount_money: { amount: 5000, currency: "USD" },
|
||||
total_money: { amount: 5000, currency: "USD" },
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
updated_at: "2026-01-01T00:00:00Z",
|
||||
},
|
||||
}),
|
||||
{ status: 200 }
|
||||
);
|
||||
};
|
||||
|
||||
const square = new SquareProvider({
|
||||
apiKey: "sandbox-token",
|
||||
locationId: "L1",
|
||||
sandbox: true,
|
||||
apiVersion: "2024-09-19",
|
||||
fetch: fakeFetch,
|
||||
signal: controller.signal,
|
||||
randomId: () => "deterministic-idempotency-key",
|
||||
timeoutMs: 5_000,
|
||||
});
|
||||
|
||||
const intent = await square.createIntent({
|
||||
amount: { amount: 5000n, currency: "USD" },
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `class SquareProvider implements PaymentProvider`
|
||||
|
||||
#### `constructor(config: SquareConfig)`
|
||||
|
||||
Accepts a `SquareConfig` (see `../types/config.md`). Required:
|
||||
`apiKey`, `locationId`. Optional: `baseUrl`, `sandbox`, `apiVersion`,
|
||||
`randomId`, `fetch`, `signal`, `timeoutMs`, `webhookSecret`.
|
||||
|
||||
#### `readonly name: "square"`
|
||||
|
||||
Literal — narrows at the type level for discriminated unions.
|
||||
|
||||
#### `createIntent(input: CreatePaymentIntentInput): Promise<PaymentIntent>`
|
||||
|
||||
POSTs `<baseUrl>/payments` with `amount_money`, `idempotency_key`
|
||||
(falls back to `randomId()`), `autocomplete` (`true` unless
|
||||
`captureMethod === "manual"`), `location_id`, and the optional
|
||||
`customer_id`, `note`, `source_id` fields. Returns the mapped
|
||||
`PaymentIntent`.
|
||||
|
||||
#### `confirmIntent(intentId: string): Promise<PaymentIntent>`
|
||||
|
||||
No-op for Square (payments are auto-confirmed). Delegates to
|
||||
`getIntent(intentId)`.
|
||||
|
||||
#### `captureIntent(intentId: string): Promise<PaymentIntent>`
|
||||
|
||||
POSTs `<baseUrl>/payments/<intentId>/complete` with no body.
|
||||
|
||||
#### `cancelIntent(intentId: string): Promise<PaymentIntent>`
|
||||
|
||||
POSTs `<baseUrl>/payments/<intentId>/cancel` with no body.
|
||||
|
||||
#### `refund(input: RefundInput): Promise<Refund>`
|
||||
|
||||
POSTs `<baseUrl>/refunds` with `payment_id`, `idempotency_key`
|
||||
(falls back to `randomId()`), optional `amount_money`, and optional
|
||||
`reason`. Returns the mapped `Refund`.
|
||||
|
||||
#### `getIntent(intentId: string): Promise<PaymentIntent>`
|
||||
|
||||
GETs `<baseUrl>/payments/<intentId>`.
|
||||
|
||||
### Throws
|
||||
|
||||
Every method throws `PaymentProviderError` on HTTP failure, timeout,
|
||||
or JSON parse failure (raised by the foundation's `httpRequest`).
|
||||
`err.provider` is always `"square"`; `err.httpStatus` is set when the
|
||||
failure originated from a non-ok response.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The provider stores its `FetchLike` / `AbortSignal` / `timeoutMs` /
|
||||
`randomId` once at construction and passes them through to every
|
||||
`httpRequest` call so behaviour is deterministic across method
|
||||
invocations.
|
||||
- `location_id` is sent on `CreatePayment` only — Square does not
|
||||
require it on `CompletePayment` / `CancelPayment` / `Refund` calls.
|
||||
- The default `randomId` is a closure that calls `crypto.randomUUID()`
|
||||
at call time. Runtimes without a global `crypto` MUST inject their
|
||||
own `RandomIdFn`.
|
||||
- The class does not duplicate webhook verification logic; Square
|
||||
webhook signatures are verified by `@suaveplan/payment`'s
|
||||
`WebhookVerifier`, which is provider-agnostic.
|
||||
- All formatting flows through the foundation: caller-supplied
|
||||
`Content-Type` / `Accept` are preserved by `httpRequest`'s shallow
|
||||
header merge, but the Square-specific `Authorization` and
|
||||
`Square-Version` headers always win on collision.
|
||||
102
docs/money/payment/payment-provider-square/src/types/config.md
Normal file
102
docs/money/payment/payment-provider-square/src/types/config.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# SquareConfig and default constants
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the configuration shape `SquareProvider` accepts and the three
|
||||
default constants the provider falls back to when the caller omits the
|
||||
corresponding optional field. The interface extends the shared
|
||||
`ApiKeyConfig` from `@suaveplan/payment-providers` so every common
|
||||
injectable seam — `fetch`, `timeoutMs`, `signal`, `baseUrl`,
|
||||
`webhookSecret` — is inherited rather than redeclared.
|
||||
|
||||
## Features
|
||||
|
||||
- `SquareConfig extends ApiKeyConfig` with `locationId: string`
|
||||
(required), `sandbox?: boolean`, `apiVersion?: string`, and
|
||||
`randomId?: RandomIdFn`.
|
||||
- Three exported constants pin the production base URL, the sandbox
|
||||
base URL, and the default `Square-Version` header value so they
|
||||
show up exactly once across the package and are auditable.
|
||||
- Type-only — the file ships no runtime objects beyond the constants;
|
||||
the interface is erased at build time.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import type { SquareConfig } from "@suaveplan/payment-provider-square";
|
||||
|
||||
const config: SquareConfig = {
|
||||
apiKey: "sq0atp-...",
|
||||
locationId: "L1234567890",
|
||||
};
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Pin every optional field — useful for the sandbox + deterministic
|
||||
testing combination:
|
||||
|
||||
```ts
|
||||
import type { SquareConfig } from "@suaveplan/payment-provider-square";
|
||||
import {
|
||||
SQUARE_DEFAULT_API_VERSION,
|
||||
SQUARE_SANDBOX_BASE_URL,
|
||||
} from "@suaveplan/payment-provider-square";
|
||||
|
||||
const config: SquareConfig = {
|
||||
apiKey: "sq0atp-sandbox-...",
|
||||
locationId: "L_SANDBOX",
|
||||
sandbox: true,
|
||||
apiVersion: SQUARE_DEFAULT_API_VERSION,
|
||||
randomId: () => "deterministic-id",
|
||||
timeoutMs: 5_000,
|
||||
baseUrl: SQUARE_SANDBOX_BASE_URL, // optional — sandbox flag picks this up
|
||||
};
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `interface SquareConfig extends ApiKeyConfig`
|
||||
|
||||
| Field | Type | Required | Notes |
|
||||
|---|---|---|---|
|
||||
| `apiKey` | `string` | yes | Inherited from `ApiKeyConfig`. |
|
||||
| `locationId` | `string` | yes | Square `location_id` sent on every `CreatePayment` body. |
|
||||
| `sandbox` | `boolean` | no | When `true`, flips the default base URL to `SQUARE_SANDBOX_BASE_URL`. |
|
||||
| `apiVersion` | `string` | no | Value of the `Square-Version` header. Defaults to `SQUARE_DEFAULT_API_VERSION`. |
|
||||
| `randomId` | `RandomIdFn` | no | Generator for missing idempotency keys. Defaults to `crypto.randomUUID()`. |
|
||||
| `baseUrl` | `string` | no | Inherited from `ApiKeyConfig`. Wins over `sandbox`. |
|
||||
| `webhookSecret` | `string` | no | Inherited from `ApiKeyConfig`. Not used by the provider itself. |
|
||||
| `fetch` | `FetchLike` | no | Inherited from `ProviderCommonOptions`. |
|
||||
| `timeoutMs` | `number` | no | Inherited from `ProviderCommonOptions`. |
|
||||
| `signal` | `AbortSignal` | no | Inherited from `ProviderCommonOptions`. |
|
||||
|
||||
### `const SQUARE_DEFAULT_BASE_URL`
|
||||
|
||||
`"https://connect.squareup.com/v2"` — Square production base URL.
|
||||
|
||||
### `const SQUARE_SANDBOX_BASE_URL`
|
||||
|
||||
`"https://connect.squareupsandbox.com/v2"` — Square sandbox base URL.
|
||||
|
||||
### `const SQUARE_DEFAULT_API_VERSION`
|
||||
|
||||
`"2024-01-18"` — default `Square-Version` header value.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `locationId` is intentionally required (the upstream
|
||||
`payment-providers` Square adapter omitted it; consumers had to
|
||||
wrap the provider to inject it). Multi-location merchants are the
|
||||
common case, and Square's `CreatePayment` endpoint rejects requests
|
||||
that target the wrong location implicitly.
|
||||
- The `sandbox` flag is a convenience — callers who need exotic base
|
||||
URLs (Square Connect for the EU, an internal proxy, etc.) should
|
||||
set `baseUrl` directly.
|
||||
- `randomId` is shaped as a synchronous `() => string` rather than a
|
||||
promise-returning function. Square's idempotency keys are opaque;
|
||||
any unique-enough string works.
|
||||
Reference in New Issue
Block a user