Add decimal_string support with vendored Decimal type#2617
Merged
jar-stripe merged 16 commits intomasterfrom Mar 24, 2026
Merged
Add decimal_string support with vendored Decimal type#2617jar-stripe merged 16 commits intomasterfrom
jar-stripe merged 16 commits intomasterfrom
Conversation
Sources: - apps-extensibility-sdk/libs/apps-extensibility-sdk/src/stdlib/decimal.ts - apps-extensibility-sdk/libs/apps-extensibility-sdk/src/stdlib/decimal.test.ts Adapts the source for stripe-node: - Inlines brand symbol declarations (no external brand.ts dependency) - Ports tests from vitest (expectTypeOf) to Mocha/Chai - Bumps tsconfig.cjs.json target from es2017 to es2020 to allow BigInt literals (Node.js 18+ supports BigInt natively; engines field requires >=18) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
- src/Types.d.ts: Add decimal_string kind to V2RuntimeSchema union,
alongside the existing int64_string kind.
- src/V2Int64.ts: Add Decimal import and decimal_string cases to both
coercion functions:
* coerceV2RequestData: duck-type detects Decimal instances (toFixed +
isZero methods) and calls .toString() for wire format
* coerceV2ResponseData: converts string API values to Decimal instances
using Decimal.from(value)
- test/V2Decimal.spec.ts: Tests covering decimal_string deserialization,
serialization, nullable/array/object/nested structures, precision
preservation, full round-trip behavior, and int64_string non-regression.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
- src/stripe.cjs.node.ts, src/stripe.cjs.worker.ts: export Decimal so
users can do `import { Decimal } from 'stripe'` or reference it as
`require('stripe').Decimal`
- types/lib.d.ts: declare Stripe.Decimal interface + namespace (with
static from() / zero) and Stripe.RoundingMode type in the Stripe
namespace, following the same pattern as Stripe.V2.Amount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
There was a problem hiding this comment.
Pull request overview
Adds first-class support for Stripe V2 decimal_string fields by introducing a vendored arbitrary-precision Decimal implementation and integrating it into the existing V2 request/response coercion pipeline.
Changes:
- Adds a new vendored
src/Decimal.tsimplementation (BigInt coefficient × 10^exponent) plus tests. - Extends
V2RuntimeSchemawith{ kind: 'decimal_string' }and coerces request/response values viaDecimal. - Exposes
Decimalfrom the CommonJS entrypoints and updates TS declarations; bumps CJS TS target toes2020for BigInt literal support.
Reviewed changes
Copilot reviewed 7 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/Decimal.ts |
Adds vendored arbitrary-precision Decimal implementation using BigInt. |
src/Types.d.ts |
Extends V2 runtime schema union to include decimal_string. |
src/V2Int64.ts |
Adds request/response coercion logic for decimal_string using Decimal. |
src/stripe.cjs.node.ts |
Exports Decimal from the CJS node entrypoint. |
src/stripe.cjs.worker.ts |
Exports Decimal from the CJS worker entrypoint. |
types/lib.d.ts |
Adds Stripe.Decimal / Stripe.RoundingMode type surface and docs. |
tsconfig.cjs.json |
Bumps TS target to es2020 to support BigInt literals in emitted JS. |
test/Decimal.spec.ts |
Adds unit tests for Decimal parsing/arithmetic/formatting. |
test/V2Decimal.spec.ts |
Adds coercion pipeline tests for decimal_string schemas and round-trips. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…urce Schema coercion now fires for any method that has a requestSchema or responseSchema, regardless of apiMode. V1 methods without schemas are unaffected. This matches Tier 1 SDK behavior (Java, Go, .NET) which coerce decimal fields unconditionally. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
…ma for v1 and v2 methods Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
xavdid-stripe
approved these changes
Mar 24, 2026
Member
xavdid-stripe
left a comment
There was a problem hiding this comment.
couple of small things but it looks good overall!
…, error handling - Update vendored Decimal.ts with full IEEE 754-2019 rounding directions (7 modes), explicit required params on div/toFixed, round() method, rounding presets, isDecimal(), and DEFAULT_DIV_PRECISION - Inline brand symbols (no external brand.ts in stripe-node) - Add Decimal export to ESM entrypoints for CJS/ESM parity - Wrap Decimal.from() in V2Int64.ts with contextual error message - Update types/lib.d.ts to match new Decimal API surface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
… compat The stripe-node prettier version doesn't support ES2022 # private class fields. Convert to TypeScript `private readonly` to unblock formatting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
File now handles both int64_string and decimal_string coercion, so the name should reflect its broader scope. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Add eslint-disable for __brand/__stripeType naming convention - Replace ++ with += 1 and = with /= operator assignment - Replace nested ternary with if/else Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
- Replace RoundingMode.HALF_UP/HALF_EVEN with 'half-up'/'half-even' strings - Make div() and toFixed() direction param explicit (no longer optional) - Update V1 coercion test to expect coercion (v2 guard was removed) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why?
The Stripe API uses
decimal_stringfields — high-precision decimal values that travel as JSON strings on the wire to avoid floating-point loss. This PR adds aStripe.Decimaltype and bidirectional coercion so these fields are transparent to SDK users: pass aStripe.Decimalin, get aStripe.Decimalback.Coercion fires for both v1 and v2 methods. The codegen-emitted
requestSchema/responseSchemametadata drives which fields get coerced; methods without decimal fields are unaffected. TheapiMode === "v2"guard inStripeResource.tshas been removed — coercion now fires whenever a schema is present, matching Tier 1 SDK behavior (Java, Go, .NET).What?
Runtime (hand-written):
src/Decimal.ts: Vendored from the Stripe-authoredapps-extensibility-sdk. UsesBigIntcoefficient × 10^exponent for arbitrary precision with zero external dependencies. Branded TypeScript type (__decimalBrand). Frozen instances. Full arithmetic (+, -, ×, ÷), comparison, and formatting methods.src/Types.d.ts: Adds{kind: 'decimal_string'}toV2RuntimeSchemadiscriminated union.src/V2Coercion.ts: Addsdecimal_stringcoercion incoerceV2ResponseData(Decimal.from(value)) andcoerceV2RequestData(duck-type detect Decimal →.toString()). Decimal plugs into the existing int64 coercion pipeline.src/StripeResource.ts: RemovesapiMode === "v2"guard — coercion fires wheneverspec.requestSchema/spec.responseSchemais present.src/stripe.cjs.node.ts/src/stripe.cjs.worker.ts/src/stripe.esm.node.ts/src/stripe.esm.worker.ts: ExportDecimalfor both CJS and ESM consumers.types/lib.d.ts: ManualStripe.Decimalinterface declaration (instance methods + staticfrom()/zero),RoundDirection,DecimalRoundingOptions,DecimalRoundingPresets,isDecimal(),DEFAULT_DIV_PRECISION.tsconfig.cjs.json: Bumpedtargetfromes2017toes2020for BigInt literal support.Generated:
decimal_stringfields in request params or response (v1 and v2) now emitrequestSchema/responseSchemaentries with{kind: 'decimal_string'}.primitiveDecimalTypechanged fromstringtoDecimal, so TypeScript types useStripe.Decimalinstead ofstringfor these fields.See Also
Changelog
decimal_stringfields changed type fromstringtoStripe.Decimalin both request params and response objects. Code that reads or writes these fields asstringwill need to useStripe.Decimalinstead (construct viaDecimal.from("1.23"), serialize via.toString()). Affected fields across v1 and v2 APIs:currency_conversion.fx_ratemetric_tons; Climate.Product:metric_tons_availableunit_amount_decimalquantity_decimal,unit_amount_decimalquantity_decimal,unit_amount_decimalquantity_decimal,unit_cost_decimal,gross_amount_decimal,local_amount_decimal,national_amount_decimalamount_decimal,flat_amount_decimal,unit_amount_decimalunit_amount_decimal,flat_amount_decimal(includingcurrency_optionsandtiers)percent_ownershipunit_amount_decimal,flat_amount_decimal,quantity_decimal(where applicable)