@nymbalhq/adapter-stripe 1.0.0 → 1.1.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/dist/index.d.ts +2 -0
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/recipes/stripe.json +41 -0
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Logger, PaymentsAdapter, AdapterContext } from '@nymbalhq/types';
|
|
|
3
3
|
interface StripePaymentsConfig {
|
|
4
4
|
secretKey: string;
|
|
5
5
|
webhookSecret: string;
|
|
6
|
+
/** The public key the storefront's Stripe.js uses; served by GET /api/capabilities. */
|
|
7
|
+
publishableKey?: string;
|
|
6
8
|
apiVersion?: string;
|
|
7
9
|
/** Override the Stripe API host (for stripe-mock style test servers). Omit in production. */
|
|
8
10
|
host?: string;
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,12 @@ function createStripePaymentsAdapter(deps) {
|
|
|
49
49
|
const cfg = deps.config;
|
|
50
50
|
if (!cfg.secretKey) throw new PaymentError("not_configured", "Stripe secretKey missing");
|
|
51
51
|
if (!cfg.webhookSecret) throw new PaymentError("not_configured", "Stripe webhookSecret missing");
|
|
52
|
+
if (cfg.publishableKey !== void 0 && /^(sk|rk)_/.test(cfg.publishableKey)) {
|
|
53
|
+
throw new PaymentError(
|
|
54
|
+
"not_configured",
|
|
55
|
+
"Stripe publishableKey holds a secret key; use the pk_ key"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
52
58
|
const stripeClient = new Stripe(cfg.secretKey, {
|
|
53
59
|
...cfg.apiVersion !== void 0 && {
|
|
54
60
|
apiVersion: cfg.apiVersion
|
|
@@ -61,6 +67,11 @@ function createStripePaymentsAdapter(deps) {
|
|
|
61
67
|
kind: "payments",
|
|
62
68
|
providerName: "stripe",
|
|
63
69
|
capabilities: () => ["intent", "capture", "refund", "webhook"],
|
|
70
|
+
// Without a key the storefront's stripe driver reports it cannot mount, which keeps Place Order disabled.
|
|
71
|
+
client: () => ({
|
|
72
|
+
driver: "stripe",
|
|
73
|
+
options: cfg.publishableKey ? { publishableKey: cfg.publishableKey } : {}
|
|
74
|
+
}),
|
|
64
75
|
producesEvents: [EVT_PAYMENT_CAPTURED, EVT_PAYMENT_FAILED, EVT_PAYMENT_REFUNDED],
|
|
65
76
|
consumesEvents: [],
|
|
66
77
|
async initialize() {
|
|
@@ -212,9 +223,11 @@ function createAdapter(ctx) {
|
|
|
212
223
|
context: { slot: ctx.slot }
|
|
213
224
|
});
|
|
214
225
|
}
|
|
226
|
+
const config = ctx.config;
|
|
227
|
+
const publishableKey = config.publishableKey ?? ctx.env["STRIPE_PUBLISHABLE_KEY"];
|
|
215
228
|
return createStripePaymentsAdapter({
|
|
216
229
|
logger: ctx.logger,
|
|
217
|
-
config:
|
|
230
|
+
config: { ...config, ...publishableKey !== void 0 && { publishableKey } }
|
|
218
231
|
});
|
|
219
232
|
}
|
|
220
233
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/stripe-adapter.ts"],"sourcesContent":["import { ConfigError, type AdapterContext, type PaymentsAdapter } from '@nymbalhq/types'\nimport { createStripePaymentsAdapter, type StripePaymentsConfig } from './stripe-adapter.js'\n\nexport { createStripePaymentsAdapter, type StripePaymentsConfig }\n\n/** The kernel's entry: `payments: { provider: 'stripe', config: StripePaymentsConfig }`. */\nexport function createAdapter(ctx: AdapterContext): PaymentsAdapter {\n if (ctx.slot !== 'payments') {\n throw new ConfigError(`@nymbalhq/adapter-stripe serves payments, not ${ctx.slot}`, {\n code: 'adapter.wrong_slot',\n context: { slot: ctx.slot },\n })\n }\n return createStripePaymentsAdapter({\n logger: ctx.logger,\n config: ctx.config as unknown as StripePaymentsConfig,\n })\n}\n","import Stripe from 'stripe'\nimport {\n EVT_PAYMENT_CAPTURED,\n EVT_PAYMENT_FAILED,\n EVT_PAYMENT_REFUNDED,\n PaymentError,\n type Logger,\n type PaymentCapture,\n type PaymentIntent,\n type PaymentIntentParams,\n type PaymentStatus,\n type PaymentsAdapter,\n type Refund,\n type WebhookResult,\n} from '@nymbalhq/types'\n\nexport interface StripePaymentsConfig {\n secretKey: string\n webhookSecret: string\n apiVersion?: string\n /** Override the Stripe API host (for stripe-mock style test servers). Omit in production. */\n host?: string\n /** Override the Stripe API port. Only used together with `host`. */\n port?: number\n /** Override the Stripe API protocol. Defaults to https when omitted. */\n protocol?: 'http' | 'https'\n}\n\n/**\n * Stripe returns lowercase ISO currency codes (e.g. \"gbp\"); Nymbal's canonical\n * currency format is uppercase ISO 4217 (e.g. \"GBP\") everywhere else in the\n * domain, so adapter results are normalised on the way out.\n */\nfunction toIsoCurrency(currency: string): string {\n return currency.toUpperCase()\n}\n\nfunction mapStatus(status: Stripe.PaymentIntent.Status): PaymentStatus {\n switch (status) {\n case 'requires_payment_method':\n case 'requires_confirmation':\n case 'requires_action':\n case 'processing':\n case 'requires_capture':\n case 'succeeded':\n case 'canceled':\n return status === 'canceled' ? 'cancelled' : (status as PaymentStatus)\n default:\n return 'failed'\n }\n}\n\nfunction refundStatus(status: string | null): Refund['status'] {\n if (status === 'succeeded') return 'succeeded'\n if (status === 'failed' || status === 'canceled') return 'failed'\n return 'pending'\n}\n\n/**\n * Stripe refused the refund outright (a card error, an invalid request): no money moved. Anything else (an API error,\n * a timeout, a dropped connection) leaves the outcome unknown.\n */\nfunction isDefiniteRefusal(err: unknown): boolean {\n const type = (err as { type?: unknown } | null)?.type\n return type === 'StripeCardError' || type === 'StripeInvalidRequestError'\n}\n\nfunction toIntent(intent: Stripe.PaymentIntent): PaymentIntent {\n return {\n id: intent.id,\n clientSecret: intent.client_secret ?? '',\n amountMinor: intent.amount,\n currency: toIsoCurrency(intent.currency),\n status: mapStatus(intent.status),\n }\n}\n\nexport function createStripePaymentsAdapter(deps: {\n logger: Logger\n config: StripePaymentsConfig\n}): PaymentsAdapter {\n const { logger } = deps\n const cfg = deps.config\n if (!cfg.secretKey) throw new PaymentError('not_configured', 'Stripe secretKey missing')\n if (!cfg.webhookSecret) throw new PaymentError('not_configured', 'Stripe webhookSecret missing')\n const stripeClient = new Stripe(cfg.secretKey, {\n ...(cfg.apiVersion !== undefined && {\n apiVersion: cfg.apiVersion as Stripe.LatestApiVersion,\n }),\n ...(cfg.host !== undefined && { host: cfg.host }),\n ...(cfg.port !== undefined && { port: cfg.port }),\n ...(cfg.protocol !== undefined && { protocol: cfg.protocol }),\n })\n return {\n kind: 'payments',\n providerName: 'stripe',\n capabilities: () => ['intent', 'capture', 'refund', 'webhook'],\n producesEvents: [EVT_PAYMENT_CAPTURED, EVT_PAYMENT_FAILED, EVT_PAYMENT_REFUNDED],\n consumesEvents: [],\n async initialize() {\n // no-op: Stripe client already constructed\n },\n async healthCheck() {\n try {\n await stripeClient.balance.retrieve()\n return { status: 'healthy' }\n } catch (err) {\n return {\n status: 'down',\n detail: err instanceof Error ? err.message : String(err),\n }\n }\n },\n async createPaymentIntent(params: PaymentIntentParams): Promise<PaymentIntent> {\n try {\n const intent = await stripeClient.paymentIntents.create({\n amount: params.amountMinor,\n currency: params.currency.toLowerCase(),\n automatic_payment_methods: { enabled: true },\n ...(params.receiptEmail !== undefined && { receipt_email: params.receiptEmail }),\n metadata: {\n ...(params.metadata ?? {}),\n ...(params.orderRef !== undefined ? { orderRef: params.orderRef } : {}),\n ...(params.customerId !== undefined ? { customerId: params.customerId } : {}),\n },\n })\n return toIntent(intent)\n } catch (err) {\n throw new PaymentError('intent_failed', 'Stripe createPaymentIntent failed', { cause: err })\n }\n },\n async capturePayment(intentId, amountMinor): Promise<PaymentCapture> {\n try {\n const captured = await stripeClient.paymentIntents.capture(intentId, {\n ...(amountMinor !== undefined && { amount_to_capture: amountMinor }),\n })\n return {\n paymentId: captured.id,\n capturedAmountMinor: captured.amount_received ?? captured.amount,\n currency: toIsoCurrency(captured.currency),\n status: mapStatus(captured.status),\n }\n } catch (err) {\n throw new PaymentError('capture_failed', 'Stripe capturePayment failed', { cause: err })\n }\n },\n async refund(paymentId, amountMinor, reason, opts): Promise<Refund> {\n const params: Stripe.RefundCreateParams = {\n payment_intent: paymentId,\n ...(amountMinor !== undefined && { amount: amountMinor }),\n ...(reason !== undefined && { reason: reason as Stripe.RefundCreateParams.Reason }),\n }\n try {\n const refund =\n opts?.idempotencyKey === undefined\n ? await stripeClient.refunds.create(params)\n : await stripeClient.refunds.create(params, { idempotencyKey: opts.idempotencyKey })\n return {\n refundId: refund.id,\n paymentId,\n amountMinor: refund.amount,\n currency: toIsoCurrency(refund.currency),\n reason: refund.reason ?? null,\n status: refundStatus(refund.status),\n }\n } catch (err) {\n if (isDefiniteRefusal(err)) {\n throw new PaymentError('refund_rejected', 'Stripe refused the refund', { cause: err })\n }\n throw new PaymentError('refund_unknown', 'Stripe refund outcome unknown', { cause: err })\n }\n },\n async getPaymentStatus(intentId): Promise<PaymentStatus> {\n const intent = await stripeClient.paymentIntents.retrieve(intentId)\n return mapStatus(intent.status)\n },\n async getPaymentIntent(intentId): Promise<PaymentIntent> {\n try {\n return toIntent(await stripeClient.paymentIntents.retrieve(intentId))\n } catch (err) {\n throw new PaymentError('intent_failed', 'Stripe getPaymentIntent failed', { cause: err })\n }\n },\n async cancelPaymentIntent(intentId): Promise<void> {\n try {\n await stripeClient.paymentIntents.cancel(intentId)\n } catch (err) {\n // A cancel that lost a race with an earlier one of ours is done; anything else (processing, captured) stays.\n const status = await stripeClient.paymentIntents\n .retrieve(intentId)\n .then((intent) => intent.status)\n .catch(() => undefined)\n if (status === 'canceled') return\n throw new PaymentError('cancel_refused', `Stripe would not cancel ${intentId}`, {\n cause: err,\n })\n }\n },\n async parseWebhook(rawBody, signature): Promise<WebhookResult> {\n let event: Stripe.Event\n try {\n event = stripeClient.webhooks.constructEvent(rawBody, signature, cfg.webhookSecret)\n } catch (err) {\n throw new PaymentError('webhook_invalid', 'Stripe webhook signature invalid', {\n cause: err,\n })\n }\n const baseResult = { verified: true, eventId: event.id } as const\n switch (event.type) {\n case 'payment_intent.succeeded': {\n const intent = event.data.object as Stripe.PaymentIntent\n return {\n ...baseResult,\n kind: 'payment.captured',\n paymentIntentId: intent.id,\n amountMinor: intent.amount_received ?? intent.amount,\n currency: toIsoCurrency(intent.currency),\n raw: { ...intent } as unknown as Record<string, unknown>,\n }\n }\n case 'payment_intent.payment_failed': {\n const intent = event.data.object as Stripe.PaymentIntent\n return {\n ...baseResult,\n kind: 'payment.failed',\n paymentIntentId: intent.id,\n reason: intent.last_payment_error?.message ?? 'payment failed',\n }\n }\n case 'charge.refunded': {\n const charge = event.data.object as Stripe.Charge\n const pi =\n typeof charge.payment_intent === 'string'\n ? charge.payment_intent\n : charge.payment_intent?.id\n return {\n ...baseResult,\n kind: 'payment.refunded',\n ...(pi !== undefined && { paymentIntentId: pi }),\n amountMinor: charge.amount_refunded,\n currency: toIsoCurrency(charge.currency),\n }\n }\n default:\n logger.debug({ type: event.type }, 'stripe webhook ignored')\n return { ...baseResult, kind: 'ignored' }\n }\n },\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/stripe-adapter.ts"],"sourcesContent":["import { ConfigError, type AdapterContext, type PaymentsAdapter } from '@nymbalhq/types'\nimport { createStripePaymentsAdapter, type StripePaymentsConfig } from './stripe-adapter.js'\n\nexport { createStripePaymentsAdapter, type StripePaymentsConfig }\n\n/** The kernel's entry: `payments: { provider: 'stripe', config: StripePaymentsConfig }`. */\nexport function createAdapter(ctx: AdapterContext): PaymentsAdapter {\n if (ctx.slot !== 'payments') {\n throw new ConfigError(`@nymbalhq/adapter-stripe serves payments, not ${ctx.slot}`, {\n code: 'adapter.wrong_slot',\n context: { slot: ctx.slot },\n })\n }\n const config = ctx.config as unknown as StripePaymentsConfig\n const publishableKey = config.publishableKey ?? ctx.env['STRIPE_PUBLISHABLE_KEY']\n return createStripePaymentsAdapter({\n logger: ctx.logger,\n config: { ...config, ...(publishableKey !== undefined && { publishableKey }) },\n })\n}\n","import Stripe from 'stripe'\nimport {\n EVT_PAYMENT_CAPTURED,\n EVT_PAYMENT_FAILED,\n EVT_PAYMENT_REFUNDED,\n PaymentError,\n type Logger,\n type PaymentCapture,\n type PaymentIntent,\n type PaymentIntentParams,\n type PaymentStatus,\n type PaymentsAdapter,\n type Refund,\n type WebhookResult,\n} from '@nymbalhq/types'\n\nexport interface StripePaymentsConfig {\n secretKey: string\n webhookSecret: string\n /** The public key the storefront's Stripe.js uses; served by GET /api/capabilities. */\n publishableKey?: string\n apiVersion?: string\n /** Override the Stripe API host (for stripe-mock style test servers). Omit in production. */\n host?: string\n /** Override the Stripe API port. Only used together with `host`. */\n port?: number\n /** Override the Stripe API protocol. Defaults to https when omitted. */\n protocol?: 'http' | 'https'\n}\n\n/**\n * Stripe returns lowercase ISO currency codes (e.g. \"gbp\"); Nymbal's canonical\n * currency format is uppercase ISO 4217 (e.g. \"GBP\") everywhere else in the\n * domain, so adapter results are normalised on the way out.\n */\nfunction toIsoCurrency(currency: string): string {\n return currency.toUpperCase()\n}\n\nfunction mapStatus(status: Stripe.PaymentIntent.Status): PaymentStatus {\n switch (status) {\n case 'requires_payment_method':\n case 'requires_confirmation':\n case 'requires_action':\n case 'processing':\n case 'requires_capture':\n case 'succeeded':\n case 'canceled':\n return status === 'canceled' ? 'cancelled' : (status as PaymentStatus)\n default:\n return 'failed'\n }\n}\n\nfunction refundStatus(status: string | null): Refund['status'] {\n if (status === 'succeeded') return 'succeeded'\n if (status === 'failed' || status === 'canceled') return 'failed'\n return 'pending'\n}\n\n/**\n * Stripe refused the refund outright (a card error, an invalid request): no money moved. Anything else (an API error,\n * a timeout, a dropped connection) leaves the outcome unknown.\n */\nfunction isDefiniteRefusal(err: unknown): boolean {\n const type = (err as { type?: unknown } | null)?.type\n return type === 'StripeCardError' || type === 'StripeInvalidRequestError'\n}\n\nfunction toIntent(intent: Stripe.PaymentIntent): PaymentIntent {\n return {\n id: intent.id,\n clientSecret: intent.client_secret ?? '',\n amountMinor: intent.amount,\n currency: toIsoCurrency(intent.currency),\n status: mapStatus(intent.status),\n }\n}\n\nexport function createStripePaymentsAdapter(deps: {\n logger: Logger\n config: StripePaymentsConfig\n}): PaymentsAdapter {\n const { logger } = deps\n const cfg = deps.config\n if (!cfg.secretKey) throw new PaymentError('not_configured', 'Stripe secretKey missing')\n if (!cfg.webhookSecret) throw new PaymentError('not_configured', 'Stripe webhookSecret missing')\n // The publishable key is served to every shopper: a secret or restricted key pasted there must never be.\n if (cfg.publishableKey !== undefined && /^(sk|rk)_/.test(cfg.publishableKey)) {\n throw new PaymentError(\n 'not_configured',\n 'Stripe publishableKey holds a secret key; use the pk_ key',\n )\n }\n const stripeClient = new Stripe(cfg.secretKey, {\n ...(cfg.apiVersion !== undefined && {\n apiVersion: cfg.apiVersion as Stripe.LatestApiVersion,\n }),\n ...(cfg.host !== undefined && { host: cfg.host }),\n ...(cfg.port !== undefined && { port: cfg.port }),\n ...(cfg.protocol !== undefined && { protocol: cfg.protocol }),\n })\n return {\n kind: 'payments',\n providerName: 'stripe',\n capabilities: () => ['intent', 'capture', 'refund', 'webhook'],\n // Without a key the storefront's stripe driver reports it cannot mount, which keeps Place Order disabled.\n client: () => ({\n driver: 'stripe',\n options: cfg.publishableKey ? { publishableKey: cfg.publishableKey } : {},\n }),\n producesEvents: [EVT_PAYMENT_CAPTURED, EVT_PAYMENT_FAILED, EVT_PAYMENT_REFUNDED],\n consumesEvents: [],\n async initialize() {\n // no-op: Stripe client already constructed\n },\n async healthCheck() {\n try {\n await stripeClient.balance.retrieve()\n return { status: 'healthy' }\n } catch (err) {\n return {\n status: 'down',\n detail: err instanceof Error ? err.message : String(err),\n }\n }\n },\n async createPaymentIntent(params: PaymentIntentParams): Promise<PaymentIntent> {\n try {\n const intent = await stripeClient.paymentIntents.create({\n amount: params.amountMinor,\n currency: params.currency.toLowerCase(),\n automatic_payment_methods: { enabled: true },\n ...(params.receiptEmail !== undefined && { receipt_email: params.receiptEmail }),\n metadata: {\n ...(params.metadata ?? {}),\n ...(params.orderRef !== undefined ? { orderRef: params.orderRef } : {}),\n ...(params.customerId !== undefined ? { customerId: params.customerId } : {}),\n },\n })\n return toIntent(intent)\n } catch (err) {\n throw new PaymentError('intent_failed', 'Stripe createPaymentIntent failed', { cause: err })\n }\n },\n async capturePayment(intentId, amountMinor): Promise<PaymentCapture> {\n try {\n const captured = await stripeClient.paymentIntents.capture(intentId, {\n ...(amountMinor !== undefined && { amount_to_capture: amountMinor }),\n })\n return {\n paymentId: captured.id,\n capturedAmountMinor: captured.amount_received ?? captured.amount,\n currency: toIsoCurrency(captured.currency),\n status: mapStatus(captured.status),\n }\n } catch (err) {\n throw new PaymentError('capture_failed', 'Stripe capturePayment failed', { cause: err })\n }\n },\n async refund(paymentId, amountMinor, reason, opts): Promise<Refund> {\n const params: Stripe.RefundCreateParams = {\n payment_intent: paymentId,\n ...(amountMinor !== undefined && { amount: amountMinor }),\n ...(reason !== undefined && { reason: reason as Stripe.RefundCreateParams.Reason }),\n }\n try {\n const refund =\n opts?.idempotencyKey === undefined\n ? await stripeClient.refunds.create(params)\n : await stripeClient.refunds.create(params, { idempotencyKey: opts.idempotencyKey })\n return {\n refundId: refund.id,\n paymentId,\n amountMinor: refund.amount,\n currency: toIsoCurrency(refund.currency),\n reason: refund.reason ?? null,\n status: refundStatus(refund.status),\n }\n } catch (err) {\n if (isDefiniteRefusal(err)) {\n throw new PaymentError('refund_rejected', 'Stripe refused the refund', { cause: err })\n }\n throw new PaymentError('refund_unknown', 'Stripe refund outcome unknown', { cause: err })\n }\n },\n async getPaymentStatus(intentId): Promise<PaymentStatus> {\n const intent = await stripeClient.paymentIntents.retrieve(intentId)\n return mapStatus(intent.status)\n },\n async getPaymentIntent(intentId): Promise<PaymentIntent> {\n try {\n return toIntent(await stripeClient.paymentIntents.retrieve(intentId))\n } catch (err) {\n throw new PaymentError('intent_failed', 'Stripe getPaymentIntent failed', { cause: err })\n }\n },\n async cancelPaymentIntent(intentId): Promise<void> {\n try {\n await stripeClient.paymentIntents.cancel(intentId)\n } catch (err) {\n // A cancel that lost a race with an earlier one of ours is done; anything else (processing, captured) stays.\n const status = await stripeClient.paymentIntents\n .retrieve(intentId)\n .then((intent) => intent.status)\n .catch(() => undefined)\n if (status === 'canceled') return\n throw new PaymentError('cancel_refused', `Stripe would not cancel ${intentId}`, {\n cause: err,\n })\n }\n },\n async parseWebhook(rawBody, signature): Promise<WebhookResult> {\n let event: Stripe.Event\n try {\n event = stripeClient.webhooks.constructEvent(rawBody, signature, cfg.webhookSecret)\n } catch (err) {\n throw new PaymentError('webhook_invalid', 'Stripe webhook signature invalid', {\n cause: err,\n })\n }\n const baseResult = { verified: true, eventId: event.id } as const\n switch (event.type) {\n case 'payment_intent.succeeded': {\n const intent = event.data.object as Stripe.PaymentIntent\n return {\n ...baseResult,\n kind: 'payment.captured',\n paymentIntentId: intent.id,\n amountMinor: intent.amount_received ?? intent.amount,\n currency: toIsoCurrency(intent.currency),\n raw: { ...intent } as unknown as Record<string, unknown>,\n }\n }\n case 'payment_intent.payment_failed': {\n const intent = event.data.object as Stripe.PaymentIntent\n return {\n ...baseResult,\n kind: 'payment.failed',\n paymentIntentId: intent.id,\n reason: intent.last_payment_error?.message ?? 'payment failed',\n }\n }\n case 'charge.refunded': {\n const charge = event.data.object as Stripe.Charge\n const pi =\n typeof charge.payment_intent === 'string'\n ? charge.payment_intent\n : charge.payment_intent?.id\n return {\n ...baseResult,\n kind: 'payment.refunded',\n ...(pi !== undefined && { paymentIntentId: pi }),\n amountMinor: charge.amount_refunded,\n currency: toIsoCurrency(charge.currency),\n }\n }\n default:\n logger.debug({ type: event.type }, 'stripe webhook ignored')\n return { ...baseResult, kind: 'ignored' }\n }\n },\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nymbalhq/adapter-stripe",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Stripe payments for Nymbal: the `stripe` payments provider",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,13 +21,15 @@
|
|
|
21
21
|
".": {
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"import": "./dist/index.js"
|
|
24
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"./recipes/*": "./recipes/*"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"recipes"
|
|
28
30
|
],
|
|
29
31
|
"dependencies": {
|
|
30
|
-
"@nymbalhq/types": "1.
|
|
32
|
+
"@nymbalhq/types": "1.1.0"
|
|
31
33
|
},
|
|
32
34
|
"peerDependencies": {
|
|
33
35
|
"stripe": "^17.4.0"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stripe",
|
|
3
|
+
"summary": "Take card payments with Stripe instead of the native stub.",
|
|
4
|
+
"install": ["@nymbalhq/adapter-stripe", "stripe"],
|
|
5
|
+
"set": [
|
|
6
|
+
{
|
|
7
|
+
"path": "commerce.payments",
|
|
8
|
+
"value": {
|
|
9
|
+
"provider": "stripe",
|
|
10
|
+
"config": {
|
|
11
|
+
"secretKey": { "env": "STRIPE_SECRET_KEY" },
|
|
12
|
+
"webhookSecret": { "env": "STRIPE_WEBHOOK_SECRET" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"env": [
|
|
18
|
+
{
|
|
19
|
+
"name": "STRIPE_SECRET_KEY",
|
|
20
|
+
"example": "",
|
|
21
|
+
"required": true,
|
|
22
|
+
"comment": "Your Stripe secret key (Dashboard, Developers, API keys)"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "STRIPE_WEBHOOK_SECRET",
|
|
26
|
+
"example": "",
|
|
27
|
+
"required": true,
|
|
28
|
+
"comment": "The signing secret of the webhook endpoint below"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "STRIPE_PUBLISHABLE_KEY",
|
|
32
|
+
"example": "",
|
|
33
|
+
"required": true,
|
|
34
|
+
"comment": "Your Stripe publishable key, which the storefront's payment form uses"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"next": [
|
|
38
|
+
"Add a webhook endpoint in the Stripe dashboard at https://<your API host>/api/webhooks/stripe and copy its signing secret into STRIPE_WEBHOOK_SECRET.",
|
|
39
|
+
"For local development, stripe listen --forward-to localhost:3001/api/webhooks/stripe prints a signing secret to use instead."
|
|
40
|
+
]
|
|
41
|
+
}
|