@coderize/stripe

中文文档
2.3.0发布于 2026/11/07UNLICENSEDTypeScriptES Module零依赖近 30 天下载 2285

CoderizeDEV应用程序的共享花纹构件:被绑定的API版本,客户端,CI的版本守护,webhook基础,被移动字段的阅读器和浏览器安全卡费毛起

中文使用文档
文档目录11 节
  1. 规则:更改API版本是主要发布
  2. 从1.x升级
  3. 在应用程序中采纳
  4. 1. 客户
  5. 2. 中情局警卫
  6. 3. 网络用户
  7. 4. 移动字段的读者
  8. 5. 支付卡费( @coderize/stripe/fees (中文(简体) )
  9. 审查新的 SDK 默认值
  10. 计划
  11. 版本数

@ coderize/ stripe (编译)

每个CoderizeDEV应用程序如何与Frede交谈:一个被绑定的API版本,客户端用它构建,一个CI守护者 失败 stripe 升级会移动它, 网络hook基础( raw- body signition check, 仅限一次) 处理、按类型排列路由、字段的阅读器在API版本之间移动,以及浏览器安全 卡片费总价 所以,一个出票页 显示了准确的收费 API收费.

pnpm add @coderize/stripe

同伴依赖 : stripe 23. 每个应用程序都保留 stripe 所以这个一揽子方案从不带来 sDK的第二份副本。 包含有 TypeScript 类型的 Plain JavaScript (ESM).

规则:更改API版本是主要发布

STRIPE_API_VERSION 实值 2026-10-28.endive 2.x. 1.x被钉住 2026-08-26.dahlia从1.x移动的应用程序 首先更改其代码:参见 从1.x升级。该版本仅以 主要 释放此软件包。 翻新会将小的和补丁的发布单独合并,并保留主要内容供审查,所以没有 app更改了API版本,没有读取更改日志的人,首先测试出站.

没有了针头,条纹节点不使用账户的 Dashboard 版本:它发送该版本自己的发布 被建造反对。 条形 23.0 将默认移动到 2026-09-30.endive 第23.1段至第23.1段 2026-10-28.endive,所以一个 未绑定的客户端已经处于绝境状态.

从1.x升级

2.0.0 从 2026-08-26.dahlia 改为 2026-10-28.endive。 。 。 . 2026-10-28.endive 没有GA突破 改变它自己的,所以移动意味着承担断裂的改变 2026-09-30.endive。应用程序停留在 1.x 上 直到它自己通过PR(革新持有主要),并且PR做出这些改变:

  1. 丢弃 payment_method_types 从每一个写 不再需要它. 退出会话创建, 支付意向 创建、更新和确认,并设置 Intent 创建和现在更新答案 400个 当它通过时 (单位:千美元)payment_method_types_no_longer_supported 以图谋。 要么:

    • 在Dashboard中删除并管理支付方法(动态支付方法,一种支付方法) 配置),不包括任何你不想与 excluded_payment_method_types;或 ;或
    • 改为: allowed_payment_method_types: [...]。 。 。 .

    allowed_payment_method_types 静默过滤器: 无法使用的账户或金额类型被忽略 而不是失败请求。 如果一种方法很重要(价格取决于卡或电子检查,例如),则检查 页:1 payment_method_types 创建对象返回,当您要求的对象缺失时失败. 阅读 payment_method_types 在返回对象上仍然工作,并且 Paying Links 创建保存 参数:它不是变化的一部分。 更新验证旧创建参数的测试 .

  2. 过 billing_cycle_anchor 作为订阅更新和恢复的对象. 'unchanged' 变成 { type: 'unchanged' } 财务报告和审定财务报表 'now' 变成 { type: 'now' }。 。 。 . invoices.createPreview 将同一对象带入 subscription_details.billing_cycle_anchor时标会变成 { type: 'timestamp', timestamp }。 。 。 . 订阅 创建 不变.

  3. 请检查access-date=中的日期值 (帮助) 2026-09-30.endive对接app. 这些是其他的破碎物品 一个应用程序可以在这里 合理打击:

    • 花纹税 : 新设 failed_tax_calculation 税收计算错误( 创建和预览) , 发票 最终确定、支付和检索,并用自动税创建和更新订阅。 当作失败 计算,绝不作为零税.
    • 连接 : requirements.disabled_reason 拒绝的平台 rejected.platform_fraud, (中文(简体) ), rejected.platform_terms_of_service 财务报告和审定财务报表 rejected.platform_other· ; requirements.errors 可列出 eventually_due 要求;以及 accounts.reject 不再需要钱 reason: 'fraud' (使用时 fraud_other 或一个 具体 fraud_* 说明理由。 只读的应用程序 charges_enabled, (中文(简体) ), payouts_enabled 财务报告和审定财务报表 details_submitted 不受影响.
    • 脚印.js on Endive (单位:千美元)@stripe/stripe-js 10):付款请求按钮和元素 paymentMethodTypes 选项已丢失, 退出会话保存的元素 canConfirm 虚度时 有待更新 billingDetails: 'never' 需要的账单细节 在确认.
    • 其余(账户v2,财务连接,财务和资金管理,PayTo,BLIK,印度授权, 雷达付款评价、储备、争议证据页数限制)只涉及使用这些软件的应用程序 产品。 Frede 列表 : https://docs.stripe.com/changelog/endive (中文(简体) )。 。 。 .
  4. 丢弃任何明确 apiVersion。 。 。 . createStripe 拒绝 apiVersion: '2026-08-26.dahlia' 现在,和类型 拒绝 创建自己客户端的脚本移动到 createStripe 以及证明dahlia的测试 字符串比较 STRIPE_API_VERSION 换句话说.

  5. 移动每个 Webhook 端点到 2026-10-28.endive。 。 。 . 一个有效载荷在其端点的API版本中被渲染,而不是 所以Dahlia上留下的终点 总是发送Dahlia的有效载荷 下面的读者选择 形状,所以两个相重叠时没有中断 :

    1. 在 2026-10-28.endive 用于同一路径和事件(Dashboard,或 webhookEndpoints.create 与 api_version: STRIPE_API_VERSION) (中文(简体) ).
    2. 把签名的秘密都交给应用公司 verifyWebhook({ secret: [oldSecret, newSecret] })。 。 。 . 两个端点在两场比赛同时进行 都是一样的 event.id这样 processEventOnce 跳过第二次送货.
    3. 部署,确认事件到达新的终点, 然后关闭旧的,并放弃它的秘密.
  6. 运行测试模式检出 (和订阅变更,其中应用有一个)合并前.

