@happyvertical/payments 0.74.8
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/AGENT.md +33 -0
- package/LICENSE +7 -0
- package/README.md +97 -0
- package/dist/adapters/base-usdc.d.ts +85 -0
- package/dist/adapters/base-usdc.d.ts.map +1 -0
- package/dist/adapters/base-usdc.js +1182 -0
- package/dist/adapters/base-usdc.js.map +1 -0
- package/dist/adapters/btc.d.ts +63 -0
- package/dist/adapters/btc.d.ts.map +1 -0
- package/dist/adapters/btc.js +843 -0
- package/dist/adapters/btc.js.map +1 -0
- package/dist/adapters/stripe.d.ts +54 -0
- package/dist/adapters/stripe.d.ts.map +1 -0
- package/dist/adapters/stripe.js +696 -0
- package/dist/adapters/stripe.js.map +1 -0
- package/dist/chunks/errors-BgFC46qQ.js +45 -0
- package/dist/chunks/errors-BgFC46qQ.js.map +1 -0
- package/dist/chunks/shared-DGHSqDQT.js +392 -0
- package/dist/chunks/shared-DGHSqDQT.js.map +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/factory.d.ts +13 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/shared.d.ts +32 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/testing/conformance.d.ts +33 -0
- package/dist/testing/conformance.d.ts.map +1 -0
- package/dist/testing/conformance.js +114 -0
- package/dist/testing/conformance.js.map +1 -0
- package/dist/types.d.ts +174 -0
- package/dist/types.d.ts.map +1 -0
- package/metadata.json +30 -0
- package/package.json +88 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.js","sources":["../../src/adapters/stripe.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto';\nimport {\n PaymentConfigurationError,\n PaymentProviderError,\n PaymentVerificationError,\n} from '../errors.js';\nimport {\n applyExpiryToPendingStatus,\n type FetchLike,\n formEncode,\n getFetch,\n normalizeDate,\n normalizeMaxStoredPaymentOptions,\n normalizeMinorUnitAmount,\n normalizeNonEmptyString,\n normalizePositivePaymentAmount,\n normalizeUrlString,\n pollPaymentStatus,\n readJsonResponse,\n rememberPaymentOption,\n} from '../shared.js';\nimport type {\n CreatePaymentOptionInput,\n PaymentBackend,\n PaymentBackendCapabilities,\n PaymentEvent,\n PaymentOption,\n PaymentStatus,\n PaymentStatusContext,\n PaymentStatusResult,\n PaymentWebhookEvent,\n PayoutResult,\n RefundPaymentInput,\n RefundResult,\n SendPayoutInput,\n WatchPaymentInput,\n} from '../types.js';\n\nexport const STRIPE_BACKEND_ID = 'stripe';\nconst STRIPE_CHECKOUT_MIN_EXPIRY_MS = 30 * 60 * 1_000;\nconst STRIPE_CHECKOUT_MAX_EXPIRY_MS = 24 * 60 * 60 * 1_000;\nconst DEFAULT_STRIPE_API_VERSION = '2024-06-20';\nconst DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS = 50_000;\n\nexport interface StripeAdapterOptions {\n secretKey: string;\n fetch?: FetchLike;\n apiBaseUrl?: string;\n apiVersion?: string;\n defaultCurrency?: string;\n supportedCurrencies?: string[];\n successUrl?: string;\n cancelUrl?: string;\n checkoutMode?: string;\n webhookSecret?: string;\n pollIntervalMs?: number;\n maxStoredPaymentOptions?: number;\n maxStoredWebhookEventIds?: number;\n}\n\nexport interface StripeWebhookEvent extends PaymentWebhookEvent {\n id: string;\n type: string;\n status: PaymentStatus;\n quoteId?: string;\n providerPaymentId?: string;\n raw: unknown;\n}\n\nexport class StripeAdapter implements PaymentBackend {\n readonly capabilities: PaymentBackendCapabilities;\n\n private readonly fetch: FetchLike;\n private readonly secretKey: string;\n private readonly apiBaseUrl: string;\n private readonly apiVersion: string;\n private readonly defaultCurrency: string;\n private readonly supportedCurrencies: Set<string>;\n private readonly checkoutMode: string;\n private readonly webhookSecret: string | undefined;\n private readonly maxStoredPaymentOptions: number;\n private readonly maxStoredWebhookEventIds: number;\n private readonly optionsByQuote = new Map<string, PaymentOption>();\n private readonly seenWebhookEventIds = new Set<string>();\n\n constructor(private readonly options: StripeAdapterOptions) {\n if (typeof options.secretKey !== 'string' || !options.secretKey.trim()) {\n throw new PaymentConfigurationError('StripeAdapter requires secretKey.');\n }\n\n if (options.webhookSecret !== undefined) {\n if (typeof options.webhookSecret !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must be a string when configured.',\n );\n }\n\n if (!options.webhookSecret.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter webhookSecret must not be empty when configured.',\n );\n }\n }\n\n if (options.apiBaseUrl !== undefined) {\n if (typeof options.apiBaseUrl !== 'string') {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must be a string when configured.',\n );\n }\n\n if (!options.apiBaseUrl.trim()) {\n throw new PaymentConfigurationError(\n 'StripeAdapter apiBaseUrl must not be empty when configured.',\n );\n }\n }\n\n this.fetch = getFetch(options.fetch);\n this.maxStoredPaymentOptions = normalizeMaxStoredPaymentOptions(\n options.maxStoredPaymentOptions,\n 'StripeAdapter maxStoredPaymentOptions',\n );\n this.maxStoredWebhookEventIds = normalizeMaxStoredPaymentOptions(\n options.maxStoredWebhookEventIds ?? DEFAULT_MAX_STORED_WEBHOOK_EVENT_IDS,\n 'StripeAdapter maxStoredWebhookEventIds',\n );\n this.secretKey = options.secretKey.trim();\n this.apiBaseUrl = normalizeUrlString(\n options.apiBaseUrl ?? 'https://api.stripe.com/v1',\n 'StripeAdapter apiBaseUrl',\n ).replace(/\\/$/, '');\n this.apiVersion = normalizeNonEmptyString(\n options.apiVersion ?? DEFAULT_STRIPE_API_VERSION,\n 'StripeAdapter apiVersion',\n );\n this.defaultCurrency = normalizeStripeCurrency(\n options.defaultCurrency ?? 'usd',\n );\n this.supportedCurrencies = normalizeSupportedStripeCurrencies(\n options.supportedCurrencies,\n this.defaultCurrency,\n );\n this.checkoutMode = options.checkoutMode ?? 'payment';\n\n if (this.checkoutMode !== 'payment') {\n throw new PaymentConfigurationError(\n 'StripeAdapter only supports payment Checkout mode.',\n );\n }\n\n this.webhookSecret = options.webhookSecret?.trim();\n this.capabilities = {\n id: STRIPE_BACKEND_ID,\n displayName: 'Stripe Checkout',\n settlementCurrency: this.defaultCurrency.toUpperCase(),\n supportedSettlementCurrencies: [...this.supportedCurrencies].map(\n (currency) => currency.toUpperCase(),\n ),\n chain: 'stripe',\n settlementShape: 'url',\n x402Capable: false,\n confirmationLatency: {\n expectedSeconds: 5,\n maxExpectedSeconds: 600,\n description:\n 'Card payments usually confirm in seconds; bank debits can remain processing while Stripe settles them.',\n },\n supportsRefunds: true,\n supportsPayouts: true,\n supportsWebhooks: true,\n metadata: {\n provider: 'stripe',\n },\n };\n }\n\n async createPaymentOption(\n input: CreatePaymentOptionInput,\n ): Promise<PaymentOption> {\n const quoteId = normalizeNonEmptyString(input.quoteId, 'Stripe quoteId');\n const rawSuccessUrl = input.successUrl ?? this.options.successUrl;\n const rawCancelUrl = input.cancelUrl ?? this.options.cancelUrl;\n\n if (rawSuccessUrl === undefined || rawCancelUrl === undefined) {\n throw new PaymentConfigurationError(\n 'StripeAdapter createPaymentOption requires successUrl and cancelUrl.',\n );\n }\n\n const successUrl = normalizeUrlString(rawSuccessUrl, 'Stripe successUrl');\n const cancelUrl = normalizeUrlString(rawCancelUrl, 'Stripe cancelUrl');\n const currency = normalizeStripeCurrency(input.currency);\n this.assertSupportedCurrency(currency);\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe Checkout amount',\n );\n const expiresAt = normalizeDate(input.expiresAt);\n const stripeExpiresAt = normalizeStripeCheckoutExpiresAt(expiresAt);\n const params: Record<string, unknown> = {\n mode: this.checkoutMode,\n ...Object.fromEntries([\n ['success_url', successUrl],\n ['cancel_url', cancelUrl],\n ['client_reference_id', quoteId],\n ['customer_email', input.buyerEmail],\n ['expires_at', Math.floor(stripeExpiresAt.getTime() / 1_000)],\n ]),\n 'line_items[0][quantity]': 1,\n 'line_items[0][price_data][currency]': currency,\n 'line_items[0][price_data][unit_amount]': amount,\n 'line_items[0][price_data][product_data][name]':\n input.description ?? `Quote ${quoteId}`,\n ...flattenStripeMetadata(input.metadata),\n 'metadata[quoteId]': quoteId,\n };\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n '/checkout/sessions',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(params),\n },\n );\n const sessionId = normalizeOptionalProviderString(\n readProviderString(session, 'id'),\n );\n const checkoutUrl = normalizeOptionalProviderString(\n readProviderString(session, 'url'),\n );\n\n if (!sessionId || !checkoutUrl) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session response did not include id and url.',\n );\n }\n\n const option: PaymentOption = {\n backendId: this.capabilities.id,\n quoteId,\n payTo: checkoutUrl,\n settlementShape: 'url',\n settlementCurrency: currency.toUpperCase(),\n settlementAmount: amount,\n amount,\n currency: currency.toUpperCase(),\n expiresAt: stripeExpiresAt,\n providerPaymentId: sessionId,\n paymentUri: checkoutUrl,\n metadata: {\n sessionId,\n paymentIntent: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n },\n };\n\n rememberPaymentOption(\n this.optionsByQuote,\n quoteId,\n option,\n this.maxStoredPaymentOptions,\n );\n\n return option;\n }\n\n watchPayment(input: WatchPaymentInput): AsyncIterable<PaymentEvent> {\n return pollPaymentStatus(\n {\n ...input,\n pollIntervalMs:\n input.pollIntervalMs ?? this.options.pollIntervalMs ?? 5_000,\n },\n () => this.getStatus(input.quoteId, input.payTo, input.statusContext),\n );\n }\n\n async getStatus(\n quoteId: string,\n payTo: string,\n context: PaymentStatusContext = {},\n ): Promise<PaymentStatusResult> {\n const normalizedQuoteId = normalizeNonEmptyString(\n quoteId,\n 'Stripe quoteId',\n );\n const normalizedPayTo = normalizeNonEmptyString(payTo, 'Stripe payTo');\n const contextProviderPaymentId =\n context.providerPaymentId === undefined\n ? undefined\n : normalizeNonEmptyString(\n context.providerPaymentId,\n 'Stripe providerPaymentId',\n );\n const sessionId =\n this.optionsByQuote.get(normalizedQuoteId)?.providerPaymentId ??\n contextProviderPaymentId ??\n extractStripeSessionId(normalizedPayTo);\n\n if (!sessionId) {\n throw new PaymentConfigurationError(\n 'Stripe getStatus requires a Checkout Session id or URL.',\n );\n }\n\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(sessionId)}`,\n );\n const sessionQuoteId = readStripeSessionQuoteId(session);\n\n if (sessionQuoteId !== undefined && sessionQuoteId !== normalizedQuoteId) {\n throw new PaymentVerificationError(\n `Stripe Checkout Session quoteId ${sessionQuoteId} did not match ${normalizedQuoteId}.`,\n );\n }\n\n const paymentStatus = readString(session, 'payment_status');\n const status = mapStripeStatus(\n readString(session, 'status'),\n paymentStatus,\n );\n\n const option = this.optionsByQuote.get(normalizedQuoteId);\n const contextAmount =\n context.amount === undefined\n ? undefined\n : normalizeMinorUnitAmount(context.amount, 'Stripe status');\n const contextCurrency =\n context.currency === undefined\n ? undefined\n : normalizeStripeCurrency(context.currency).toUpperCase();\n const sessionCurrency =\n readString(session, 'currency') === undefined\n ? undefined\n : normalizeStripeCurrency(\n readString(session, 'currency') ?? '',\n ).toUpperCase();\n const sessionAmount = readSafeInteger(session, 'amount_total');\n const expiresAt =\n option?.expiresAt ??\n (context.expiresAt === undefined\n ? undefined\n : normalizeDate(context.expiresAt));\n const effectiveStatus = applyExpiryToPendingStatus(status, expiresAt);\n\n return {\n backendId: this.capabilities.id,\n quoteId: normalizedQuoteId,\n payTo: normalizedPayTo,\n status: effectiveStatus,\n settlementCurrency:\n sessionCurrency ??\n option?.settlementCurrency ??\n contextCurrency ??\n this.defaultCurrency.toUpperCase(),\n settlementAmount:\n sessionAmount ?? option?.settlementAmount ?? contextAmount,\n receivedAmount:\n paymentStatus === 'paid' || paymentStatus === 'no_payment_required'\n ? (sessionAmount ?? option?.settlementAmount ?? contextAmount)\n : undefined,\n amount: option?.amount ?? contextAmount,\n currency: option?.currency ?? contextCurrency,\n providerPaymentId: sessionId,\n transactionId: normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n ),\n updatedAt: new Date(),\n raw: session,\n };\n }\n\n async sendPayout(input: SendPayoutInput): Promise<PayoutResult> {\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const destination = normalizeNonEmptyString(\n input.destination,\n 'Stripe payout destination',\n );\n const quoteId =\n input.quoteId === undefined\n ? undefined\n : normalizeNonEmptyString(input.quoteId, 'Stripe payout quoteId');\n const amount = normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe payout amount',\n );\n const transfer = await this.stripeRequest<Record<string, unknown>>(\n '/transfers',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode({\n amount,\n currency,\n destination,\n description: input.memo,\n ...flattenStripeMetadata(input.metadata),\n ...(quoteId === undefined ? {} : { 'metadata[quoteId]': quoteId }),\n }),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: 'submitted',\n payoutId: normalizeOptionalProviderString(\n readProviderString(transfer, 'id'),\n ),\n destination,\n amount,\n currency: currency.toUpperCase(),\n raw: transfer,\n };\n }\n\n async refundPayment(input: RefundPaymentInput): Promise<RefundResult> {\n const rawPaymentReference = input.paymentId ?? input.transactionId;\n\n if (!rawPaymentReference) {\n throw new PaymentConfigurationError(\n 'Stripe refunds require paymentId or transactionId.',\n );\n }\n\n const paymentReference = normalizeNonEmptyString(\n rawPaymentReference,\n 'Stripe refund payment reference',\n );\n const currency = normalizeStripeCurrency(\n input.currency ?? this.defaultCurrency,\n );\n this.assertSupportedCurrency(currency);\n const amount =\n input.amount === undefined\n ? undefined\n : normalizePositivePaymentAmount(\n input.amount,\n currency,\n 'Stripe refund amount',\n );\n const refundReferenceParam =\n await this.resolveStripeRefundReferenceParam(paymentReference);\n const refundParams: Record<string, unknown> = {\n ...refundReferenceParam,\n amount: amount === undefined ? undefined : amount,\n reason: input.reason,\n ...flattenStripeMetadata(input.metadata),\n };\n\n const refund = await this.stripeRequest<Record<string, unknown>>(\n '/refunds',\n {\n method: 'POST',\n idempotencyKey: input.idempotencyKey,\n body: formEncode(refundParams),\n },\n );\n\n return {\n backendId: this.capabilities.id,\n status: mapStripeRefundStatus(readString(refund, 'status')),\n refundId: normalizeOptionalProviderString(\n readProviderString(refund, 'id'),\n ),\n transactionId: paymentReference,\n amount,\n currency: currency.toUpperCase(),\n raw: refund,\n };\n }\n\n parseWebhookEvent(payload: string, signature?: string): StripeWebhookEvent {\n if (!this.webhookSecret) {\n throw new PaymentConfigurationError(\n 'StripeAdapter parseWebhookEvent requires webhookSecret.',\n );\n }\n\n if (!signature) {\n throw new PaymentProviderError('Missing Stripe webhook signature.');\n }\n\n verifyStripeWebhookSignature(payload, signature, this.webhookSecret);\n\n const event = parseStripeWebhookPayload(payload);\n const id = readRequiredWebhookString(\n event,\n 'id',\n 'Stripe webhook event id',\n );\n const type = readRequiredWebhookString(\n event,\n 'type',\n 'Stripe webhook event type',\n );\n\n const duplicate = this.seenWebhookEventIds.has(id);\n\n if (!duplicate) {\n this.seenWebhookEventIds.add(id);\n while (this.seenWebhookEventIds.size > this.maxStoredWebhookEventIds) {\n const oldest = this.seenWebhookEventIds.values().next().value;\n\n if (oldest === undefined) {\n break;\n }\n\n this.seenWebhookEventIds.delete(oldest);\n }\n }\n\n const data = (\n event.data as { object?: Record<string, unknown> } | undefined\n )?.object;\n\n return {\n id,\n type,\n status: mapStripeWebhookStatus(type, data),\n quoteId: normalizeOptionalWebhookString(\n readString(data, 'client_reference_id') ??\n readString(\n (data?.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n ),\n providerPaymentId: normalizeOptionalWebhookString(readString(data, 'id')),\n duplicate,\n raw: event,\n };\n }\n\n private async stripeRequest<T>(\n path: string,\n init: RequestInit & { idempotencyKey?: string } = {},\n ): Promise<T> {\n const headers = new Headers(init.headers);\n headers.set('Authorization', `Bearer ${this.secretKey}`);\n headers.set('Content-Type', 'application/x-www-form-urlencoded');\n headers.set('Accept', 'application/json');\n headers.set('Stripe-Version', this.apiVersion);\n\n if (init.idempotencyKey !== undefined) {\n headers.set(\n 'Idempotency-Key',\n normalizeNonEmptyString(init.idempotencyKey, 'Stripe idempotencyKey'),\n );\n }\n\n const { idempotencyKey: _idempotencyKey, ...requestInit } = init;\n const response = await this.fetch(`${this.apiBaseUrl}${path}`, {\n ...requestInit,\n method: init.method ?? 'GET',\n headers,\n });\n\n return readJsonResponse<T>(response, `Stripe ${path}`);\n }\n\n private assertSupportedCurrency(currency: string): void {\n if (!this.supportedCurrencies.has(currency)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency ${currency.toUpperCase()} is not configured as supported.`,\n );\n }\n }\n\n private async resolveStripeRefundReferenceParam(\n paymentReference: string,\n ): Promise<Record<string, string>> {\n if (paymentReference.startsWith('cs_')) {\n const session = await this.stripeRequest<Record<string, unknown>>(\n `/checkout/sessions/${encodeURIComponent(paymentReference)}`,\n );\n const paymentIntent = normalizeOptionalProviderString(\n readProviderString(session, 'payment_intent'),\n );\n\n if (!paymentIntent) {\n throw new PaymentProviderError(\n 'Stripe Checkout Session did not include payment_intent for refund.',\n );\n }\n\n return Object.fromEntries([['payment_intent', paymentIntent]]);\n }\n\n return stripeRefundReferenceParam(paymentReference);\n }\n}\n\nfunction stripeRefundReferenceParam(\n paymentReference: string,\n): Record<string, string> {\n if (paymentReference.startsWith('pi_')) {\n return Object.fromEntries([['payment_intent', paymentReference]]);\n }\n\n if (paymentReference.startsWith('ch_')) {\n return { charge: paymentReference };\n }\n\n throw new PaymentConfigurationError(\n 'Stripe refunds require a Checkout Session (cs_), payment_intent (pi_), or charge (ch_) reference.',\n );\n}\n\nfunction normalizeStripeCurrency(value: string): string {\n if (typeof value !== 'string') {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (!/^[a-z]{3}$/.test(normalized)) {\n throw new PaymentConfigurationError(\n `StripeAdapter currency must be a three-letter ISO currency code, received ${String(value)}.`,\n );\n }\n\n return normalized;\n}\n\nfunction normalizeSupportedStripeCurrencies(\n configuredCurrencies: string[] | undefined,\n defaultCurrency: string,\n): Set<string> {\n const normalized = new Set(\n (configuredCurrencies ?? ['usd', 'eur', 'gbp', 'cad']).map(\n normalizeStripeCurrency,\n ),\n );\n normalized.add(defaultCurrency);\n\n return normalized;\n}\n\nfunction normalizeStripeCheckoutExpiresAt(\n expiresAt: Date,\n now = Date.now(),\n): Date {\n if (expiresAt.getTime() <= now) {\n throw new PaymentProviderError('Stripe Checkout expiry is in the past.');\n }\n\n const min = now + STRIPE_CHECKOUT_MIN_EXPIRY_MS;\n const max = now + STRIPE_CHECKOUT_MAX_EXPIRY_MS;\n\n if (expiresAt.getTime() < min || expiresAt.getTime() > max) {\n throw new PaymentConfigurationError(\n 'Stripe Checkout expiry must be at least 30 minutes and no more than 24 hours from now.',\n );\n }\n\n return expiresAt;\n}\n\nexport function verifyStripeWebhookSignature(\n payload: string,\n signatureHeader: string,\n secret: string,\n toleranceSeconds = 300,\n): void {\n if (typeof payload !== 'string') {\n throw new PaymentProviderError('Stripe webhook payload must be a string.');\n }\n\n const normalizedSignatureHeader = normalizeNonEmptyString(\n signatureHeader,\n 'Stripe signature header',\n );\n const normalizedSecret = normalizeNonEmptyString(\n secret,\n 'Stripe webhook secret',\n );\n\n if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) {\n throw new PaymentConfigurationError(\n `Stripe webhook toleranceSeconds must be a non-negative finite number, received ${String(toleranceSeconds)}.`,\n );\n }\n\n const timestampCandidates: string[] = [];\n const signatures: string[] = [];\n\n for (const part of normalizedSignatureHeader.split(',')) {\n const [rawKey, ...rawValue] = part.split('=');\n const key = rawKey?.trim();\n const value = rawValue.join('=').trim();\n\n if (!key || !value) {\n continue;\n }\n\n if (key === 't') {\n timestampCandidates.push(value);\n }\n\n if (key === 'v1') {\n signatures.push(value);\n }\n }\n\n if (timestampCandidates.length !== 1 || signatures.length === 0) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestamp = timestampCandidates[0] ?? '';\n\n if (!/^\\d+$/.test(timestamp)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const timestampSeconds = Number(timestamp);\n\n if (!Number.isSafeInteger(timestampSeconds)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const nowSeconds = Date.now() / 1_000;\n const ageSeconds = nowSeconds - timestampSeconds;\n\n if (ageSeconds < -5) {\n throw new PaymentProviderError(\n 'Stripe webhook signature timestamp is in the future.',\n );\n }\n\n if (ageSeconds > toleranceSeconds) {\n throw new PaymentProviderError('Stripe webhook signature is too old.');\n }\n\n const expected = createHmac('sha256', normalizedSecret)\n .update(`${timestamp}.${payload}`)\n .digest('hex');\n const expectedBuffer = Buffer.from(expected, 'hex');\n\n for (const signature of signatures) {\n if (!/^[0-9a-f]+$/i.test(signature)) {\n throw new PaymentProviderError('Invalid Stripe signature header.');\n }\n\n const actualBuffer = Buffer.from(signature, 'hex');\n\n if (\n expectedBuffer.length === actualBuffer.length &&\n timingSafeEqual(expectedBuffer, actualBuffer)\n ) {\n return;\n }\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook signature.');\n}\n\nfunction parseStripeWebhookPayload(payload: string): Record<string, unknown> {\n try {\n const event = JSON.parse(payload);\n\n if (!event || typeof event !== 'object' || Array.isArray(event)) {\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.');\n }\n\n return event as Record<string, unknown>;\n } catch (error) {\n if (error instanceof PaymentProviderError) {\n throw error;\n }\n\n throw new PaymentProviderError('Invalid Stripe webhook JSON payload.', {\n cause: error,\n });\n }\n}\n\nfunction normalizeOptionalWebhookString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction normalizeOptionalProviderString(\n value: string | undefined,\n): string | undefined {\n const normalized = value?.trim();\n\n return normalized ? normalized : undefined;\n}\n\nfunction readProviderString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'string' ? item : undefined;\n}\n\nfunction readRequiredWebhookString(\n value: Record<string, unknown>,\n key: string,\n context: string,\n): string {\n const item = value[key];\n\n if (typeof item !== 'string') {\n throw new PaymentProviderError(`${context} must be a string.`);\n }\n\n return normalizeNonEmptyString(item, context);\n}\n\nfunction readStripeSessionQuoteId(\n session: Record<string, unknown>,\n): string | undefined {\n return normalizeOptionalWebhookString(\n readString(session, 'client_reference_id') ??\n readString(\n (session.metadata as Record<string, unknown>) ?? {},\n 'quoteId',\n ),\n );\n}\n\nfunction mapStripeStatus(\n checkoutStatus: string | undefined,\n paymentStatus: string | undefined,\n): PaymentStatus {\n if (paymentStatus === 'paid' || paymentStatus === 'no_payment_required') {\n return 'confirmed';\n }\n\n if (checkoutStatus === 'expired') {\n return 'expired';\n }\n\n if (paymentStatus === 'unpaid' || checkoutStatus === 'open') {\n return 'pending';\n }\n\n if (checkoutStatus === 'complete') {\n return 'processing';\n }\n\n return 'pending';\n}\n\nfunction mapStripeWebhookStatus(\n type: string | undefined,\n object: Record<string, unknown> | undefined,\n): PaymentStatus {\n if (type === 'checkout.session.completed') {\n return mapStripeStatus(\n readString(object, 'status'),\n readString(object, 'payment_status'),\n );\n }\n\n if (type === 'checkout.session.async_payment_succeeded') {\n return 'confirmed';\n }\n\n if (type === 'checkout.session.async_payment_failed') {\n return 'failed';\n }\n\n if (type === 'checkout.session.expired') {\n return 'expired';\n }\n\n if (type?.includes('failed')) {\n return 'failed';\n }\n\n if (type?.includes('refunded')) {\n return 'refunded';\n }\n\n return 'processing';\n}\n\nfunction mapStripeRefundStatus(\n status: string | undefined,\n): RefundResult['status'] {\n switch (status) {\n case 'succeeded':\n return 'succeeded';\n case 'failed':\n case 'canceled':\n return 'failed';\n case 'requires_action':\n return 'requires_action';\n default:\n return 'submitted';\n }\n}\n\nfunction extractStripeSessionId(payTo: string): string | undefined {\n if (/^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(payTo)) {\n return payTo;\n }\n\n try {\n const url = new URL(payTo);\n const match = url.pathname.match(/\\/pay\\/([^/?#]+)/);\n\n const sessionId = match?.[1];\n\n return sessionId && /^cs_(test_|live_)?[A-Za-z0-9_]+$/.test(sessionId)\n ? sessionId\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction flattenStripeMetadata(\n metadata:\n | Record<string, string | number | boolean | null | undefined>\n | undefined,\n): Record<string, string | number | boolean> {\n const result: Record<string, string | number | boolean> = {};\n\n for (const [key, value] of Object.entries(metadata ?? {})) {\n if (value !== undefined && value !== null) {\n result[`metadata[${key}]`] = value;\n }\n }\n\n return result;\n}\n\nfunction readString(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n if (typeof item === 'string') {\n return item;\n }\n\n if (typeof item === 'number') {\n return String(item);\n }\n\n return undefined;\n}\n\nfunction readSafeInteger(\n value: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const item = value[key];\n\n return typeof item === 'number' && Number.isSafeInteger(item) && item >= 0\n ? item\n : undefined;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class PaymentError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
retryable;
|
|
4
|
+
constructor(message, code = "PAYMENT_PROVIDER_ERROR", options = {}) {
|
|
5
|
+
super(
|
|
6
|
+
message,
|
|
7
|
+
options.cause === void 0 ? void 0 : { cause: options.cause }
|
|
8
|
+
);
|
|
9
|
+
this.name = "PaymentError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.retryable = options.retryable ?? false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
class PaymentConfigurationError extends PaymentError {
|
|
15
|
+
constructor(message, options = {}) {
|
|
16
|
+
super(message, "PAYMENT_CONFIGURATION_ERROR", options);
|
|
17
|
+
this.name = "PaymentConfigurationError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class PaymentProviderError extends PaymentError {
|
|
21
|
+
constructor(message, options = {}) {
|
|
22
|
+
super(message, "PAYMENT_PROVIDER_ERROR", options);
|
|
23
|
+
this.name = "PaymentProviderError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
class PaymentUnsupportedError extends PaymentError {
|
|
27
|
+
constructor(message, options = {}) {
|
|
28
|
+
super(message, "PAYMENT_UNSUPPORTED", options);
|
|
29
|
+
this.name = "PaymentUnsupportedError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class PaymentVerificationError extends PaymentError {
|
|
33
|
+
constructor(message, options = {}) {
|
|
34
|
+
super(message, "PAYMENT_VERIFICATION_FAILED", options);
|
|
35
|
+
this.name = "PaymentVerificationError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
PaymentConfigurationError as P,
|
|
40
|
+
PaymentError as a,
|
|
41
|
+
PaymentProviderError as b,
|
|
42
|
+
PaymentUnsupportedError as c,
|
|
43
|
+
PaymentVerificationError as d
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=errors-BgFC46qQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-BgFC46qQ.js","sources":["../../src/errors.ts"],"sourcesContent":["export type PaymentErrorCode =\n | 'PAYMENT_CONFIGURATION_ERROR'\n | 'PAYMENT_PROVIDER_ERROR'\n | 'PAYMENT_UNSUPPORTED'\n | 'PAYMENT_VERIFICATION_FAILED'\n | 'PAYMENT_TIMEOUT'\n | 'PAYMENT_INVALID_INPUT';\n\nexport class PaymentError extends Error {\n readonly code: PaymentErrorCode;\n readonly retryable: boolean;\n\n constructor(\n message: string,\n code: PaymentErrorCode = 'PAYMENT_PROVIDER_ERROR',\n options: { cause?: unknown; retryable?: boolean } = {},\n ) {\n super(\n message,\n options.cause === undefined ? undefined : { cause: options.cause },\n );\n this.name = 'PaymentError';\n this.code = code;\n this.retryable = options.retryable ?? false;\n }\n}\n\nexport class PaymentConfigurationError extends PaymentError {\n constructor(message: string, options: { cause?: unknown } = {}) {\n super(message, 'PAYMENT_CONFIGURATION_ERROR', options);\n this.name = 'PaymentConfigurationError';\n }\n}\n\nexport class PaymentProviderError extends PaymentError {\n constructor(\n message: string,\n options: { cause?: unknown; retryable?: boolean } = {},\n ) {\n super(message, 'PAYMENT_PROVIDER_ERROR', options);\n this.name = 'PaymentProviderError';\n }\n}\n\nexport class PaymentUnsupportedError extends PaymentError {\n constructor(message: string, options: { cause?: unknown } = {}) {\n super(message, 'PAYMENT_UNSUPPORTED', options);\n this.name = 'PaymentUnsupportedError';\n }\n}\n\nexport class PaymentVerificationError extends PaymentError {\n constructor(message: string, options: { cause?: unknown } = {}) {\n super(message, 'PAYMENT_VERIFICATION_FAILED', options);\n this.name = 'PaymentVerificationError';\n }\n}\n"],"names":[],"mappings":"AAQO,MAAM,qBAAqB,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EAET,YACE,SACA,OAAyB,0BACzB,UAAoD,CAAA,GACpD;AACA;AAAA,MACE;AAAA,MACA,QAAQ,UAAU,SAAY,SAAY,EAAE,OAAO,QAAQ,MAAA;AAAA,IAAM;AAEnE,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,YAAY,QAAQ,aAAa;AAAA,EACxC;AACF;AAEO,MAAM,kCAAkC,aAAa;AAAA,EAC1D,YAAY,SAAiB,UAA+B,IAAI;AAC9D,UAAM,SAAS,+BAA+B,OAAO;AACrD,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,6BAA6B,aAAa;AAAA,EACrD,YACE,SACA,UAAoD,IACpD;AACA,UAAM,SAAS,0BAA0B,OAAO;AAChD,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,gCAAgC,aAAa;AAAA,EACxD,YAAY,SAAiB,UAA+B,IAAI;AAC9D,UAAM,SAAS,uBAAuB,OAAO;AAC7C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,iCAAiC,aAAa;AAAA,EACzD,YAAY,SAAiB,UAA+B,IAAI;AAC9D,UAAM,SAAS,+BAA+B,OAAO;AACrD,SAAK,OAAO;AAAA,EACd;AACF;"}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { b as PaymentProviderError, P as PaymentConfigurationError } from "./errors-BgFC46qQ.js";
|
|
2
|
+
const TERMINAL_PAYMENT_STATUSES = /* @__PURE__ */ new Set([
|
|
3
|
+
"confirmed",
|
|
4
|
+
"failed",
|
|
5
|
+
"expired",
|
|
6
|
+
"refunded"
|
|
7
|
+
]);
|
|
8
|
+
const DEFAULT_MAX_STORED_PAYMENT_OPTIONS = 1e3;
|
|
9
|
+
const MAX_DECIMAL_PRECISION = 100;
|
|
10
|
+
const ZERO_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
|
|
11
|
+
"BIF",
|
|
12
|
+
"CLP",
|
|
13
|
+
"DJF",
|
|
14
|
+
"GNF",
|
|
15
|
+
"JPY",
|
|
16
|
+
"KMF",
|
|
17
|
+
"KRW",
|
|
18
|
+
"MGA",
|
|
19
|
+
"PYG",
|
|
20
|
+
"RWF",
|
|
21
|
+
"VND",
|
|
22
|
+
"VUV",
|
|
23
|
+
"XAF",
|
|
24
|
+
"XOF",
|
|
25
|
+
"XPF"
|
|
26
|
+
]);
|
|
27
|
+
const THREE_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
|
|
28
|
+
"BHD",
|
|
29
|
+
"IQD",
|
|
30
|
+
"JOD",
|
|
31
|
+
"KWD",
|
|
32
|
+
"LYD",
|
|
33
|
+
"OMR",
|
|
34
|
+
"TND"
|
|
35
|
+
]);
|
|
36
|
+
const TWO_DECIMAL_WHOLE_UNIT_CURRENCIES = /* @__PURE__ */ new Set(["ISK", "UGX"]);
|
|
37
|
+
function getFetch(fetchLike) {
|
|
38
|
+
const resolved = fetchLike ?? globalThis.fetch;
|
|
39
|
+
if (!resolved) {
|
|
40
|
+
throw new PaymentProviderError(
|
|
41
|
+
"A fetch implementation is required in this runtime."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (typeof resolved !== "function") {
|
|
45
|
+
throw new PaymentProviderError("Fetch implementation must be a function.");
|
|
46
|
+
}
|
|
47
|
+
return resolved.bind(globalThis);
|
|
48
|
+
}
|
|
49
|
+
function normalizeDate(value) {
|
|
50
|
+
if (!(value instanceof Date) && typeof value !== "string") {
|
|
51
|
+
throw new PaymentProviderError(`Invalid date value: ${String(value)}`);
|
|
52
|
+
}
|
|
53
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
54
|
+
if (Number.isNaN(date.getTime())) {
|
|
55
|
+
throw new PaymentProviderError(`Invalid date value: ${String(value)}`);
|
|
56
|
+
}
|
|
57
|
+
return date;
|
|
58
|
+
}
|
|
59
|
+
function normalizeFutureDate(value, context) {
|
|
60
|
+
const date = normalizeDate(value);
|
|
61
|
+
if (date.getTime() <= Date.now()) {
|
|
62
|
+
throw new PaymentProviderError(`${context} is in the past.`);
|
|
63
|
+
}
|
|
64
|
+
return date;
|
|
65
|
+
}
|
|
66
|
+
function normalizeAmount(value) {
|
|
67
|
+
if (typeof value !== "string") {
|
|
68
|
+
throw new PaymentProviderError("Monetary amounts must be decimal strings.");
|
|
69
|
+
}
|
|
70
|
+
const raw = value.trim();
|
|
71
|
+
if (!/^\d+(\.\d+)?$/.test(raw)) {
|
|
72
|
+
throw new PaymentProviderError(`Invalid amount value: ${String(value)}`);
|
|
73
|
+
}
|
|
74
|
+
const [whole, fraction] = raw.split(".");
|
|
75
|
+
const normalizedWhole = whole.replace(/^0+(?=\d)/, "") || "0";
|
|
76
|
+
const normalizedFraction = fraction?.replace(/0+$/, "");
|
|
77
|
+
return normalizedFraction ? `${normalizedWhole}.${normalizedFraction}` : normalizedWhole;
|
|
78
|
+
}
|
|
79
|
+
function normalizeCurrency(value, context) {
|
|
80
|
+
if (typeof value !== "string") {
|
|
81
|
+
throw new PaymentProviderError(`${context} currency must be a string.`);
|
|
82
|
+
}
|
|
83
|
+
const normalized = value.trim().toUpperCase();
|
|
84
|
+
if (!/^[A-Z0-9]{3,10}$/.test(normalized)) {
|
|
85
|
+
throw new PaymentProviderError(
|
|
86
|
+
`${context} currency must be a currency code, received ${String(value)}.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return normalized;
|
|
90
|
+
}
|
|
91
|
+
function normalizeMinorUnitAmount(value, context) {
|
|
92
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
93
|
+
throw new PaymentProviderError(
|
|
94
|
+
`${context} must be a non-negative integer in the smallest currency unit, received ${String(value)}.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
function normalizePositiveMinorUnitAmount(value, context) {
|
|
100
|
+
const amount = normalizeMinorUnitAmount(value, context);
|
|
101
|
+
if (amount === 0) {
|
|
102
|
+
throw new PaymentProviderError(`${context} must be greater than zero.`);
|
|
103
|
+
}
|
|
104
|
+
return amount;
|
|
105
|
+
}
|
|
106
|
+
function normalizePositivePaymentAmount(value, currency, context) {
|
|
107
|
+
const amount = normalizePositiveMinorUnitAmount(value, context);
|
|
108
|
+
const normalizedCurrency = normalizeCurrency(currency, context);
|
|
109
|
+
if (TWO_DECIMAL_WHOLE_UNIT_CURRENCIES.has(normalizedCurrency) && amount % 100 !== 0) {
|
|
110
|
+
throw new PaymentProviderError(
|
|
111
|
+
`${context} for ${normalizedCurrency} must be evenly divisible by 100.`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return amount;
|
|
115
|
+
}
|
|
116
|
+
function normalizeMaxStoredPaymentOptions(value, context) {
|
|
117
|
+
if (value === void 0) {
|
|
118
|
+
return DEFAULT_MAX_STORED_PAYMENT_OPTIONS;
|
|
119
|
+
}
|
|
120
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
121
|
+
throw new PaymentConfigurationError(
|
|
122
|
+
`${context} must be a positive safe integer.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
function rememberPaymentOption(optionsByQuote, quoteId, option, maxStoredPaymentOptions) {
|
|
128
|
+
optionsByQuote.delete(quoteId);
|
|
129
|
+
optionsByQuote.set(quoteId, option);
|
|
130
|
+
while (optionsByQuote.size > maxStoredPaymentOptions) {
|
|
131
|
+
const oldestQuoteId = optionsByQuote.keys().next().value;
|
|
132
|
+
if (oldestQuoteId === void 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
optionsByQuote.delete(oldestQuoteId);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function normalizeNonEmptyString(value, context) {
|
|
139
|
+
if (typeof value !== "string") {
|
|
140
|
+
throw new PaymentProviderError(`${context} must be a string.`);
|
|
141
|
+
}
|
|
142
|
+
const normalized = value.trim();
|
|
143
|
+
if (!normalized) {
|
|
144
|
+
throw new PaymentProviderError(`${context} must not be empty.`);
|
|
145
|
+
}
|
|
146
|
+
return normalized;
|
|
147
|
+
}
|
|
148
|
+
function normalizeUrlString(value, context) {
|
|
149
|
+
const normalized = normalizeNonEmptyString(value, context);
|
|
150
|
+
try {
|
|
151
|
+
const url = new URL(normalized);
|
|
152
|
+
if (!["http:", "https:"].includes(url.protocol)) {
|
|
153
|
+
throw new PaymentConfigurationError(`${context} must use http or https.`);
|
|
154
|
+
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error instanceof PaymentConfigurationError) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
throw new PaymentConfigurationError(`${context} must be a valid URL.`, {
|
|
160
|
+
cause: error
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return normalized;
|
|
164
|
+
}
|
|
165
|
+
function decimalToAtomicUnits(value, decimals) {
|
|
166
|
+
const precision = normalizeDecimalPrecision(decimals);
|
|
167
|
+
const normalized = normalizeAmount(value);
|
|
168
|
+
const [whole, fraction = ""] = normalized.split(".");
|
|
169
|
+
if (fraction.length > precision) {
|
|
170
|
+
throw new PaymentProviderError(
|
|
171
|
+
`Amount ${String(value)} has more than ${precision} decimal places.`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const padded = `${fraction}${"0".repeat(precision)}`.slice(0, precision);
|
|
175
|
+
const combined = `${whole}${padded}`.replace(/^0+(?=\d)/, "");
|
|
176
|
+
return combined || "0";
|
|
177
|
+
}
|
|
178
|
+
function atomicUnitsToDecimal(value, decimals) {
|
|
179
|
+
const precision = normalizeDecimalPrecision(decimals);
|
|
180
|
+
if (typeof value !== "string" && typeof value !== "bigint") {
|
|
181
|
+
throw new PaymentProviderError(
|
|
182
|
+
`Invalid atomic amount value: ${String(value)}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const raw = typeof value === "bigint" ? value.toString() : value;
|
|
186
|
+
if (!/^\d+$/.test(raw)) {
|
|
187
|
+
throw new PaymentProviderError(
|
|
188
|
+
`Invalid atomic amount value: ${String(value)}`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (precision === 0) {
|
|
192
|
+
return raw || "0";
|
|
193
|
+
}
|
|
194
|
+
const padded = raw.padStart(precision + 1, "0");
|
|
195
|
+
const whole = padded.slice(0, -precision);
|
|
196
|
+
const fraction = padded.slice(-precision).replace(/0+$/, "");
|
|
197
|
+
return fraction ? `${whole}.${fraction}` : whole;
|
|
198
|
+
}
|
|
199
|
+
function minorUnitsToDecimal(value, decimals) {
|
|
200
|
+
return atomicUnitsToDecimal(
|
|
201
|
+
BigInt(normalizeMinorUnitAmount(value, "Minor-unit")),
|
|
202
|
+
decimals
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
function decimalToMinorUnitAmount(value, decimals, context) {
|
|
206
|
+
const atomic = typeof value === "bigint" ? value : BigInt(decimalToAtomicUnits(value, decimals));
|
|
207
|
+
if (atomic < 0n) {
|
|
208
|
+
throw new PaymentProviderError(
|
|
209
|
+
`Invalid atomic amount value: ${String(value)}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
if (atomic > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
213
|
+
throw new PaymentProviderError(
|
|
214
|
+
`${context} amount exceeds JavaScript's safe integer range.`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return Number(atomic);
|
|
218
|
+
}
|
|
219
|
+
function currencyMinorUnitDecimals(currency) {
|
|
220
|
+
const normalized = normalizeCurrency(currency, "Payment");
|
|
221
|
+
if (normalized === "BTC") {
|
|
222
|
+
return 8;
|
|
223
|
+
}
|
|
224
|
+
if (normalized === "USDC") {
|
|
225
|
+
return 6;
|
|
226
|
+
}
|
|
227
|
+
if (THREE_DECIMAL_CURRENCIES.has(normalized)) {
|
|
228
|
+
return 3;
|
|
229
|
+
}
|
|
230
|
+
return ZERO_DECIMAL_CURRENCIES.has(normalized) ? 0 : 2;
|
|
231
|
+
}
|
|
232
|
+
function applyExpiryToPendingStatus(status, expiresAt) {
|
|
233
|
+
if (!expiresAt || expiresAt >= /* @__PURE__ */ new Date()) {
|
|
234
|
+
return status;
|
|
235
|
+
}
|
|
236
|
+
return status === "pending" || status === "requires_action" ? "expired" : status;
|
|
237
|
+
}
|
|
238
|
+
function normalizeDecimalPrecision(decimals) {
|
|
239
|
+
if (!Number.isSafeInteger(decimals) || decimals < 0 || decimals > MAX_DECIMAL_PRECISION) {
|
|
240
|
+
throw new PaymentProviderError(
|
|
241
|
+
`Invalid decimal precision: ${String(decimals)}`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
return decimals;
|
|
245
|
+
}
|
|
246
|
+
function sleep(ms, signal) {
|
|
247
|
+
if (signal?.aborted) {
|
|
248
|
+
return Promise.reject(signal.reason);
|
|
249
|
+
}
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
let timeout;
|
|
252
|
+
const handleAbort = () => {
|
|
253
|
+
clearTimeout(timeout);
|
|
254
|
+
reject(signal?.reason);
|
|
255
|
+
};
|
|
256
|
+
const handleResolve = () => {
|
|
257
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
258
|
+
resolve();
|
|
259
|
+
};
|
|
260
|
+
timeout = setTimeout(handleResolve, ms);
|
|
261
|
+
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function* pollPaymentStatus(input, getStatus) {
|
|
265
|
+
const startedAt = Date.now();
|
|
266
|
+
const pollIntervalMs = normalizePollIntervalMs(input.pollIntervalMs ?? 5e3);
|
|
267
|
+
const timeoutMs = input.timeoutMs === void 0 ? void 0 : normalizeTimeoutMs(input.timeoutMs);
|
|
268
|
+
let lastStatus;
|
|
269
|
+
let lastResult;
|
|
270
|
+
const remainingTimeoutMs = () => timeoutMs === void 0 ? void 0 : timeoutMs - (Date.now() - startedAt);
|
|
271
|
+
const yieldTimeoutEvent = async () => ({
|
|
272
|
+
...lastResult ?? await getStatus(),
|
|
273
|
+
event: "timeout",
|
|
274
|
+
status: lastResult?.status ?? "pending",
|
|
275
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
276
|
+
});
|
|
277
|
+
while (!input.signal?.aborted) {
|
|
278
|
+
if ((remainingTimeoutMs() ?? 1) <= 0) {
|
|
279
|
+
yield await yieldTimeoutEvent();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const status = await getStatus();
|
|
283
|
+
lastResult = status;
|
|
284
|
+
if (status.status !== lastStatus) {
|
|
285
|
+
const event = toPaymentEvent(status);
|
|
286
|
+
yield event;
|
|
287
|
+
lastStatus = status.status;
|
|
288
|
+
if (TERMINAL_PAYMENT_STATUSES.has(status.status)) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const remaining = remainingTimeoutMs();
|
|
293
|
+
if (remaining !== void 0 && remaining <= 0) {
|
|
294
|
+
yield await yieldTimeoutEvent();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
await sleep(
|
|
298
|
+
remaining === void 0 ? pollIntervalMs : Math.min(pollIntervalMs, remaining),
|
|
299
|
+
input.signal
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function normalizePollIntervalMs(value) {
|
|
304
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
305
|
+
throw new PaymentProviderError(
|
|
306
|
+
`pollIntervalMs must be a positive integer, received ${String(value)}.`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
return value;
|
|
310
|
+
}
|
|
311
|
+
function normalizeTimeoutMs(value) {
|
|
312
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
313
|
+
throw new PaymentProviderError(
|
|
314
|
+
`timeoutMs must be a non-negative integer, received ${String(value)}.`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return value;
|
|
318
|
+
}
|
|
319
|
+
function toPaymentEvent(status) {
|
|
320
|
+
if (status.status === "confirmed") {
|
|
321
|
+
return { ...status, event: "confirmed" };
|
|
322
|
+
}
|
|
323
|
+
if (status.status === "failed") {
|
|
324
|
+
return { ...status, event: "failed" };
|
|
325
|
+
}
|
|
326
|
+
if (status.status === "expired") {
|
|
327
|
+
return { ...status, event: "expired" };
|
|
328
|
+
}
|
|
329
|
+
if (status.status === "refunded") {
|
|
330
|
+
return { ...status, event: "refunded" };
|
|
331
|
+
}
|
|
332
|
+
return { ...status, event: "status" };
|
|
333
|
+
}
|
|
334
|
+
async function readJsonResponse(response, context) {
|
|
335
|
+
const text = await response.text();
|
|
336
|
+
let body;
|
|
337
|
+
if (text) {
|
|
338
|
+
try {
|
|
339
|
+
body = JSON.parse(text);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (response.ok) {
|
|
342
|
+
throw new PaymentProviderError(`${context}: invalid JSON response`, {
|
|
343
|
+
cause: error
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
body = void 0;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!response.ok) {
|
|
350
|
+
const message = body && typeof body === "object" && "message" in body ? String(body.message) : body && typeof body === "object" && typeof body.error === "string" ? String(body.error) : body && typeof body === "object" && "error" in body && typeof body.error?.message === "string" ? body.error.message : text || response.statusText;
|
|
351
|
+
throw new PaymentProviderError(`${context}: ${message}`, {
|
|
352
|
+
retryable: response.status >= 500
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (body === void 0) {
|
|
356
|
+
throw new PaymentProviderError(`${context}: empty response body`);
|
|
357
|
+
}
|
|
358
|
+
return body;
|
|
359
|
+
}
|
|
360
|
+
function formEncode(params) {
|
|
361
|
+
const searchParams = new URLSearchParams();
|
|
362
|
+
for (const [key, value] of Object.entries(params)) {
|
|
363
|
+
if (value === void 0 || value === null) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
searchParams.set(key, String(value));
|
|
367
|
+
}
|
|
368
|
+
return searchParams.toString();
|
|
369
|
+
}
|
|
370
|
+
export {
|
|
371
|
+
normalizeMaxStoredPaymentOptions as a,
|
|
372
|
+
normalizeUrlString as b,
|
|
373
|
+
normalizeFutureDate as c,
|
|
374
|
+
normalizeCurrency as d,
|
|
375
|
+
normalizePositiveMinorUnitAmount as e,
|
|
376
|
+
decimalToMinorUnitAmount as f,
|
|
377
|
+
getFetch as g,
|
|
378
|
+
normalizeDate as h,
|
|
379
|
+
normalizeMinorUnitAmount as i,
|
|
380
|
+
readJsonResponse as j,
|
|
381
|
+
currencyMinorUnitDecimals as k,
|
|
382
|
+
decimalToAtomicUnits as l,
|
|
383
|
+
minorUnitsToDecimal as m,
|
|
384
|
+
normalizeNonEmptyString as n,
|
|
385
|
+
normalizePositivePaymentAmount as o,
|
|
386
|
+
pollPaymentStatus as p,
|
|
387
|
+
normalizeAmount as q,
|
|
388
|
+
rememberPaymentOption as r,
|
|
389
|
+
applyExpiryToPendingStatus as s,
|
|
390
|
+
formEncode as t
|
|
391
|
+
};
|
|
392
|
+
//# sourceMappingURL=shared-DGHSqDQT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-DGHSqDQT.js","sources":["../../src/shared.ts"],"sourcesContent":["import {\n PaymentConfigurationError,\n PaymentProviderError,\n PaymentUnsupportedError,\n} from './errors.js';\nimport type {\n PaymentEvent,\n PaymentStatus,\n PaymentStatusResult,\n WatchPaymentInput,\n} from './types.js';\n\nexport type FetchLike = (\n input: string | URL | Request,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport const TERMINAL_PAYMENT_STATUSES = new Set<PaymentStatus>([\n 'confirmed',\n 'failed',\n 'expired',\n 'refunded',\n]);\nexport const DEFAULT_MAX_STORED_PAYMENT_OPTIONS = 1_000;\nconst MAX_DECIMAL_PRECISION = 100;\nconst ZERO_DECIMAL_CURRENCIES = new Set([\n 'BIF',\n 'CLP',\n 'DJF',\n 'GNF',\n 'JPY',\n 'KMF',\n 'KRW',\n 'MGA',\n 'PYG',\n 'RWF',\n 'VND',\n 'VUV',\n 'XAF',\n 'XOF',\n 'XPF',\n]);\nconst THREE_DECIMAL_CURRENCIES = new Set([\n 'BHD',\n 'IQD',\n 'JOD',\n 'KWD',\n 'LYD',\n 'OMR',\n 'TND',\n]);\nconst TWO_DECIMAL_WHOLE_UNIT_CURRENCIES = new Set(['ISK', 'UGX']);\n\nexport function getFetch(fetchLike?: FetchLike): FetchLike {\n const resolved = fetchLike ?? globalThis.fetch;\n\n if (!resolved) {\n throw new PaymentProviderError(\n 'A fetch implementation is required in this runtime.',\n );\n }\n\n if (typeof resolved !== 'function') {\n throw new PaymentProviderError('Fetch implementation must be a function.');\n }\n\n return resolved.bind(globalThis) as FetchLike;\n}\n\nexport function normalizeDate(value: Date | string): Date {\n if (!(value instanceof Date) && typeof value !== 'string') {\n throw new PaymentProviderError(`Invalid date value: ${String(value)}`);\n }\n\n const date = value instanceof Date ? value : new Date(value);\n\n if (Number.isNaN(date.getTime())) {\n throw new PaymentProviderError(`Invalid date value: ${String(value)}`);\n }\n\n return date;\n}\n\nexport function normalizeFutureDate(\n value: Date | string,\n context: string,\n): Date {\n const date = normalizeDate(value);\n\n if (date.getTime() <= Date.now()) {\n throw new PaymentProviderError(`${context} is in the past.`);\n }\n\n return date;\n}\n\nexport function normalizeAmount(value: string): string {\n if (typeof value !== 'string') {\n throw new PaymentProviderError('Monetary amounts must be decimal strings.');\n }\n\n const raw = value.trim();\n\n if (!/^\\d+(\\.\\d+)?$/.test(raw)) {\n throw new PaymentProviderError(`Invalid amount value: ${String(value)}`);\n }\n\n const [whole, fraction] = raw.split('.');\n const normalizedWhole = whole.replace(/^0+(?=\\d)/, '') || '0';\n const normalizedFraction = fraction?.replace(/0+$/, '');\n\n return normalizedFraction\n ? `${normalizedWhole}.${normalizedFraction}`\n : normalizedWhole;\n}\n\nexport function normalizePositiveAmount(\n value: string,\n context: string,\n): string {\n const amount = normalizeAmount(value);\n\n if (amount === '0') {\n throw new PaymentProviderError(`${context} must be greater than zero.`);\n }\n\n return amount;\n}\n\nexport function normalizeCurrency(value: string, context: string): string {\n if (typeof value !== 'string') {\n throw new PaymentProviderError(`${context} currency must be a string.`);\n }\n\n const normalized = value.trim().toUpperCase();\n\n if (!/^[A-Z0-9]{3,10}$/.test(normalized)) {\n throw new PaymentProviderError(\n `${context} currency must be a currency code, received ${String(value)}.`,\n );\n }\n\n return normalized;\n}\n\nexport function normalizeMinorUnitAmount(\n value: number,\n context: string,\n): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n throw new PaymentProviderError(\n `${context} must be a non-negative integer in the smallest currency unit, received ${String(value)}.`,\n );\n }\n\n return value;\n}\n\nexport function normalizePositiveMinorUnitAmount(\n value: number,\n context: string,\n): number {\n const amount = normalizeMinorUnitAmount(value, context);\n\n if (amount === 0) {\n throw new PaymentProviderError(`${context} must be greater than zero.`);\n }\n\n return amount;\n}\n\nexport function normalizePositivePaymentAmount(\n value: number,\n currency: string,\n context: string,\n): number {\n const amount = normalizePositiveMinorUnitAmount(value, context);\n const normalizedCurrency = normalizeCurrency(currency, context);\n\n if (\n TWO_DECIMAL_WHOLE_UNIT_CURRENCIES.has(normalizedCurrency) &&\n amount % 100 !== 0\n ) {\n throw new PaymentProviderError(\n `${context} for ${normalizedCurrency} must be evenly divisible by 100.`,\n );\n }\n\n return amount;\n}\n\nexport function normalizeMaxStoredPaymentOptions(\n value: number | undefined,\n context: string,\n): number {\n if (value === undefined) {\n return DEFAULT_MAX_STORED_PAYMENT_OPTIONS;\n }\n\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new PaymentConfigurationError(\n `${context} must be a positive safe integer.`,\n );\n }\n\n return value;\n}\n\nexport function rememberPaymentOption<TOption>(\n optionsByQuote: Map<string, TOption>,\n quoteId: string,\n option: TOption,\n maxStoredPaymentOptions: number,\n): void {\n optionsByQuote.delete(quoteId);\n optionsByQuote.set(quoteId, option);\n\n while (optionsByQuote.size > maxStoredPaymentOptions) {\n const oldestQuoteId = optionsByQuote.keys().next().value;\n\n if (oldestQuoteId === undefined) {\n return;\n }\n\n optionsByQuote.delete(oldestQuoteId);\n }\n}\n\nexport function normalizeNonEmptyString(\n value: string,\n context: string,\n): string {\n if (typeof value !== 'string') {\n throw new PaymentProviderError(`${context} must be a string.`);\n }\n\n const normalized = value.trim();\n\n if (!normalized) {\n throw new PaymentProviderError(`${context} must not be empty.`);\n }\n\n return normalized;\n}\n\nexport function normalizeUrlString(value: string, context: string): string {\n const normalized = normalizeNonEmptyString(value, context);\n\n try {\n const url = new URL(normalized);\n\n if (!['http:', 'https:'].includes(url.protocol)) {\n throw new PaymentConfigurationError(`${context} must use http or https.`);\n }\n } catch (error) {\n if (error instanceof PaymentConfigurationError) {\n throw error;\n }\n\n throw new PaymentConfigurationError(`${context} must be a valid URL.`, {\n cause: error,\n });\n }\n\n return normalized;\n}\n\nexport function decimalToAtomicUnits(value: string, decimals: number): string {\n const precision = normalizeDecimalPrecision(decimals);\n\n const normalized = normalizeAmount(value);\n const [whole, fraction = ''] = normalized.split('.');\n\n if (fraction.length > precision) {\n throw new PaymentProviderError(\n `Amount ${String(value)} has more than ${precision} decimal places.`,\n );\n }\n\n const padded = `${fraction}${'0'.repeat(precision)}`.slice(0, precision);\n const combined = `${whole}${padded}`.replace(/^0+(?=\\d)/, '');\n\n return combined || '0';\n}\n\nexport function atomicUnitsToDecimal(\n value: string | bigint,\n decimals: number,\n): string {\n const precision = normalizeDecimalPrecision(decimals);\n\n if (typeof value !== 'string' && typeof value !== 'bigint') {\n throw new PaymentProviderError(\n `Invalid atomic amount value: ${String(value)}`,\n );\n }\n\n const raw = typeof value === 'bigint' ? value.toString() : value;\n\n if (!/^\\d+$/.test(raw)) {\n throw new PaymentProviderError(\n `Invalid atomic amount value: ${String(value)}`,\n );\n }\n\n if (precision === 0) {\n return raw || '0';\n }\n\n const padded = raw.padStart(precision + 1, '0');\n const whole = padded.slice(0, -precision);\n const fraction = padded.slice(-precision).replace(/0+$/, '');\n\n return fraction ? `${whole}.${fraction}` : whole;\n}\n\nexport function amountToMinorUnits(value: string, decimals = 2): string {\n return decimalToAtomicUnits(value, decimals);\n}\n\nexport function minorUnitsToDecimal(value: number, decimals: number): string {\n return atomicUnitsToDecimal(\n BigInt(normalizeMinorUnitAmount(value, 'Minor-unit')),\n decimals,\n );\n}\n\nexport function decimalToMinorUnitAmount(\n value: string | bigint,\n decimals: number,\n context: string,\n): number {\n const atomic =\n typeof value === 'bigint'\n ? value\n : BigInt(decimalToAtomicUnits(value, decimals));\n\n if (atomic < 0n) {\n throw new PaymentProviderError(\n `Invalid atomic amount value: ${String(value)}`,\n );\n }\n\n if (atomic > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new PaymentProviderError(\n `${context} amount exceeds JavaScript's safe integer range.`,\n );\n }\n\n return Number(atomic);\n}\n\nexport function currencyMinorUnitDecimals(currency: string): number {\n const normalized = normalizeCurrency(currency, 'Payment');\n\n if (normalized === 'BTC') {\n return 8;\n }\n\n if (normalized === 'USDC') {\n return 6;\n }\n\n if (THREE_DECIMAL_CURRENCIES.has(normalized)) {\n return 3;\n }\n\n return ZERO_DECIMAL_CURRENCIES.has(normalized) ? 0 : 2;\n}\n\nexport function applyExpiryToPendingStatus(\n status: PaymentStatus,\n expiresAt?: Date,\n): PaymentStatus {\n if (!expiresAt || expiresAt >= new Date()) {\n return status;\n }\n\n return status === 'pending' || status === 'requires_action'\n ? 'expired'\n : status;\n}\n\nfunction normalizeDecimalPrecision(decimals: number): number {\n if (\n !Number.isSafeInteger(decimals) ||\n decimals < 0 ||\n decimals > MAX_DECIMAL_PRECISION\n ) {\n throw new PaymentProviderError(\n `Invalid decimal precision: ${String(decimals)}`,\n );\n }\n\n return decimals;\n}\n\nexport function compareDecimalAmounts(left: string, right: string): -1 | 0 | 1 {\n const [leftWhole, leftFraction = ''] = normalizeAmount(left).split('.');\n const [rightWhole, rightFraction = ''] = normalizeAmount(right).split('.');\n const leftWholeValue = BigInt(leftWhole ?? '0');\n const rightWholeValue = BigInt(rightWhole ?? '0');\n\n if (leftWholeValue > rightWholeValue) {\n return 1;\n }\n\n if (leftWholeValue < rightWholeValue) {\n return -1;\n }\n\n const scale = Math.max(leftFraction.length, rightFraction.length);\n const leftFractionValue = BigInt(\n (leftFraction + '0'.repeat(scale)).slice(0, scale) || '0',\n );\n const rightFractionValue = BigInt(\n (rightFraction + '0'.repeat(scale)).slice(0, scale) || '0',\n );\n\n if (leftFractionValue > rightFractionValue) {\n return 1;\n }\n\n if (leftFractionValue < rightFractionValue) {\n return -1;\n }\n\n return 0;\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason);\n }\n\n return new Promise((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout>;\n const handleAbort = (): void => {\n clearTimeout(timeout);\n reject(signal?.reason);\n };\n const handleResolve = (): void => {\n signal?.removeEventListener('abort', handleAbort);\n resolve();\n };\n\n timeout = setTimeout(handleResolve, ms);\n signal?.addEventListener('abort', handleAbort, { once: true });\n });\n}\n\nexport async function* pollPaymentStatus(\n input: WatchPaymentInput,\n getStatus: () => Promise<PaymentStatusResult>,\n): AsyncIterable<PaymentEvent> {\n const startedAt = Date.now();\n const pollIntervalMs = normalizePollIntervalMs(input.pollIntervalMs ?? 5_000);\n const timeoutMs =\n input.timeoutMs === undefined\n ? undefined\n : normalizeTimeoutMs(input.timeoutMs);\n let lastStatus: PaymentStatus | undefined;\n let lastResult: PaymentStatusResult | undefined;\n\n const remainingTimeoutMs = (): number | undefined =>\n timeoutMs === undefined ? undefined : timeoutMs - (Date.now() - startedAt);\n\n const yieldTimeoutEvent = async (): Promise<PaymentEvent> => ({\n ...(lastResult ?? (await getStatus())),\n event: 'timeout',\n status: lastResult?.status ?? 'pending',\n updatedAt: new Date(),\n });\n\n while (!input.signal?.aborted) {\n if ((remainingTimeoutMs() ?? 1) <= 0) {\n yield await yieldTimeoutEvent();\n return;\n }\n\n const status = await getStatus();\n lastResult = status;\n\n if (status.status !== lastStatus) {\n const event = toPaymentEvent(status);\n yield event;\n lastStatus = status.status;\n\n if (TERMINAL_PAYMENT_STATUSES.has(status.status)) {\n return;\n }\n }\n\n const remaining = remainingTimeoutMs();\n\n if (remaining !== undefined && remaining <= 0) {\n yield await yieldTimeoutEvent();\n return;\n }\n\n await sleep(\n remaining === undefined\n ? pollIntervalMs\n : Math.min(pollIntervalMs, remaining),\n input.signal,\n );\n }\n}\n\nfunction normalizePollIntervalMs(value: number): number {\n if (!Number.isInteger(value) || value <= 0) {\n throw new PaymentProviderError(\n `pollIntervalMs must be a positive integer, received ${String(value)}.`,\n );\n }\n\n return value;\n}\n\nfunction normalizeTimeoutMs(value: number): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new PaymentProviderError(\n `timeoutMs must be a non-negative integer, received ${String(value)}.`,\n );\n }\n\n return value;\n}\n\nexport function toPaymentEvent(status: PaymentStatusResult): PaymentEvent {\n if (status.status === 'confirmed') {\n return { ...status, event: 'confirmed' };\n }\n\n if (status.status === 'failed') {\n return { ...status, event: 'failed' };\n }\n\n if (status.status === 'expired') {\n return { ...status, event: 'expired' };\n }\n\n if (status.status === 'refunded') {\n return { ...status, event: 'refunded' };\n }\n\n return { ...status, event: 'status' };\n}\n\nexport async function readJsonResponse<T>(\n response: Response,\n context: string,\n): Promise<T> {\n const text = await response.text();\n let body: unknown;\n\n if (text) {\n try {\n body = JSON.parse(text);\n } catch (error) {\n if (response.ok) {\n throw new PaymentProviderError(`${context}: invalid JSON response`, {\n cause: error,\n });\n }\n\n body = undefined;\n }\n }\n\n if (!response.ok) {\n const message =\n body && typeof body === 'object' && 'message' in body\n ? String((body as { message: unknown }).message)\n : body &&\n typeof body === 'object' &&\n typeof (body as { error?: unknown }).error === 'string'\n ? String((body as { error: string }).error)\n : body &&\n typeof body === 'object' &&\n 'error' in body &&\n typeof (body as { error?: { message?: unknown } }).error\n ?.message === 'string'\n ? (body as { error: { message: string } }).error.message\n : text || response.statusText;\n\n throw new PaymentProviderError(`${context}: ${message}`, {\n retryable: response.status >= 500,\n });\n }\n\n if (body === undefined) {\n throw new PaymentProviderError(`${context}: empty response body`);\n }\n\n return body as T;\n}\n\nexport function formEncode(params: Record<string, unknown>): string {\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n searchParams.set(key, String(value));\n }\n\n return searchParams.toString();\n}\n\nexport function throwUnsupported(message: string): never {\n throw new PaymentUnsupportedError(message);\n}\n"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type PaymentErrorCode = 'PAYMENT_CONFIGURATION_ERROR' | 'PAYMENT_PROVIDER_ERROR' | 'PAYMENT_UNSUPPORTED' | 'PAYMENT_VERIFICATION_FAILED' | 'PAYMENT_TIMEOUT' | 'PAYMENT_INVALID_INPUT';
|
|
2
|
+
export declare class PaymentError extends Error {
|
|
3
|
+
readonly code: PaymentErrorCode;
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
constructor(message: string, code?: PaymentErrorCode, options?: {
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
retryable?: boolean;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export declare class PaymentConfigurationError extends PaymentError {
|
|
11
|
+
constructor(message: string, options?: {
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export declare class PaymentProviderError extends PaymentError {
|
|
16
|
+
constructor(message: string, options?: {
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
retryable?: boolean;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export declare class PaymentUnsupportedError extends PaymentError {
|
|
22
|
+
constructor(message: string, options?: {
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export declare class PaymentVerificationError extends PaymentError {
|
|
27
|
+
constructor(message: string, options?: {
|
|
28
|
+
cause?: unknown;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,6BAA6B,GAC7B,wBAAwB,GACxB,qBAAqB,GACrB,6BAA6B,GAC7B,iBAAiB,GACjB,uBAAuB,CAAC;AAE5B,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAG1B,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,gBAA2C,EACjD,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;CAUzD;AAED,qBAAa,yBAA0B,SAAQ,YAAY;gBAC7C,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAI/D;AAED,qBAAa,oBAAqB,SAAQ,YAAY;gBAElD,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;CAKzD;AAED,qBAAa,uBAAwB,SAAQ,YAAY;gBAC3C,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAI/D;AAED,qBAAa,wBAAyB,SAAQ,YAAY;gBAC5C,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAI/D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseUsdcAdapterOptions } from './adapters/base-usdc.js';
|
|
2
|
+
import { BtcAdapterOptions } from './adapters/btc.js';
|
|
3
|
+
import { StripeAdapterOptions } from './adapters/stripe.js';
|
|
4
|
+
import { PaymentBackend } from './types.js';
|
|
5
|
+
export type PaymentBackendOptions = ({
|
|
6
|
+
type: 'base-usdc';
|
|
7
|
+
} & BaseUsdcAdapterOptions) | ({
|
|
8
|
+
type: 'btc';
|
|
9
|
+
} & BtcAdapterOptions) | ({
|
|
10
|
+
type: 'stripe';
|
|
11
|
+
} & StripeAdapterOptions);
|
|
12
|
+
export declare function createPaymentBackend(options: PaymentBackendOptions): Promise<PaymentBackend>;
|
|
13
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,qBAAqB,GAC7B,CAAC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG,sBAAsB,CAAC,GAChD,CAAC;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG,iBAAiB,CAAC,GACrC,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,oBAAoB,CAAC,CAAC;AAEhD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAuCzB"}
|