@djangocfg/支付
提供者不可知论 反应支付模块. 条纹一等软件包
从不依赖于混凝土 SDK——主机注入适配器. 作战测试
在制作中(一次性付款 主动离职、经常订阅
条纹链接,卡片在文件上),取入前 @djangocfg/*。 。 。 .
📖 完整文件 ∗∗ ——架构,服务器 合同,花纹陷阱,测试.
缝合
东道主选 一个 适配器并通过 <PaymentProvider>软件包
钩子/组件读取 usePaymentAdapter() 绝不导入条纹
或直接生成的 API 客户端.
import { PaymentProvider, createMockPaymentAdapter } from '@djangocfg/payments';
// Mock-first: build & verify the whole UX before any backend exists.
<PaymentProvider adapter={createMockPaymentAdapter()}>
{children}
</PaymentProvider>
Swapping to real Strape是一行主机更改:
// loadStripe is re-exported by this package — the host never declares @stripe/*.
import { PaymentProvider, createStripeAdapter, loadStripe } from '@djangocfg/payments';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PK!); // once, module scope
const adapter = createStripeAdapter({
getStripe: () => stripePromise,
createIntentOnBackend: (input) => api.payments.createIntent(input), // host transport
});
<PaymentProvider adapter={adapter}>{children}</PaymentProvider>;
层层
domain/ pure types + money/card helpers (no React, no Stripe)
context/ <PaymentProvider> + <CheckoutGuard> (the seam, the in-flight lock)
transport/ mock-adapter | stripe-adapter (the SDK seam; see the note below)
hooks/ useCheckout, useCardSetup, usePaymentHistory, useSavedCards
components/ CheckoutForm, CardSetupForm, StripePaymentElement, dialogs, tables, badges
@stripe/* 是一个 运行时间 完全依赖两个文件
(单位:千美元)transport/stripe-adapter.ts, (中文(简体) ), components/StripePaymentElement.tsx)和a 数据
只类型 三分之一(components/appearance.ts()——由
scripts/check-stripe-imports.mjs,哪个 pnpm check 运行.
@stripe/stripe-js 只有很小的 CDN 装载器(真正的 SDK 负载来自
js.stripe.com 在运行时,所以树摇会将花纹组件从
模拟只捆绑。 见 @docs/ARCHITECTURE.md 页:1
为什么这是一个包 边界在哪里.
样式 (Tailwind v4) — 需要接线
这个包被消耗了 从源 用 Tailwind 工具样式
课程。 尾风v4只产生它可以看到的类,所以消费者的
全局 CSS 必须导入软件包的样式条目( 它带有 @source
指向 Tailwind 的指令 :
/* your app's globals.css */
@import "@djangocfg/ui-core/styles/full";
@import "@djangocfg/payments/styles"; /* ← add this */
缺失时的症状:组件在斑点——例如:.
PaymentStatusBadge 芯片失去背景符号, 显示为纯文本 .
Next.js 主机也将软件包添加到 transpilePackages。 。 。 .
公共 API
| 导出 | 仁爱 | 目的 |
|---|---|---|
PaymentProvider 编号 : usePaymentAdapter | 上下文 | 插入/ 读取适配器 |
createMockPaymentAdapter | 适配器 | 全假状态机(成功/下降/3DS/卡) |
createStripeAdapter | 适配器 | real strape (主机供应密钥+后端呼叫) |
useCheckout | 钩子 | idle → creating → requires_payment → processing → succeeded|failed|requires_action |
useCardSetup | 钩子 | 同一台免费保存卡片的机器 |
useSavedCards | 钩子 | 文件上的卡片为相( p)unavailable|loading|ready|error+ 设置默认/去除 |
usePaymentHistory | 钩子 | 通过 adapter.listPayments |
CheckoutDialog | 组件 | 关闭锁定对话框 shell; 将您的取出正文包入其中 |
CheckoutForm | 组件 | 提供者-不可知表壳; 通过 paymentField |
CardSetupForm | 组件 | 同样,用于保存一卡(没有金额,没有"援助") |
UpdateCardDialog | 组件 | 整个加卡流:意图打开、确认、报告 |
SavedCardList | 组件 | 纸牌表:默认徽章、过期警告、行动作 |
StripePaymentElement | 组件 | <Elements> + 键 <PaymentElement>; 渲染活元素 |
PaymentHistory | 组件 | 可排序表格 PaymentRecord |
PaymentStatusBadge | 组件 | ui-core语义符号上的状态药丸 |
toMinorUnits 编号 : toMajorUnits 编号 : formatAmount | 用户 | 边界资金(整数小单位) |
cardExpiresAt 编号 : isCardExpired 编号 : isCardExpiringSoon 编号 : formatCardExpiry 编号 : sortCards 编号 : cardsOf | 用户 | 以时钟计算出卡片 |
公约
- 来源消耗(无捆绑);
main编号 :types编号 :exports→./src/index.ts。 。 。 . - ui-core平面导入. 没有部件依赖性: 软件包可能不依赖于一个
部件( r)
widgets/CLAUDE.md) (中文(简体) ). - 对 没有 自己挂载
<UiProviders>——主持人提供一次. - 无地:用户提供标签为道具/道具(host supports i18n).
- 校验
pnpm -F @djangocfg/payments check财务报告和审定财务报表… lint。 。 。 .
文件上的卡片
订阅超过支付卡的寿命: 当续约失败时 重试2周 对同一张存储卡,然后放弃。 无 一个想要付钱的客户 就会失去订阅费.
const { phase, canAddCard, canManageCards, refresh, setDefault, remove, isBusy } =
useSavedCards();
<SavedCardList
phase={phase}
busy={isBusy}
onAddCard={canAddCard ? () => setOpen(true) : undefined}
onSetDefault={canManageCards ? setDefault : undefined}
onRemove={canManageCards ? remove : undefined}
/>
<UpdateCardDialog open={open} onClose={close} onSaved={() => { close(); void refresh(); }} />
4个主机端点,全线或无线,加上失败的4个服务器规则
默默地——见 @docs/CARD_ON_FILE.md 财务报告和审定财务报表
@docs/SERVER_CONTRACT.md。 。 。 .
不是林克,不是比林门户. 链接是一个购买方钱包
link.com您不知道您的订阅情况, 以及续约费 存储pm_…。Billing门户网站是一个服务器侧方向转换器,可以丢弃 这个软件包的主题和主机的地址。 原因出现@docs/STRIPE_NOTES.md。 。 。 .
配置密钥( K)
三把花纹钥匙,从安全的地方分出去 条纹船 测试
(单位:千美元)sk_test_…, (中文(简体) ), pk_test_…和 现场直播 (单位:千美元)sk_live_…, (中文(简体) ), pk_live_…(香味) 风味
与 相同的可变名称;只有数值不同。 先提出测试.
| 密钥 | 前缀 | 住在这里 | 曝光到浏览器吗 ? |
|---|---|---|---|
| 密钥 | sk_test_… 编号 : sk_live_… | 仅后端 (单位:千美元)STRIPE__SECRET_KEY(中文(简体) ) | 从来没有 |
| Webhook 签名秘密 | whsec_… | 仅后端 (单位:千美元)STRIPE__WEBHOOK_SECRET(中文(简体) ) | 从来没有 |
| 可公布的密钥 | pk_test_… 编号 : pk_live_… | 后端 + 前端 | 安全(设计公开) |
# backend, git-ignored secrets file
STRIPE__SECRET_KEY=sk_test_xxx
STRIPE__PUBLISHABLE_KEY=pk_test_xxx
STRIPE__WEBHOOK_SECRET=whsec_xxx # comma-separate to rotate: whsec_new,whsec_old
# your Next.js app .env
NEXT_PUBLIC_STRIPE_PK=pk_test_xxx
与 没有 NEXT_PUBLIC_STRIPE_PK 设定,主机返回到 模拟
适配器 ——整个UX仍能制得(没有真正的充电).
- 秘诀
sk_)和网钩whsec_) 键必须活在一个被 git-ignored 文件或一个秘密管理员。 仅pk_…在跟踪配置中是安全的.
条纹设置( 测试模式)
- 测试密钥 – Dashboard – 开发者 – API 密钥(切换"测试模式").
- 网页 - 当地,条纹CLI打印a
whsec_…转交文件 结束点 :
已部署: 在 Dashboard 中创建终点并订阅stripe listen --forward-to localhost:8000/<your-webhook-path>/payment_intent.succeeded, (中文(简体) ),payment_intent.payment_failed, (中文(简体) ),charge.refunded(加上发票/订阅事件). - 测试付款 ——卡片
4242 4242 4242 4242,任何未来过期/CVC.stripe trigger payment_intent.succeeded stripe events resend <evt_id> # test idempotency / replay
活下来
- 切换全部三个
STRIPE__*价值和价值NEXT_PUBLIC_STRIPE_PK活下来. - 创建一个 现场直播 webhook 端点(live模式有自己的签名秘密).
- 如果您启用钱包, 请为 Apple Pay / Google Pay 注册您的域 .
- 做一个小真正的充电来确认端到端.