中央情报局警卫coderize-stripe-check保持原样,并穿行23.0和23.1条.

在应用程序中采纳

1. 客户

替换应用程序 new Stripe(key, { apiVersion }) 与 createStripe,并删除其自己的版本常数.

// src/plugins/stripe.js
import fp from 'fastify-plugin'
import { createStripe } from '@coderize/stripe'

export default fp(async function stripePlugin(app) {
  app.decorate('stripe', createStripe(process.env.STRIPE_SECRET_KEY))
})

createStripe(secretKey, options) 返回指针上的条形节点客户端 maxNetworkRetries: 2其他项目 条形节点选项通过( c)timeout, (中文(简体) ), stripeAccount, (中文(简体) ), httpClient(......) (中文(简体) ). 它扔在空钥匙上,然后 a 一个 apiVersion 除了指针: 需要另一个版本的应用程序需要在这里发布另一个主要版本,而不是一个 本地覆盖 。 构建自己客户端的脚本( S)scripts/*.mjs, (中文(简体) ), prisma/*.js使用它,或者他们说话 sDK的默认版本,而应用则会说话取出接针.

仅构建客户端的测试不需要网络:构建一个不需要请求.

2. 中情局警卫

安装后, 在应用程序的 CI 工作流程中添加一个步骤 :

- name: Check the Stripe API version
  run: pnpm --filter <scope>/api exec coderize-stripe-check

它不需要网络、密钥或数据库,并且在下列情况下失败(退出 1):

  • 已安装 stripe 默认为 API 版本, 此版本尚未审查(REVIEWED_SDK_DEFAULTS),或
  • 来自 createStripe 不发送针.

所以,当翻新提供 stripe 释放移动默认值的 PR 红色直到发布此值 包检出. 别在应用程序里工作 同样的支票是 checkStripeVersion() 测试.

一旦这个程序运行,就删除它自己的守护脚本和打针测试.

3. 网络用户

花纹标记它发送的确切字节. 解析 JSON 并按顺序再次更改白空间和密钥 命令,因此签名不再匹配,对重新平分对象的检查也证明没有。 所以说 webhook 路由读取 活体: 在 Fastify 中,在 webhook 中注册的缓冲内容类型解析器 路由本身的插件( 绝不是全局); 在 Next.js, await request.text()。 。 。 .

使用 handleStripeWebhook。 。 。 . 整个网络都用一个电话 检查签名,回答事件 类型中没有处理器,将事件id记录在与处理器相同的交易中,所以第二个副本是 跳过(甚至一个在同一时刻到达),并在交易完成后产生副作用。 这个 应用程序只写它的处理器和一个表格:

model StripeEvent {
  id         String   @id
  type       String
  receivedAt DateTime @default(now())
}
// src/routes/stripeWebhook.js (Fastify)
import { handleStripeWebhook } from '@coderize/stripe'

export default async function stripeWebhookRoutes(app) {
  app.addContentTypeParser('application/json', { parseAs: 'buffer' }, (request, body, done) => done(null, body))

  app.post('/', async (request, reply) => {
    const { status, body } = await handleStripeWebhook({
      stripe: app.stripe,
      rawBody: request.body,
      signature: request.headers['stripe-signature'],
      // Both secrets while an endpoint is being replaced; the old one comes out after the switch.
      secret: [process.env.STRIPE_WEBHOOK_SECRET, process.env.STRIPE_WEBHOOK_SECRET_NEXT],
      prisma: app.prisma,
      handlers,
      log: request.log
    })
    return reply.code(status).send(body)
  })
}

const handlers = {
  // Every database write goes through `tx`; anything outside the database goes through `after`.
  'invoice.paid': async (event, { tx, after }) => {
    const payment = await tx.payment.create({ data: { stripeInvoiceId: event.data.object.id /* ... */ } })
    after(() => sendReceipt(payment))
  }
}
// src/app/api/stripe/webhook/route.ts (Next.js)
export async function POST(request: Request) {
  const { status, body } = await handleStripeWebhook({
    stripe,
    rawBody: await request.text(),
    signature: request.headers.get('stripe-signature'),
    secret: [process.env.STRIPE_WEBHOOK_SECRET!, process.env.STRIPE_WEBHOOK_SECRET_NEXT!],
    prisma,
    handlers
  })
  return Response.json(body, { status })
}

