@aquarian-metals/coin-moebius-square 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aquarian-metals
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @aquarian-metals/coin-moebius-square
2
+
3
+ Square (Block) provider for **[Coin Moebius](https://github.com/aquarian-metals/coin-moebius)**.
4
+
5
+ Two entries in one package:
6
+
7
+ - `@aquarian-metals/coin-moebius-square` — browser entry, redirects to Square's hosted checkout (Payment Link flow).
8
+ - `@aquarian-metals/coin-moebius-square/server` — Node-only HMAC-SHA256 webhook verifier. **Never import this from browser code.**
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @aquarian-metals/coin-moebius-square
14
+ ```
15
+
16
+ No additional dependencies — the server verifier uses Web Crypto exclusively.
17
+
18
+ ## Use — browser
19
+
20
+ ```ts
21
+ import { createSquareProvider } from '@aquarian-metals/coin-moebius-square';
22
+ import { createPaymentManager } from '@aquarian-metals/coin-moebius';
23
+
24
+ const payments = createPaymentManager({
25
+ providers: [
26
+ createSquareProvider({
27
+ sessionEndpoint: '/api/checkout/square',
28
+ }),
29
+ ],
30
+ });
31
+ ```
32
+
33
+ Your session endpoint calls `POST /v2/online-checkout/payment-links` and returns the `payment_link.url` field as `{ url }`. The provider fires `onPending` and redirects the buyer to Square's hosted checkout.
34
+
35
+ ## Use — server (webhook verification)
36
+
37
+ ```ts
38
+ import { createSquareVerifier } from '@aquarian-metals/coin-moebius-square/server';
39
+
40
+ const verify = createSquareVerifier({
41
+ signatureKey: process.env.SQUARE_WEBHOOK_SIGNATURE_KEY,
42
+ notificationUrl: 'https://your-public-domain.example/webhooks/square',
43
+ });
44
+
45
+ // inside your webhook route:
46
+ const result = await verify.verify(rawBody, request.headers);
47
+ ```
48
+
49
+ ### Why the verifier needs a `notificationUrl`
50
+
51
+ Square signs the webhook over **`notificationUrl + rawBody`** — the public URL the merchant configured on the webhook subscription is part of the HMAC input. A worker running behind a reverse proxy or Cloudflare typically cannot recover the original public URL from the inbound request (it sees an internal route, a different host, or a stripped path), so the verifier requires the merchant to pass the URL explicitly.
52
+
53
+ **The URL must match byte-for-byte** with what the merchant configured in Square's Developer Console (Webhooks → your subscription → Notification URL). Any difference — trailing slash, scheme, port, capitalization of the host — produces a silent signature failure. Treat the value like a secret and pin it in your environment configuration.
54
+
55
+ ### Signature key
56
+
57
+ The signature key is **subscription-specific**, generated in Square's Developer Console alongside the subscription. It is not the same as the application's access token. To rotate, recreate the subscription.
58
+
59
+ ### Status mapping
60
+
61
+ | Square event | Inner status | `PaymentResult.status` |
62
+ | ----------------------- | ---------------------- | ---------------------------------------------------- |
63
+ | `payment.created` | — | `pending` |
64
+ | `payment.updated` | `COMPLETED` | `success` |
65
+ | `payment.updated` | `APPROVED` (auth-only) | `pending` |
66
+ | `payment.updated` | `FAILED` or `CANCELED` | `failed` |
67
+ | `refund.created` | — | `pending` |
68
+ | `refund.updated` | `COMPLETED` | `refunded` |
69
+ | `refund.updated` | `FAILED` or `REJECTED` | `failed` |
70
+ | `dispute.created` | — | `disputed` |
71
+ | `dispute.state.updated` | — | `disputed` |
72
+ | anything else | — | (verifier returns `null`, signature still validated) |
73
+
74
+ The `paymentId` on the returned `PaymentResult` is the Square `payment.id` whenever available (preferred for cross-event correlation across payment / refund / dispute on the same purchase). Amounts are converted from Square's smallest-currency-unit integers (e.g., cents for USD) to a major-unit decimal to match the rest of the SDK.
75
+
76
+ ### Known gap: no replay-window enforcement
77
+
78
+ Square's signature scheme does not include a timestamp, so the verifier cannot reject stale-and-replayed deliveries on its own. If your application is sensitive to replays, deduplicate at the application layer using the webhook's `event_id` field.
79
+
80
+ ### Sandbox vs production
81
+
82
+ The signature scheme is the same in both environments — the verifier has no mode flag. Sandbox API endpoints are at `connect.squareupsandbox.com`; production is at `connect.squareup.com`. Your session endpoint chooses which one to hit; the verifier only cares about the signature key + notification URL pair.
83
+
84
+ ### Currency + locations
85
+
86
+ Square locations have a per-location currency, but the webhook payload carries the actual currency on `amount_money.currency`, so the verifier surfaces whatever the payload says. Merchants with multiple locations don't need to override anything.
87
+
88
+ ## License
89
+
90
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Square client-side provider for Coin Moebius.
3
+ *
4
+ * Hosted-checkout flow via Square's Payment Link API. The provider POSTs the
5
+ * buyer's selection to the caller's `sessionEndpoint`, receives `{ url }`
6
+ * pointing at the hosted checkout (`https://square.link/u/<id>` or the
7
+ * longer `https://checkout.square.site/<id>` form), fires `onPending`, and
8
+ * redirects the buyer. Square handles the wallet, funding source, and
9
+ * receipt; the merchant's server receives the webhook on completion.
10
+ *
11
+ * import { createSquareProvider } from '@aquarian-metals/coin-moebius-square';
12
+ * const square = createSquareProvider({
13
+ * sessionEndpoint: '/api/checkout/square',
14
+ * });
15
+ *
16
+ * const manager = createPaymentManager({ providers: [square] });
17
+ * await manager.initiate({ productId: 'pro', amount: 9.99, currency: 'USD' });
18
+ *
19
+ * The session endpoint is expected to call Square's
20
+ * `POST /v2/online-checkout/payment-links` with a `quick_pay` or `order`
21
+ * body and return `{ url }` using the `payment_link.url` value from the
22
+ * response.
23
+ */
24
+ import type { PaymentProvider } from '@aquarian-metals/coin-moebius-core';
25
+ export interface SquareProviderConfig {
26
+ /** Full URL of the session endpoint that returns `{ url }`. */
27
+ sessionEndpoint: string;
28
+ /** Optional fetch override — used by tests. Defaults to global `fetch`. */
29
+ fetcher?: typeof fetch;
30
+ /** Optional navigation override — used by tests. Defaults to `location.assign`. */
31
+ navigate?: (url: string) => void;
32
+ }
33
+ /**
34
+ * Build a `PaymentProvider` registered as `id: 'square'`. Fires `onPending`
35
+ * immediately, then navigates to the Square-hosted checkout URL. Final
36
+ * settlement lands on the server via webhook (HMAC-SHA256, see `./server`).
37
+ */
38
+ export declare function createSquareProvider(config: SquareProviderConfig): PaymentProvider;
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EACX,eAAe,EAGf,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACpC,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAQD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,eAAe,CAiDlF"}
package/dist/index.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Build a `PaymentProvider` registered as `id: 'square'`. Fires `onPending`
3
+ * immediately, then navigates to the Square-hosted checkout URL. Final
4
+ * settlement lands on the server via webhook (HMAC-SHA256, see `./server`).
5
+ */
6
+ export function createSquareProvider(config) {
7
+ const fetcher = config.fetcher ?? globalThis.fetch.bind(globalThis);
8
+ const navigate = config.navigate ??
9
+ ((url) => {
10
+ window.location.assign(url);
11
+ });
12
+ return {
13
+ id: 'square',
14
+ name: 'Square',
15
+ async initiate(options, callbacks) {
16
+ try {
17
+ const body = {
18
+ productId: options.productId,
19
+ amount: options.amount,
20
+ currency: options.currency,
21
+ };
22
+ if (options.metadata)
23
+ body.metadata = options.metadata;
24
+ const response = await fetcher(config.sessionEndpoint, {
25
+ method: 'POST',
26
+ headers: { 'Content-Type': 'application/json' },
27
+ body: JSON.stringify(body),
28
+ });
29
+ if (!response.ok) {
30
+ throw new Error(`coin-moebius/square: session endpoint responded ${response.status}`);
31
+ }
32
+ const payload = (await response.json());
33
+ if (!payload.url) {
34
+ throw new Error('coin-moebius/square: session response missing `url`');
35
+ }
36
+ const result = {
37
+ status: 'pending',
38
+ paymentId: payload.paymentId ?? '',
39
+ provider: 'square',
40
+ amount: options.amount,
41
+ currency: options.currency,
42
+ metadata: options.metadata ?? {},
43
+ timestamp: Date.now(),
44
+ };
45
+ callbacks.onPending?.(result);
46
+ navigate(payload.url);
47
+ }
48
+ catch (err) {
49
+ callbacks.onError(err instanceof Error ? err : new Error(String(err)));
50
+ }
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4CA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAA4B;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpE,MAAM,QAAQ,GACb,MAAM,CAAC,QAAQ;QACf,CAAC,CAAC,GAAW,EAAE,EAAE;YAChB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IAEJ,OAAO;QACN,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,KAAK,CAAC,QAAQ,CAAC,OAAwB,EAAE,SAAS;YACjD,IAAI,CAAC;gBACJ,MAAM,IAAI,GAA4B;oBACrC,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;iBAC1B,CAAC;gBACF,IAAI,OAAO,CAAC,QAAQ;oBAAE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;gBAEvD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE;oBACtD,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;iBAC1B,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,mDAAmD,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBACvF,CAAC;gBACD,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAoB,CAAC;gBAC3D,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBACxE,CAAC;gBAED,MAAM,MAAM,GAAkB;oBAC7B,MAAM,EAAE,SAAS;oBACjB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;oBAClC,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;oBAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;iBACrB,CAAC;gBACF,SAAS,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC;gBAC9B,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,SAAS,CAAC,OAAO,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxE,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Square server-side webhook verifier. Implements Square's HMAC-SHA256
3
+ * signature scheme as documented at
4
+ * <https://developer.squareup.com/docs/webhooks/step3validate>:
5
+ *
6
+ * X-Square-HmacSha256-Signature: <base64(HMAC-SHA256(notificationUrl + rawBody, signatureKey))>
7
+ *
8
+ * The signature is computed over the **concatenation of the notification
9
+ * URL and the raw body**, with no separator. The `notificationUrl` must
10
+ * exactly match the URL the merchant configured on their webhook
11
+ * subscription in Square's Developer Console. The verifier accepts it as
12
+ * a required config field because workers running behind a reverse proxy
13
+ * or Cloudflare typically can't recover the original public URL from the
14
+ * inbound request.
15
+ *
16
+ * The signature key is **subscription-specific**, generated in Square's
17
+ * Developer Console alongside the subscription. It is not the same as the
18
+ * application's access token. Rotate by recreating the subscription.
19
+ *
20
+ * Status mapping. `null` results mean the event was signature-verified but
21
+ * does not map to a payment-status change consumers should record.
22
+ *
23
+ * payment.created → pending
24
+ * payment.updated (status COMPLETED) → success
25
+ * payment.updated (status APPROVED) → pending (auth-only)
26
+ * payment.updated (status FAILED or CANCELED) → failed
27
+ * refund.created → pending
28
+ * refund.updated (status COMPLETED) → refunded
29
+ * refund.updated (status FAILED) → failed
30
+ * dispute.created → disputed
31
+ * dispute.state.updated → disputed
32
+ * anything else → null
33
+ *
34
+ * **Known gap:** Square's signature scheme has no timestamp component, so
35
+ * the verifier cannot enforce a replay window. Merchants who care about
36
+ * replay protection should deduplicate at the application layer using the
37
+ * webhook's `event_id` field. Documented in the README.
38
+ */
39
+ import type { WebhookEvent } from '@aquarian-metals/coin-moebius-core';
40
+ export interface SquareVerifierConfig {
41
+ /**
42
+ * The subscription's signature key from Square's Developer Console
43
+ * (Webhooks → your subscription → Signature key).
44
+ */
45
+ signatureKey: string;
46
+ /**
47
+ * The exact notification URL configured on the Square webhook
48
+ * subscription. Must match byte-for-byte (including scheme, host, port,
49
+ * path, and any trailing slash) — Square HMACs over `notificationUrl +
50
+ * rawBody`, so a mismatch produces silent signature failure.
51
+ */
52
+ notificationUrl: string;
53
+ }
54
+ export interface WebhookVerifier {
55
+ verify(rawBody: unknown, headers: Record<string, string | undefined>): Promise<WebhookEvent | null>;
56
+ }
57
+ export declare function createSquareVerifier(config: SquareVerifierConfig): WebhookVerifier;
58
+ /**
59
+ * Base64-encoded HMAC-SHA256 of `notificationUrl + rawBody`, keyed by the
60
+ * subscription's signature key. Exported so callers with non-standard
61
+ * rawBody pipelines can verify with the same routine without going through
62
+ * the full registry path.
63
+ */
64
+ export declare function computeSquareSignature(notificationUrl: string, rawBody: Uint8Array, signatureKey: string): Promise<string>;
65
+ /**
66
+ * Square does not expose a buyer-facing customer portal in its
67
+ * Subscriptions API. Buyers don't manage their own subscriptions on the
68
+ * Square side; the merchant cancels from their Square dashboard, and the
69
+ * buyer is notified by email. We surface the merchant-side dashboard URL
70
+ * so the merchant can drill into a specific subscription for support.
71
+ *
72
+ * `mode` toggles between live and sandbox dashboards. Pass the
73
+ * subscription id to deep-link directly into the row when available.
74
+ */
75
+ export declare function getSquarePortalUrl(opts?: {
76
+ mode?: 'live' | 'sandbox';
77
+ subscriptionId?: string;
78
+ }): string;
79
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEtF,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,MAAM,CACL,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACzC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,eAAe,CAqClF;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC3C,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,UAAU,EACnB,YAAY,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAkVD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,GAAE;IACL,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACnB,GACJ,MAAM,CAMR"}
package/dist/server.js ADDED
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Square server-side webhook verifier. Implements Square's HMAC-SHA256
3
+ * signature scheme as documented at
4
+ * <https://developer.squareup.com/docs/webhooks/step3validate>:
5
+ *
6
+ * X-Square-HmacSha256-Signature: <base64(HMAC-SHA256(notificationUrl + rawBody, signatureKey))>
7
+ *
8
+ * The signature is computed over the **concatenation of the notification
9
+ * URL and the raw body**, with no separator. The `notificationUrl` must
10
+ * exactly match the URL the merchant configured on their webhook
11
+ * subscription in Square's Developer Console. The verifier accepts it as
12
+ * a required config field because workers running behind a reverse proxy
13
+ * or Cloudflare typically can't recover the original public URL from the
14
+ * inbound request.
15
+ *
16
+ * The signature key is **subscription-specific**, generated in Square's
17
+ * Developer Console alongside the subscription. It is not the same as the
18
+ * application's access token. Rotate by recreating the subscription.
19
+ *
20
+ * Status mapping. `null` results mean the event was signature-verified but
21
+ * does not map to a payment-status change consumers should record.
22
+ *
23
+ * payment.created → pending
24
+ * payment.updated (status COMPLETED) → success
25
+ * payment.updated (status APPROVED) → pending (auth-only)
26
+ * payment.updated (status FAILED or CANCELED) → failed
27
+ * refund.created → pending
28
+ * refund.updated (status COMPLETED) → refunded
29
+ * refund.updated (status FAILED) → failed
30
+ * dispute.created → disputed
31
+ * dispute.state.updated → disputed
32
+ * anything else → null
33
+ *
34
+ * **Known gap:** Square's signature scheme has no timestamp component, so
35
+ * the verifier cannot enforce a replay window. Merchants who care about
36
+ * replay protection should deduplicate at the application layer using the
37
+ * webhook's `event_id` field. Documented in the README.
38
+ */
39
+ export function createSquareVerifier(config) {
40
+ return {
41
+ async verify(rawBody, headers) {
42
+ if (!config.signatureKey) {
43
+ throw new Error('coin-moebius/square: signatureKey missing on verifier config');
44
+ }
45
+ if (!config.notificationUrl) {
46
+ throw new Error('coin-moebius/square: notificationUrl missing on verifier config');
47
+ }
48
+ const signatureHeader = headerValue(headers, 'x-square-hmacsha256-signature');
49
+ if (!signatureHeader) {
50
+ throw new Error('coin-moebius/square: missing x-square-hmacsha256-signature header');
51
+ }
52
+ const bodyBytes = bodyToBytes(rawBody);
53
+ const expected = await computeSquareSignature(config.notificationUrl, bodyBytes, config.signatureKey);
54
+ if (!timingSafeStringEqual(expected, signatureHeader.trim())) {
55
+ throw new Error('coin-moebius/square: invalid signature');
56
+ }
57
+ const bodyString = new TextDecoder().decode(bodyBytes);
58
+ let parsed;
59
+ try {
60
+ parsed = JSON.parse(bodyString);
61
+ }
62
+ catch {
63
+ throw new Error('coin-moebius/square: body is not valid JSON');
64
+ }
65
+ return toPaymentResult(parsed);
66
+ },
67
+ };
68
+ }
69
+ /**
70
+ * Base64-encoded HMAC-SHA256 of `notificationUrl + rawBody`, keyed by the
71
+ * subscription's signature key. Exported so callers with non-standard
72
+ * rawBody pipelines can verify with the same routine without going through
73
+ * the full registry path.
74
+ */
75
+ export async function computeSquareSignature(notificationUrl, rawBody, signatureKey) {
76
+ const urlBytes = new TextEncoder().encode(notificationUrl);
77
+ const message = new Uint8Array(urlBytes.length + rawBody.length);
78
+ message.set(urlBytes, 0);
79
+ message.set(rawBody, urlBytes.length);
80
+ const keyBytes = new TextEncoder().encode(signatureKey);
81
+ const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
82
+ const sigBuf = await crypto.subtle.sign('HMAC', key, message);
83
+ return toBase64(new Uint8Array(sigBuf));
84
+ }
85
+ function toPaymentResult(event) {
86
+ const eventType = event.type ?? '';
87
+ // Subscription lifecycle events take precedence over the one-time
88
+ // payment mapping. Square emits separate top-level event types for
89
+ // subscriptions (no overlap with payment events), so the dispatch is
90
+ // straightforward.
91
+ const subscriptionEvent = toSubscriptionEvent(event, eventType);
92
+ if (subscriptionEvent)
93
+ return subscriptionEvent;
94
+ const data = event.data?.object ?? {};
95
+ const payment = data.payment;
96
+ const refund = data.refund;
97
+ const dispute = data.dispute;
98
+ const status = mapEvent(eventType, payment, refund);
99
+ if (status === null)
100
+ return null;
101
+ const { paymentId, amount, currency } = readDetails(eventType, payment, refund, dispute);
102
+ return {
103
+ kind: 'payment',
104
+ status,
105
+ paymentId,
106
+ provider: 'square',
107
+ amount,
108
+ currency,
109
+ metadata: {
110
+ squareEventType: eventType,
111
+ squareEventId: event.event_id,
112
+ squarePaymentStatus: payment?.status,
113
+ squareRefundStatus: refund?.status,
114
+ squareDisputeState: dispute?.state,
115
+ },
116
+ timestamp: Date.now(),
117
+ raw: event,
118
+ };
119
+ }
120
+ /**
121
+ * Map Square subscription event types onto our normalized
122
+ * `SubscriptionEvent`. Returns `null` for any other event so the caller
123
+ * falls through to the payment-event path.
124
+ *
125
+ * subscription.created → subscription.created
126
+ * invoice.payment_made (subscription-linked) → subscription.renewed
127
+ * invoice.scheduled_charge_failed → subscription.payment_failed
128
+ * subscription.updated → subscription.updated
129
+ * subscription.canceled → subscription.canceled
130
+ */
131
+ function toSubscriptionEvent(event, eventType) {
132
+ const innerObject = (event.data?.object ?? {});
133
+ let subscriptionType = null;
134
+ switch (eventType) {
135
+ case 'subscription.created':
136
+ subscriptionType = 'subscription.created';
137
+ break;
138
+ case 'subscription.updated':
139
+ subscriptionType = 'subscription.updated';
140
+ break;
141
+ case 'subscription.canceled':
142
+ case 'subscription.deactivated':
143
+ subscriptionType = 'subscription.canceled';
144
+ break;
145
+ case 'invoice.payment_made':
146
+ if (innerObject.invoice?.subscription_id)
147
+ subscriptionType = 'subscription.renewed';
148
+ break;
149
+ case 'invoice.scheduled_charge_failed':
150
+ if (innerObject.invoice?.subscription_id)
151
+ subscriptionType = 'subscription.payment_failed';
152
+ break;
153
+ default:
154
+ return null;
155
+ }
156
+ if (subscriptionType === null)
157
+ return null;
158
+ const subscription = innerObject.subscription;
159
+ const invoice = innerObject.invoice;
160
+ const subscriptionId = subscription?.id ?? invoice?.subscription_id ?? '';
161
+ if (!subscriptionId)
162
+ return null;
163
+ const status = mapSquareSubscriptionStatus(eventType, subscription?.status);
164
+ const { amount, currency } = readSquareSubscriptionAmount(invoice);
165
+ const charged = subscription?.charged_through_date;
166
+ // Square's `charged_through_date` is a calendar date (`YYYY-MM-DD`).
167
+ // Treat it as midnight UTC of the day AFTER, since that's when the
168
+ // next renewal becomes due.
169
+ const currentPeriodEnd = parseChargedThroughDate(charged);
170
+ return {
171
+ kind: 'subscription',
172
+ type: subscriptionType,
173
+ subscriptionId,
174
+ provider: 'square',
175
+ productId: typeof subscription?.plan_variation_id === 'string'
176
+ ? subscription.plan_variation_id
177
+ : typeof subscription?.plan_id === 'string'
178
+ ? subscription.plan_id
179
+ : null,
180
+ customerRef: typeof subscription?.customer_id === 'string' ? subscription.customer_id : null,
181
+ status,
182
+ currentPeriodEnd,
183
+ amount,
184
+ currency,
185
+ metadata: {
186
+ squareEventType: eventType,
187
+ squareEventId: event.event_id,
188
+ },
189
+ timestamp: Date.now(),
190
+ raw: event,
191
+ };
192
+ }
193
+ function mapSquareSubscriptionStatus(eventType, rawStatus) {
194
+ if (eventType === 'subscription.canceled' || eventType === 'subscription.deactivated') {
195
+ return 'canceled';
196
+ }
197
+ if (eventType === 'invoice.scheduled_charge_failed')
198
+ return 'past_due';
199
+ switch (rawStatus) {
200
+ case 'ACTIVE':
201
+ return 'active';
202
+ case 'PAUSED':
203
+ return 'paused';
204
+ case 'CANCELED':
205
+ case 'DEACTIVATED':
206
+ return 'canceled';
207
+ default:
208
+ return 'unknown';
209
+ }
210
+ }
211
+ function readSquareSubscriptionAmount(invoice) {
212
+ const money = invoice?.payment_requests?.[0]?.computed_amount_money;
213
+ const cents = money?.amount;
214
+ const amount = typeof cents === 'number' ? cents / 100 : 0;
215
+ const currency = (money?.currency ?? 'USD').toUpperCase();
216
+ return { amount, currency };
217
+ }
218
+ function parseChargedThroughDate(value) {
219
+ if (typeof value !== 'string')
220
+ return null;
221
+ const ms = Date.parse(`${value}T00:00:00Z`);
222
+ return Number.isFinite(ms) ? Math.floor(ms / 1000) : null;
223
+ }
224
+ function mapEvent(eventType, payment, refund) {
225
+ if (eventType === 'payment.created')
226
+ return 'pending';
227
+ if (eventType === 'payment.updated') {
228
+ const innerStatus = payment?.status;
229
+ if (innerStatus === 'COMPLETED')
230
+ return 'success';
231
+ if (innerStatus === 'APPROVED')
232
+ return 'pending';
233
+ if (innerStatus === 'FAILED' || innerStatus === 'CANCELED')
234
+ return 'failed';
235
+ // Unknown inner status — surface as pending so consumers don't miss
236
+ // it; they can inspect `raw.data.object.payment.status` for detail.
237
+ return 'pending';
238
+ }
239
+ if (eventType === 'refund.created')
240
+ return 'pending';
241
+ if (eventType === 'refund.updated') {
242
+ const innerStatus = refund?.status;
243
+ if (innerStatus === 'COMPLETED')
244
+ return 'refunded';
245
+ if (innerStatus === 'FAILED' || innerStatus === 'REJECTED')
246
+ return 'failed';
247
+ return 'pending';
248
+ }
249
+ if (eventType === 'dispute.created' || eventType === 'dispute.state.updated') {
250
+ return 'disputed';
251
+ }
252
+ return null;
253
+ }
254
+ function readDetails(eventType, payment, refund, dispute) {
255
+ // Prefer the original payment id as the stable correlation key across
256
+ // payment / refund / dispute events on the same purchase.
257
+ const correlationPaymentId = payment?.id ?? refund?.payment_id ?? dispute?.disputed_payment?.payment_id ?? '';
258
+ let money;
259
+ if (eventType.startsWith('payment.')) {
260
+ money = payment?.amount_money;
261
+ }
262
+ else if (eventType.startsWith('refund.')) {
263
+ money = refund?.amount_money;
264
+ }
265
+ else if (eventType.startsWith('dispute.')) {
266
+ money = dispute?.amount_money;
267
+ }
268
+ // Square uses smallest-currency-unit integers (cents for USD, etc.).
269
+ // Convert to a major-unit decimal here to match the rest of the SDK's
270
+ // `amount` semantics (Stripe verifier does the same `/100`).
271
+ const minorAmount = typeof money?.amount === 'number' ? money.amount : 0;
272
+ const currency = (money?.currency ?? 'USD').toUpperCase();
273
+ const amount = minorAmount / 100;
274
+ return { paymentId: correlationPaymentId, amount, currency };
275
+ }
276
+ // --- helpers ---------------------------------------------------------------
277
+ function bodyToBytes(rawBody) {
278
+ if (rawBody instanceof Uint8Array)
279
+ return rawBody;
280
+ if (typeof rawBody === 'string')
281
+ return new TextEncoder().encode(rawBody);
282
+ if (rawBody && typeof rawBody === 'object') {
283
+ return new TextEncoder().encode(JSON.stringify(rawBody));
284
+ }
285
+ throw new Error('coin-moebius/square: unsupported body type');
286
+ }
287
+ function headerValue(headers, name) {
288
+ const lower = name.toLowerCase();
289
+ for (const [key, value] of Object.entries(headers)) {
290
+ if (key.toLowerCase() === lower)
291
+ return value;
292
+ }
293
+ return undefined;
294
+ }
295
+ function timingSafeStringEqual(a, b) {
296
+ if (a.length !== b.length)
297
+ return false;
298
+ let mismatch = 0;
299
+ for (let i = 0; i < a.length; i++) {
300
+ mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
301
+ }
302
+ return mismatch === 0;
303
+ }
304
+ function toBase64(bytes) {
305
+ let binary = '';
306
+ for (const b of bytes)
307
+ binary += String.fromCharCode(b);
308
+ return btoa(binary);
309
+ }
310
+ /**
311
+ * Square does not expose a buyer-facing customer portal in its
312
+ * Subscriptions API. Buyers don't manage their own subscriptions on the
313
+ * Square side; the merchant cancels from their Square dashboard, and the
314
+ * buyer is notified by email. We surface the merchant-side dashboard URL
315
+ * so the merchant can drill into a specific subscription for support.
316
+ *
317
+ * `mode` toggles between live and sandbox dashboards. Pass the
318
+ * subscription id to deep-link directly into the row when available.
319
+ */
320
+ export function getSquarePortalUrl(opts = {}) {
321
+ const base = opts.mode === 'sandbox'
322
+ ? 'https://app.squareupsandbox.com/dashboard/subscriptions'
323
+ : 'https://squareup.com/dashboard/subscriptions';
324
+ return opts.subscriptionId ? `${base}/${opts.subscriptionId}` : base;
325
+ }
326
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@aquarian-metals/coin-moebius-square",
3
+ "version": "1.0.0",
4
+ "description": "Square (Block) provider for Coin Moebius — Payment Link redirect flow, plus a server-only HMAC-SHA256 webhook verifier.",
5
+ "keywords": [
6
+ "payments",
7
+ "square",
8
+ "block",
9
+ "payment-link",
10
+ "checkout",
11
+ "webhook",
12
+ "coin-moebius"
13
+ ],
14
+ "author": "aquarian-metals",
15
+ "license": "MIT",
16
+ "homepage": "https://github.com/aquarian-metals/coin-moebius#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/aquarian-metals/coin-moebius/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/aquarian-metals/coin-moebius.git",
23
+ "directory": "packages/providers/square"
24
+ },
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "sideEffects": false,
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./server": {
38
+ "types": "./dist/server.d.ts",
39
+ "import": "./dist/server.js"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "scripts": {
44
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
45
+ "build": "npm run clean && tsc",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "dependencies": {
52
+ "@aquarian-metals/coin-moebius-core": "^1.0.0"
53
+ },
54
+ "devDependencies": {
55
+ "typescript": "~5.8.0"
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ }
60
+ }