handleStripeWebhook({ stripe, rawBody, signature, secret, handlers, prisma, log }) 决定 { status, body },答案是:

大小写状态体质
已处理200个{ received: true }
已处理的事件副本200个{ received: true, duplicate: true }
该类型没有处理器(已登录)200个{ received: true, handled: false }
被拒绝 verifyWebhook (下关400/500 (中文(简体) ){ error, code }

当一个处理者扔出,它 拒绝 而不是以 StripeWebhookHandlerError (单位:千美元)statusCode 五百块, code HANDLER_FAILED, (中文(简体) ), eventId, (中文(简体) ), eventType,处理器错误为 cause: 交易随事件 ID回滚, 框架回答 500 并报告错误, Frede 重试 再次运行处理器。 别接. 包装器是它保存500的:一个应用程序的错误处理器的答案 Prisma的P2025和P2002,配有404和409 (中文(简体) )@coderize/fastify-kit 在普通路线上进行)和 AppError 和它的4xx, 和斯德雷克以4xx作为最终, 所以事件会被放弃, 没有报告. 这是故意的 StripeWebhookError,所以一个路径 捕捉那些发送状态 吞下它 吞下来 A 类 函数队列 after 失败将被登录, 网络浏览仍然回答 200, 因为支付它 接着发生了. log 取出皮诺 (request.log)或控制台,默认值。 指定或形状的表格 不同的经历 storeOptions (单位:千美元){ model: 'webhookEvent', idField: 'stripeEventId' }),以及 store 全部替换 Prisma 商店 .

以下各部分为从何而来. 只当一个电话不合适时直接使用.

verifyWebhook({ stripe, rawBody, signature, secret, tolerance }) 返回事件或丢出一个 StripeWebhookError 谁 statusCode 答案是发送:

code状态含义
MISSING_SIGNATURE400个没有 Stripe-Signature 标题
INVALID_SIGNATURE400个错误的秘密, 改变的身体, 或签名比 tolerance
RAW_BODY_REQUIRED500个尸体已解析: 路径已丢失其生体解析器
WEBHOOK_NOT_CONFIGURED500个没有客户端 没有签名秘密

这两起500起事件是我们的过错,所以斯德莱克不断重试,直到被修复,而不是被抛出的事件. secret 可以在替换终点时成为列表:新旧终点以不同的符号表示 秘密,一个事件通过 当它匹配。 任何来自条形节点的其他错误都会被传递.

processEventOnce(event, handler, store, { mode }) 处理每个事件一次。 条纹再换到它 得到一个2xx,并且可以同时提供两次活动. 应用程序保存存储器,一个具有独特事件ID的表格, 和回话 record(id, event, tx), (中文(简体) ), seen(id), (中文(简体) ), transaction(work),可选择 isDuplicate(err) (Prisma's (英语) P2002 (默认情况下). 它决定 { duplicate }; 回答 200 左右。 失败 拒绝: 让路线回答 500 个, 所以 Strape 重试 。 永远不要抓住它和回答2xx, 这停止了重复.

有两种模式,但失败方式不同:

  • claim (默认值):事件id被记录 首先,在与工作相同的交易中A级 重新交付,即使是同时交付,都会遇到独特的制约,被跳过。 如果工作失败 倒滚取出ID与之并重试再运行工作. 交易中的一切都会发生 一次就是这样 这是舰队需要的图案; 编码-dev-mono's routes/webhooks.js 这是 参考文献. record 返回时已报告身份 false (单位:千美元) ON CONFLICT DO NOTHING 插入 )或者通过抛出唯一约束错误. seen如果给定的话, 是便宜的预选 它跳过打开一个交易 一个明显的重递.
  • record-after数字 : seen 首先,然后工作,然后 record它永远不会失去一个事件,因为ID是 只在作品成功后写出. 但是两个送货的赛车 既可以运行工作, 和碰撞之间 作品和唱片在重试中再次运行。 只当工作无法共享交易时使用 (它称为"花纹"或"另一种服务"),并让这种功能发挥作用:每个花纹上的一等钥匙 创建、 更新而不是插入.

它从未提供的东西是在工作前将ID记录在自己的声明中. 如果工作失败了, 重试时看到ID并跳过它,一个付酬事件会永远丢失;这发生在一个舰队应用中. 删除 编号再次在一个 catch 是一个较弱的后退, 因为一个坠机中手仍然失去这个事件.

prismaEventStore(prisma, { model, idField, data, transactionOptions }) 是仓库 handleStripeWebhook 使用 : record, (中文(简体) ), seen 财务报告和审定财务报表 transaction 超过 Prisma 模型, 带有独特的事件 ID (单位:千美元)prisma.stripeEvent 财务报告和审定财务报表 id 在默认情况下),由于Neon来回路程导致交易超时20秒 普里斯玛5秒的默认紧凑. 传过来 processEventOnce 当你给台阶打电话的时候.

routeEvent(event, handlers, context) 电话 handlers[event.type](event, context) 并决心 true,或 决定 false 当没有处理器匹配时。 登录 false 其中一个: 没人处理的事件类型是最常见的 webhook 代码中的漏洞. 在 TypeScript 中,每个处理器都会将事件缩小到其类型.

4. 移动字段的读者

API版本 2025-03-31. Basil移动了多个字段,一个webhook有效载荷在 它的终点 API 密码 版本,不是客户端的指针,所以两个形状都可以到达. 这些田地都没有再搬进去了 2026-09-30.endive 或者说 2026-10-28.endive。每个读者首先采用新形状,然后采用旧形状 一秒钟,当史黛丽不说时,返回无效。 只读出旧字段的代码悄悄失败: a 续约被跳过作为"未跟踪", 收入份额从未记录过, 船到地址被账单的取而代之.

阅读器读取(新形状,后为旧)
subscriptionPeriod(subscription){ start, end } 日期从 items.data[].current_period_* (最晚获胜),那么 current_period_*
invoiceSubscriptionId(invoice)parent.subscription_details.subscription,则 subscription
invoicePeriodStart(invoice)lines.data[0].period.start日期
invoicePaymentIntentId(stripe, invoice)payment_intent,则 payments.data[].payment.payment_intent; async,见下文
invoiceChargeId(invoice)charge,则 payments.data[].payment.charge 或扩大的意图 latest_charge
checkoutShipping(session)collected_information.shipping_details,则 shipping_details

网路的发票没有 payments 名单从basil. invoicePaymentIntentId 当有效载荷时取取 缺少(一个) invoices.retrieve 与 expand: ['payments']; 通过 null 作为 stripe 读取有效载荷 只),并拒绝如果史黛丽无法被接通的话,所以被网友重复. invoiceChargeId 仅读出有效载荷: 通过一张与 expand: ['payments.data.payment.payment_intent'] 以达到后面的电荷 意图。 两人都喜欢用 status: 'paid' 对失败的尝试。 从 subscriptionPeriod 意思是"保存所储存的值",从不"写作虚无".

checkoutShipping 返回为无效。 一个自带的软件 {} 写入 checkoutShipping(session) ?? {} 以保持这种行为.

5. 支付卡费(@coderize/stripe/fees(中文(简体) )

当付款人支付处理费时,显示收费的页面和收费的API必须计算 同一个号码 电离层把它们分开了, 以浮动美元表示的页面和以整数美分表示的API, 其中387 500 000美元从0.01美元到5 000.00美元,显示收费比所收卡高1美元。 双方导入此选项 一个函数代替:

// the checkout page (browser) and the checkout route (API) alike
import { cardFeeCents, grossUpForCardFee } from '@coderize/stripe/fees'

const { feeCents, totalCents } = grossUpForCardFee(subtotalCents) // 5000 -> 181 and 5181

@coderize/stripe/fees 不导入, 因此一个 Vite 或 Astro 页面可以装入它, 没有花纹 SDK 或任何节点 内置。 主条目不再出口: 从 ./fees 到处都是.

导出这是什么
grossUpForCardFee(netCents, { rate, fixedCents }){ netCents, feeCents, totalCents }: 蚊帐总数 netCents 收费之后
cardFeeCents(netCents, fee?)页:1 feeCents 单是"处理费"一行
US_CARD_FEE{ rate: 0.029, fixedCents: 30 },花旗的标准美国卡定价和默认

总共是 (net + fixed) / (1 - rate) 四舍五入到百分点,所以雄性永远不短一次花纹 轮回自己的费用。 这就是独行侠的API和Implay的 feeCalc 已收费, 每笔金额; 运行中 在整数算术中,没有浮起一分高。 数量为整数分(一浮动或一串抛出),以及 rate 是一个小数,最多为小数点后六位数的分数(0.022 2.2%的非营利性费率.

将应用程序移动到它上会更改这些, 所以将 API 及其页面放入相同的 PR:

  • icrotary的页面 (单位:千美元)PayInvoice, (中文(简体) ), RaffleTicketForm, (中文(简体) ), LunchCredits上面387个数额减去1美元, 现在匹配电荷。 内容 DonationForm 且API不变.
  • 庇护者和受孕者 四舍五入到最接近的百分数(Math.round) (中文(简体) ). 在这500 000人中的249 742人 计算共享函数对付款人1++的收费,以及证明完全需要更新的测试.
  • 伊姆莱 不变.

审查新的 SDK 默认值

当守卫在新东西上失败时 stripe 释放 :

  1. 查找新默认值 : node -p "require('stripe/package.json').version" 和警卫的 sdkDefault。 。 。 .
  2. 读取 Frede 的变换日志 , 在 Pin 和 新默认值之间 , 并 grep 机队 打破更改:写出参数,读出字段,webhook有效载荷形状.
  3. 添加条目到 REVIEWED_SDK_DEFAULTS 内 version.js 加上日期、决定和发现 小声 变换器,然后释放。 Apps把它捡起来 他们的后卫是绿色的 针不变.
  4. 把它自己移开就是个 主要 释放: 更改 STRIPE_API_VERSION,标记条目 adopted,然后说 在更改列表中,每个应用程序必须改变什么。 每一个应用 也移动它的 Webhook 端点到新版本, 因为有效载荷遵循终点的版本.

计划

第一阶段是一分一分 被钉在了Dahlia身上 所以采用它不会改变任何行为 第二阶段将每个应用程序移动到它上 (客户,警卫,网络浏览基本内容,读者),每个应用程序一个PR,在路上修补被移动的场阅读. 第3阶段是 2.0.0 有关 2026-10-28.endive,一次通过一个应用 步骤 从1.x升级; AllSteel先行. ) (中文(简体) ).

版本数

从一个消耗性应用的感受看: 补丁 改变什么,它看不到,a 小声 添加导出, a 选项或经审查的 SDK 默认值,以及 a 主要 更改 API 版本或其他应用程序可以查看的任何东西 电线或返回值。 改造后将未成年人合并并自行补丁,并设有大修科供审查.

每一次发布都是在npm上进行,并且只有在维护者批准2FA后才能进行直播,因为翻新 把它装入每个舰队的应用程序.

版本与发布记录

@coderize/stripe 共发布 7 个版本,首次发布于 2026/11/04;过去 12 个月发布了 7 个版本。

版本发布日期距今
2.3.0latest2026/11/073 天前
2.2.02026/11/045 天前
2.1.02026/11/046 天前
2.0.02026/11/046 天前
1.0.12026/11/046 天前
1.0.02026/11/046 天前

关于 @coderize/stripe 的常见问题

@coderize/stripe 是什么?

CoderizeDEV应用程序的共享花纹构件:被绑定的API版本,客户端,CI的版本守护,webhook基础,被移动字段的阅读器和浏览器安全卡费毛起

如何安装 @coderize/stripe?

在项目目录运行 npm install @coderize/stripe,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:stripe(^23.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。它还提供命令行工具 coderize-stripe-check,可以用 npx coderize-stripe-check 直接运行。

@coderize/stripe 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@coderize/stripe 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@coderize/stripe 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@coderize/stripe 可以商用吗?

@coderize/stripe 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@coderize/stripe 的下载量有多少?

根据 npm 官方下载统计,@coderize/stripe 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,285 次,日均约 76 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@coderize/stripe 还在维护吗?

最新版本 2.3.0 发布于 2026/11/07(3 天前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/11/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。