@distilled.cloud/stripe 1.0.0-rc.15 → 1.0.0-rc.17

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.
Files changed (55) hide show
  1. package/lib/.lazy.json +1 -0
  2. package/lib/_bundle/lazy.js +4 -0
  3. package/lib/_bundle/sdk.js +2 -0
  4. package/lib/_bundle/sdk.js.map +1 -0
  5. package/lib/credentials.d.ts +1 -1
  6. package/lib/credentials.d.ts.map +1 -1
  7. package/lib/credentials.js +1 -31
  8. package/lib/errors.d.ts +83 -83
  9. package/lib/errors.d.ts.map +1 -1
  10. package/lib/errors.js +1 -130
  11. package/lib/index.d.ts +1 -1
  12. package/lib/index.js +1 -14
  13. package/lib/index.lazy.js +8 -0
  14. package/lib/pagination.d.ts +3 -3
  15. package/lib/pagination.js +1 -28
  16. package/lib/protocol.d.ts +12 -12
  17. package/lib/protocol.d.ts.map +1 -1
  18. package/lib/protocol.js +1 -399
  19. package/lib/retry.d.ts +1 -1
  20. package/lib/retry.d.ts.map +1 -1
  21. package/lib/retry.js +1 -32
  22. package/lib/services/index.js +0 -2
  23. package/lib/services/stripe.d.ts +507 -14141
  24. package/lib/services/stripe.d.ts.map +1 -1
  25. package/lib/services/stripe.js +918 -53147
  26. package/lib/services/stripe.js.map +1 -1
  27. package/lib/services.lazy/index.js +3 -0
  28. package/lib/services.lazy/stripe.js +4 -0
  29. package/lib/traits.d.ts +2 -2
  30. package/lib/traits.js +1 -16
  31. package/lib/webhooks.js +1 -160
  32. package/lib/webhooks.js.map +1 -1
  33. package/package.json +9 -7
  34. package/src/credentials.ts +12 -11
  35. package/src/errors.ts +89 -88
  36. package/src/index.ts +1 -1
  37. package/src/pagination.ts +3 -3
  38. package/src/protocol.ts +278 -162
  39. package/src/retry.ts +6 -4
  40. package/src/services/stripe.ts +37296 -85780
  41. package/src/traits.ts +2 -2
  42. package/src/webhooks.ts +2 -2
  43. package/lib/credentials.js.map +0 -1
  44. package/lib/errors.js.map +0 -1
  45. package/lib/pagination.js.map +0 -1
  46. package/lib/protocol.js.map +0 -1
  47. package/lib/protocol.test.d.ts +0 -2
  48. package/lib/protocol.test.d.ts.map +0 -1
  49. package/lib/protocol.test.js +0 -353
  50. package/lib/protocol.test.js.map +0 -1
  51. package/lib/retry.js.map +0 -1
  52. package/lib/services/index.js.map +0 -1
  53. package/lib/traits.js.map +0 -1
  54. package/src/protocol.test.ts +0 -519
  55. /package/lib/{index.js.map → index.lazy.js.map} +0 -0
package/lib/pagination.js CHANGED
@@ -1,28 +1 @@
1
- /**
2
- * Stripe pagination — hand-written.
3
- *
4
- * Only the GET …/search operations paginate (v0 parity): the converter
5
- * detects them as `mode: "page"` (inputToken `page`, outputToken
6
- * `next_page`, items `data`), but Stripe's `page` parameter is an OPAQUE
7
- * CURSOR — `next_page` is the next cursor string, not a page number — so
8
- * "page" mode traverses by following the cursor, exactly core's
9
- * `paginateCursor` semantics.
10
- *
11
- * Stripe's regular list endpoints (starting_after / ending_before +
12
- * has_more) are plain operations without the paginated surface, mirroring
13
- * distilled v0.
14
- */
15
- import * as Pagination from "@distilled.cloud/core/pagination";
16
- /** Dispatch on the operation's pagination mode, Stripe-style. */
17
- export const stripeSearchPaginate = (operation, input, pagination) => {
18
- switch (pagination.mode) {
19
- case "page":
20
- // Stripe search: `page` is a cursor, `next_page` the next cursor.
21
- return Pagination.paginateCursor(operation, input, pagination);
22
- case "single":
23
- return Pagination.paginateSingle(operation, input, pagination);
24
- default:
25
- return Pagination.paginateWithDefaults(operation, input, pagination);
26
- }
27
- };
28
- //# sourceMappingURL=pagination.js.map
1
+ export { pagination$stripeSearchPaginate as stripeSearchPaginate } from "./_bundle/sdk.js";
package/lib/protocol.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import * as API from "@distilled.cloud/core/api";
2
2
  import { ConfigError, type DefaultErrors as CoreDefaultErrors, BadRequest, Conflict, Forbidden, Locked, NotFound, UnprocessableEntity } from "@distilled.cloud/core/errors";
3
3
  /**
4
- * StripeProtocol — hand-written.
4
+ * StripeProtocol -- hand-written.
5
5
  *
6
6
  * Speaks Stripe's REST protocol. The generic trait helpers live in
7
7
  * `@distilled.cloud/core/protocol-http`; this module supplies what is
8
8
  * Stripe's own (ported from the distilled v0 stripe client):
9
9
  *
10
- * request: credentials → `Authorization: Bearer <apiKey>` + API base URL;
10
+ * request: credentials -> `Authorization: Bearer <apiKey>` + API base URL;
11
11
  * per-call {@link StripeRequestOptions} (resolved from the
12
- * calling fiber via {@link RequestOptions}) → Idempotency-Key /
12
+ * calling fiber via {@link RequestOptions}) -> Idempotency-Key /
13
13
  * Stripe-Account / Stripe-Context / Stripe-Version headers;
14
14
  * GET inputs flatten body-bound members into the query string
15
15
  * with Stripe bracket notation (`created[gte]`, `expand[]`);
@@ -20,20 +20,20 @@ import { ConfigError, type DefaultErrors as CoreDefaultErrors, BadRequest, Confl
20
20
  * as JSON otherwise (the /v2 ops), and as multipart form-data
21
21
  * for `contentType: "multipart"` (POST /v1/files)
22
22
  *
23
- * response: 2xx JSON is the payload (no envelope) → wire→TS key mapping →
23
+ * response: 2xx JSON is the payload (no envelope) -> wire->TS key mapping ->
24
24
  * Redacted wrapping of sensitive members; failures parse the
25
- * `{ error: { type, code, message, … } }` envelope and dispatch
25
+ * `{ error: { type, code, message, ... } }` envelope and dispatch
26
26
  * by per-op matcher classes first (`matchTypedError`, e.g.
27
- * ProductHasPrices), then `error.type` (card_error → CardError,
28
- * idempotency_error → IdempotencyError, invalid_request_error →
29
- * InvalidRequestError, api_error → ApiError), then the
30
- * Stripe-specific status map (402 → PaymentError, 424 →
27
+ * ProductHasPrices), then `error.type` (card_error -> CardError,
28
+ * idempotency_error -> IdempotencyError, invalid_request_error ->
29
+ * InvalidRequestError, api_error -> ApiError), then the
30
+ * Stripe-specific status map (402 -> PaymentError, 424 ->
31
31
  * ExternalDependencyFailed), then core's HTTP status map (with
32
32
  * retryAfter hints), then UnknownStripeError.
33
33
  */
34
34
  import * as Context from "effect/Context";
35
35
  import * as Effect from "effect/Effect";
36
- import type * as HttpClient from "effect/http/HttpClient";
36
+ import * as HttpClient from "effect/http/HttpClient";
37
37
  import type * as HttpClientError from "effect/http/HttpClientError";
38
38
  import * as Layer from "effect/Layer";
39
39
  import { Credentials } from "./credentials.ts";
@@ -53,9 +53,9 @@ declare const RequestOptions_base: Context.ServiceClass<RequestOptions, "StripeR
53
53
  /**
54
54
  * Per-call request options service. distilled v0 passed these as a second
55
55
  * call argument; v1 operations take only their input, so options travel on
56
- * the calling fiber's context instead — see {@link withRequestOptions}.
56
+ * the calling fiber's context instead -- see {@link withRequestOptions}.
57
57
  */
58
- export declare class RequestOptions extends RequestOptions_base {
58
+ export declare class RequestOptions extends /*@__PURE__*/ RequestOptions_base {
59
59
  }
60
60
  /**
61
61
  * Provide {@link StripeRequestOptions} to every Stripe API call below it.
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;AACjD,OAAO,EACL,WAAW,EAGX,KAAK,aAAa,IAAI,iBAAiB,EACvC,UAAU,EACV,QAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAQ,EACR,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAatC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAGpE,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,QAAQ,EACR,SAAS,EACT,wBAAwB,EACxB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAcrB,MAAM,MAAM,2BAA2B,GACnC;IACE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAChC,GACD;IACE,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,GAAG,2BAA2B,CAAC;;AAEhC;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,mBAEnC;CAAG;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,YAAa,oBAAoB,+FACR,CAAC;AAyBzD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,gBAAgB,GAChB,mBAAmB,GACnB,QAAQ,GACR,YAAY,GACZ,wBAAwB,GACxB,kBAAkB,GAClB,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,mBAAmB,GACnB,MAAM,GACN,iBAAiB,GACjB,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,yEAAyE;AACzE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AAoXlE,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAOpD,CAAC"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,2BAA2B,CAAC;AAEjD,OAAO,EACL,WAAW,EAGX,KAAK,aAAa,IAAI,iBAAiB,EACvC,UAAU,EACV,QAAQ,EACR,SAAS,EACT,MAAM,EACN,QAAQ,EACR,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAoBtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAGpE,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,QAAQ,EACR,SAAS,EACT,wBAAwB,EACxB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAcrB,MAAM,MAAM,2BAA2B,GACnC;IACE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAChC,GACD;IACE,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,GAAG,2BAA2B,CAAC;;AAEhC;;;;GAIG;AACH,qBAAa,cACX,SAAQ,aAAa,CAAC,mBAErB;CAAG;AAEN;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,YAAa,oBAAoB,+FACR,CAAC;AAyBzD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,gBAAgB,GAChB,mBAAmB,GACnB,QAAQ,GACR,YAAY,GACZ,wBAAwB,GACxB,kBAAkB,GAClB,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,mBAAmB,GACnB,MAAM,GACN,iBAAiB,GACjB,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,yEAAyE;AACzE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AA4dlE,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAWpD,CAAC"}
package/lib/protocol.js CHANGED
@@ -1,399 +1 @@
1
- import * as API from "@distilled.cloud/core/api";
2
- import { ConfigError, HTTP_STATUS_MAP, InternalServerError, BadRequest, Conflict, Forbidden, Locked, NotFound, UnprocessableEntity, } from "@distilled.cloud/core/errors";
3
- import { buildRequest, getAnn, getProps, hasPropAnn, mapKeys, matchTypedError, nameOf, } from "@distilled.cloud/core/protocol-http";
4
- import { unwrapRedactedDeep, wrapSensitive } from "@distilled.cloud/core/protocol-rest";
5
- import { validateResponse } from "@distilled.cloud/core/response-validation";
6
- import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
7
- /**
8
- * StripeProtocol — hand-written.
9
- *
10
- * Speaks Stripe's REST protocol. The generic trait helpers live in
11
- * `@distilled.cloud/core/protocol-http`; this module supplies what is
12
- * Stripe's own (ported from the distilled v0 stripe client):
13
- *
14
- * request: credentials → `Authorization: Bearer <apiKey>` + API base URL;
15
- * per-call {@link StripeRequestOptions} (resolved from the
16
- * calling fiber via {@link RequestOptions}) → Idempotency-Key /
17
- * Stripe-Account / Stripe-Context / Stripe-Version headers;
18
- * GET inputs flatten body-bound members into the query string
19
- * with Stripe bracket notation (`created[gte]`, `expand[]`);
20
- * non-GET bodies encode as `application/x-www-form-urlencoded`
21
- * with Stripe deepObject bracket expansion (`shipping[address]
22
- * [city]=SF`, `expand[0]=data`) when the operation's `T.Http`
23
- * trait says `contentType: "form-urlencoded"` (every /v1 op),
24
- * as JSON otherwise (the /v2 ops), and as multipart form-data
25
- * for `contentType: "multipart"` (POST /v1/files)
26
- *
27
- * response: 2xx JSON is the payload (no envelope) → wire→TS key mapping →
28
- * Redacted wrapping of sensitive members; failures parse the
29
- * `{ error: { type, code, message, … } }` envelope and dispatch
30
- * by per-op matcher classes first (`matchTypedError`, e.g.
31
- * ProductHasPrices), then `error.type` (card_error → CardError,
32
- * idempotency_error → IdempotencyError, invalid_request_error →
33
- * InvalidRequestError, api_error → ApiError), then the
34
- * Stripe-specific status map (402 → PaymentError, 424 →
35
- * ExternalDependencyFailed), then core's HTTP status map (with
36
- * retryAfter hints), then UnknownStripeError.
37
- */
38
- import * as Context from "effect/Context";
39
- import * as Effect from "effect/Effect";
40
- import * as HttpBody from "effect/http/HttpBody";
41
- import * as HttpClientRequest from "effect/http/HttpClientRequest";
42
- import * as Layer from "effect/Layer";
43
- import * as Option from "effect/Option";
44
- import * as Redacted from "effect/Redacted";
45
- import { Credentials } from "./credentials.js";
46
- import { ApiError, CardError, ExternalDependencyFailed, IdempotencyError, InvalidRequestError, PaymentError, STRIPE_HTTP_STATUS_MAP, StripeParseError, UnknownStripeError, } from "./errors.js";
47
- import { bodySymbol, headerSymbol, httpSymbol, labelSymbol, querySymbol, } from "./traits.js";
48
- /**
49
- * Per-call request options service. distilled v0 passed these as a second
50
- * call argument; v1 operations take only their input, so options travel on
51
- * the calling fiber's context instead — see {@link withRequestOptions}.
52
- */
53
- export class RequestOptions extends Context.Service()("StripeRequestOptions") {
54
- }
55
- /**
56
- * Provide {@link StripeRequestOptions} to every Stripe API call below it.
57
- *
58
- * @example
59
- * ```ts
60
- * yield* PostCharges({ amount: 2000, currency: "usd" }).pipe(
61
- * Stripe.withRequestOptions({ idempotencyKey: "ch-create-1" }),
62
- * );
63
- * ```
64
- */
65
- export const withRequestOptions = (options) => Effect.provide(Layer.succeed(RequestOptions, options));
66
- const stripeRequestHeaders = (options) => {
67
- const headers = {};
68
- if (options?.idempotencyKey !== undefined) {
69
- headers["Idempotency-Key"] = options.idempotencyKey;
70
- }
71
- if (options?.stripeAccount !== undefined) {
72
- headers["Stripe-Account"] = options.stripeAccount;
73
- }
74
- if (options?.stripeContext !== undefined) {
75
- headers["Stripe-Context"] = options.stripeContext;
76
- }
77
- if (options?.apiVersion !== undefined) {
78
- headers["Stripe-Version"] = options.apiVersion;
79
- }
80
- return headers;
81
- };
82
- // Bridge: Protocol.decode is typed as Effect<unknown> (no error channel), but
83
- // Stripe failures are real typed errors that an operation re-surfaces via its
84
- // `errors: [...]` list / StripeOpError annotation. Fail with the instance and
85
- // erase the error type here; the generated annotations reintroduce it.
86
- const fail = (e) => Effect.fail(e);
87
- // =============================================================================
88
- // Stripe query / form encoding (ported from distilled v0)
89
- // =============================================================================
90
- const BODYLESS = new Set(["GET", "HEAD"]);
91
- const appendQueryValue = (query, key, value) => {
92
- if (value === undefined || value === null)
93
- return;
94
- query.append(key, typeof value === "boolean" ? (value ? "true" : "false") : String(value));
95
- };
96
- /**
97
- * Stripe GET-query bracket expansion (v0's `appendStripeQuery`): arrays as
98
- * repeated `key[]` entries, nested objects as `key[nested]`, recursively.
99
- */
100
- const appendStripeQuery = (query, key, value) => {
101
- if (value === undefined || value === null)
102
- return;
103
- if (Array.isArray(value)) {
104
- for (const item of value)
105
- appendQueryValue(query, `${key}[]`, item);
106
- return;
107
- }
108
- if (typeof value === "object" && !(value instanceof Date)) {
109
- for (const [nestedKey, nestedValue] of Object.entries(value)) {
110
- appendStripeQuery(query, `${key}[${nestedKey}]`, nestedValue);
111
- }
112
- return;
113
- }
114
- appendQueryValue(query, key, value);
115
- };
116
- /**
117
- * Recursively flatten a nested object into Stripe-style bracket notation
118
- * for application/x-www-form-urlencoded encoding (v0's `flattenToFormPairs`).
119
- *
120
- * Examples:
121
- * { amount: 2000 } -> "amount=2000"
122
- * { shipping: { address: { city: "SF" } } } -> "shipping[address][city]=SF"
123
- * { expand: ["data"] } -> "expand[0]=data"
124
- * { metadata: { key: "val" } } -> "metadata[key]=val"
125
- */
126
- const flattenToFormPairs = (obj, prefix = "") => {
127
- const pairs = [];
128
- for (const [key, value] of Object.entries(obj)) {
129
- if (value === undefined || value === null)
130
- continue;
131
- const fullKey = prefix ? `${prefix}[${key}]` : key;
132
- if (Array.isArray(value)) {
133
- for (let i = 0; i < value.length; i++) {
134
- const item = value[i];
135
- if (item !== null &&
136
- item !== undefined &&
137
- typeof item === "object" &&
138
- !Array.isArray(item)) {
139
- pairs.push(...flattenToFormPairs(item, `${fullKey}[${i}]`));
140
- }
141
- else if (item !== undefined && item !== null) {
142
- pairs.push([`${fullKey}[${i}]`, String(item)]);
143
- }
144
- }
145
- }
146
- else if (typeof value === "object") {
147
- pairs.push(...flattenToFormPairs(value, fullKey));
148
- }
149
- else if (typeof value === "boolean") {
150
- pairs.push([fullKey, value ? "true" : "false"]);
151
- }
152
- else {
153
- pairs.push([fullKey, String(value)]);
154
- }
155
- }
156
- return pairs;
157
- };
158
- /** Build the urlencoded body from a nested object (Stripe deepObject style). */
159
- const buildFormUrlEncoded = (body) => {
160
- const params = new URLSearchParams();
161
- for (const [key, value] of flattenToFormPairs(body)) {
162
- params.append(key, value);
163
- }
164
- return params.toString();
165
- };
166
- // =============================================================================
167
- // Request building
168
- // =============================================================================
169
- // The protocol layer is memoized per process by `API.make`, so the build
170
- // must not capture credentials — `encode` resolves Credentials (and the
171
- // per-call RequestOptions) from the calling fiber's context on every
172
- // request. The requirement is erased at this boundary and reintroduced for
173
- // callers by the generated `StripeOpContext` annotations.
174
- const encode = ({ input, inputAst }) => Effect.gen(function* () {
175
- const resolveCredentials = yield* Credentials;
176
- const creds = yield* resolveCredentials;
177
- const options = Option.getOrUndefined(yield* Effect.serviceOption(RequestOptions));
178
- const http = getAnn(inputAst, httpSymbol);
179
- if (!http) {
180
- throw new Error("operation input is missing the Http() trait");
181
- }
182
- const baseHeaders = {
183
- Authorization: `Bearer ${Redacted.value(creds.apiKey)}`,
184
- ...stripeRequestHeaders(options),
185
- Accept: "application/json",
186
- };
187
- // Multipart (POST /v1/files): core's buildRequest speaks multipart
188
- // form-data (file parts + JSON-encoded object parts) — same behavior as
189
- // v0's buildFormData.
190
- if (http.contentType === "multipart") {
191
- return buildRequest({
192
- input: unwrapRedactedDeep(input),
193
- inputAst,
194
- baseUrl: creds.apiBaseUrl,
195
- headers: baseHeaders,
196
- });
197
- }
198
- const inputObj = (unwrapRedactedDeep(input) ?? {});
199
- const headers = { ...baseHeaders };
200
- const body = {};
201
- const query = new URLSearchParams();
202
- let uri = http.uri;
203
- const consumed = new Set();
204
- for (const prop of getProps(inputAst)) {
205
- const key = String(prop.name);
206
- consumed.add(key);
207
- const value = inputObj[key];
208
- if (value === undefined)
209
- continue;
210
- if (hasPropAnn(prop, labelSymbol)) {
211
- const token = nameOf(prop, labelSymbol);
212
- uri = uri.replace(`{${token}}`, encodeURIComponent(String(value)));
213
- }
214
- else if (hasPropAnn(prop, headerSymbol)) {
215
- headers[nameOf(prop, headerSymbol).toLowerCase()] = String(value);
216
- }
217
- else if (hasPropAnn(prop, querySymbol)) {
218
- // Stripe bracket expansion, not dotted params (`created[gte]=1`).
219
- appendStripeQuery(query, nameOf(prop, querySymbol), value);
220
- }
221
- else {
222
- body[nameOf(prop, bodySymbol)] = mapKeys(prop.type, value, "encode");
223
- }
224
- }
225
- // Input keys the schema doesn't know pass through as body fields — the
226
- // generated schemas can lag the real API, and silently dropping them
227
- // would break working callers.
228
- for (const [key, value] of Object.entries(inputObj)) {
229
- if (consumed.has(key) || value === undefined)
230
- continue;
231
- body[key] = value;
232
- }
233
- // v0's normalizeStripeGetQuery: GET inputs carry no body — flatten the
234
- // body-bound members into the query string with bracket notation.
235
- if (BODYLESS.has(http.method)) {
236
- for (const [key, value] of Object.entries(body)) {
237
- appendStripeQuery(query, key, value);
238
- }
239
- }
240
- const qs = query.toString();
241
- const url = `${creds.apiBaseUrl}${uri}${qs ? `?${qs}` : ""}`;
242
- if (process.env.DISTILLED_DEBUG_HTTP) {
243
- console.error(`[distilled] ${http.method} ${url}` +
244
- (Object.keys(body).length && !BODYLESS.has(http.method)
245
- ? ` body=${JSON.stringify(body).slice(0, 400)}`
246
- : ""));
247
- }
248
- let request = HttpClientRequest.make(http.method)(url).pipe(HttpClientRequest.setHeaders(headers));
249
- if (!BODYLESS.has(http.method) && Object.keys(body).length > 0) {
250
- request =
251
- http.contentType === "form-urlencoded"
252
- ? request.pipe(HttpClientRequest.setBody(HttpBody.text(buildFormUrlEncoded(body), "application/x-www-form-urlencoded")))
253
- : // The /v2/* operations are plain JSON.
254
- request.pipe(HttpClientRequest.bodyJsonUnsafe(body));
255
- }
256
- return request;
257
- });
258
- // =============================================================================
259
- // Response decoding / error matching (ported from v0's matchError)
260
- // =============================================================================
261
- const str = (v) => (typeof v === "string" ? v : undefined);
262
- // Structural views of the status maps for numeric lookup (the const objects'
263
- // per-status class types don't unify without widening the constructor).
264
- const stripeStatusMap = STRIPE_HTTP_STATUS_MAP;
265
- const coreStatusMap = HTTP_STATUS_MAP;
266
- /** Stripe's `{ error: { type, message, … } }` object, when present. */
267
- const stripeErrorEnvelope = (errorBody) => {
268
- const envelope = errorBody !== null && typeof errorBody === "object"
269
- ? errorBody.error
270
- : undefined;
271
- return envelope !== null && typeof envelope === "object"
272
- ? envelope
273
- : undefined;
274
- };
275
- const stripeErrorMessage = (errorBody) => {
276
- const message = stripeErrorEnvelope(errorBody)?.message;
277
- return typeof message === "string" ? message : undefined;
278
- };
279
- /**
280
- * Match a Stripe API error response to the appropriate error class.
281
- *
282
- * Stripe dispatches errors by:
283
- * 1. Per-operation matcher classes (`matchTypedError`) — see decode
284
- * 2. The `error.type` field (card_error, idempotency_error,
285
- * invalid_request_error, api_error)
286
- * 3. HTTP status code (402/424 Stripe-specific, then the core status map)
287
- */
288
- const matchStripeError = (status, errorBody, headers) => {
289
- const err = stripeErrorEnvelope(errorBody);
290
- // v0 parity: an unparseable envelope (no `error.type` string) is an
291
- // UnknownStripeError carrying the raw body.
292
- if (!err || typeof err.type !== "string") {
293
- return new UnknownStripeError({ body: errorBody });
294
- }
295
- const common = {
296
- message: str(err.message),
297
- code: str(err.code),
298
- doc_url: str(err.doc_url),
299
- request_log_url: str(err.request_log_url),
300
- };
301
- // Match by Stripe error type first for richer error info.
302
- switch (err.type) {
303
- case "card_error":
304
- return new CardError({
305
- ...common,
306
- decline_code: str(err.decline_code),
307
- charge: str(err.charge),
308
- param: str(err.param),
309
- advice_code: str(err.advice_code),
310
- network_advice_code: str(err.network_advice_code),
311
- network_decline_code: str(err.network_decline_code),
312
- payment_method_type: str(err.payment_method_type),
313
- });
314
- case "idempotency_error":
315
- return new IdempotencyError(common);
316
- case "invalid_request_error":
317
- return new InvalidRequestError({ ...common, param: str(err.param) });
318
- case "api_error":
319
- return new ApiError({ ...common, param: str(err.param) });
320
- }
321
- // Fall back to Stripe-specific HTTP status codes (402, 424).
322
- const StripeErrorClass = stripeStatusMap[status];
323
- if (StripeErrorClass) {
324
- return new StripeErrorClass({
325
- message: common.message,
326
- code: common.code,
327
- ...(str(err.decline_code) !== undefined ? { decline_code: str(err.decline_code) } : {}),
328
- ...(str(err.charge) !== undefined ? { charge: str(err.charge) } : {}),
329
- ...(str(err.param) !== undefined ? { param: str(err.param) } : {}),
330
- ...(common.doc_url !== undefined ? { doc_url: common.doc_url } : {}),
331
- ...(common.request_log_url !== undefined ? { request_log_url: common.request_log_url } : {}),
332
- });
333
- }
334
- // Fall back to standard HTTP status errors (400, 401, 403, 404, …).
335
- const CoreErrorClass = coreStatusMap[status];
336
- if (CoreErrorClass) {
337
- return new CoreErrorClass({
338
- message: common.message ?? "",
339
- retryAfter: parseRetryAfterForStatus(status, headers),
340
- });
341
- }
342
- // Unmapped 5xx (e.g. proxy statuses) → retryable server error (v1
343
- // convention; v0 fell through to UnknownStripeError here).
344
- if (status >= 500) {
345
- return new InternalServerError({
346
- message: common.message ?? `HTTP ${status}`,
347
- retryAfter: parseRetryAfterForStatus(status, headers),
348
- });
349
- }
350
- return new UnknownStripeError({
351
- type: str(err.type),
352
- code: common.code,
353
- message: common.message,
354
- param: str(err.param),
355
- body: errorBody,
356
- });
357
- };
358
- const decode = ({ response, outputAst, errors: errorClasses, }) => Effect.gen(function* () {
359
- // Read as text and parse tolerantly — error pages can be non-JSON.
360
- const text = (yield* response.text.pipe(Effect.orDie)) ?? "";
361
- if (process.env.DISTILLED_DEBUG_HTTP) {
362
- console.error(`[distilled] <- ${response.status} ${text.slice(0, 400)}`);
363
- }
364
- let json;
365
- let nonJson = false;
366
- if (text.trim().length > 0) {
367
- try {
368
- json = JSON.parse(text);
369
- }
370
- catch {
371
- nonJson = true;
372
- }
373
- }
374
- const status = response.status;
375
- const headers = response.headers;
376
- if (status >= 400) {
377
- const errorBody = nonJson ? text : json;
378
- const message = stripeErrorMessage(errorBody) ?? (nonJson && text.trim() ? text.trim() : `HTTP ${status}`);
379
- const typed = matchTypedError(errorClasses, status, [{ message }], {
380
- body: nonJson ? text : json,
381
- headers,
382
- });
383
- if (typed !== undefined)
384
- return yield* fail(typed);
385
- return yield* fail(matchStripeError(status, errorBody, headers));
386
- }
387
- // 2xx: the response body IS the payload (no envelope). Wire→TS key
388
- // mapping is schema-driven; sensitive members come back Redacted.
389
- // Strict mode checks the mapped body against the output schema first.
390
- const body = nonJson ? text : (json ?? {});
391
- const mapped = yield* validateResponse(outputAst, mapKeys(outputAst, body, "decode"), (cause) => new StripeParseError({ body: nonJson ? text : json, cause })).pipe(Effect.catch(fail));
392
- return wrapSensitive(outputAst, mapped);
393
- });
394
- export const StripeProtocol = Layer.succeed(API.Protocol, API.Protocol.of({
395
- // Erase encode's Credentials requirement (see comment above).
396
- encode: (args) => encode(args),
397
- decode,
398
- }));
399
- //# sourceMappingURL=protocol.js.map
1
+ export { protocol$RequestOptions as RequestOptions, protocol$StripeProtocol as StripeProtocol, protocol$withRequestOptions as withRequestOptions } from "./_bundle/sdk.js";
package/lib/retry.d.ts CHANGED
@@ -19,7 +19,7 @@ import * as Effect from "effect/Effect";
19
19
  export { type Options, type Factory, type Policy, makeDefault, jittered, capped, throttlingOptions, transientOptions, throttlingFactory, transientFactory, } from "@distilled.cloud/core/retry";
20
20
  declare const Retry_base: Context.ServiceClass<Retry, "StripeRetry", Policy>;
21
21
  /** Context tag for configuring retry behavior of Stripe API calls. */
22
- export declare class Retry extends Retry_base {
22
+ export declare class Retry extends /*@__PURE__*/ Retry_base {
23
23
  }
24
24
  /** Provides a custom retry policy to every Stripe API call below it. */
25
25
  export declare const policy: (optionsOrFactory: Policy) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAuC,MAAM,6BAA6B,CAAC;AAC/F;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,WAAW,EACX,QAAQ,EACR,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;;AAErC,sEAAsE;AACtE,qBAAa,KAAM,SAAQ,UAA+C;CAAG;AAE7E,wEAAwE;AACxE,eAAO,MAAM,MAAM,qBAAsB,MAAM,sFACS,CAAC;AAEzD,sCAAsC;AACtC,eAAO,MAAM,IAAI,mFAA+D,CAAC;AAEjF,kFAAkF;AAClF,eAAO,MAAM,UAAU,mFAA4B,CAAC;AAEpD,oFAAoF;AACpF,eAAO,MAAM,SAAS,mFAA2B,CAAC"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAuC,MAAM,6BAA6B,CAAC;AAC/F;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,WAAW,EACX,QAAQ,EACR,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;;AAErC,sEAAsE;AACtE,qBAAa,KAAM,SAAQ,aAAa,CAAC,UAA+C;CAAG;AAE3F,wEAAwE;AACxE,eAAO,MAAM,MAAM,qBAAsB,MAAM,sFACS,CAAC;AAEzD,sCAAsC;AACtC,eAAO,MAAM,IAAI,mFAEhB,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,UAAU,mFAA0C,CAAC;AAElE,oFAAoF;AACpF,eAAO,MAAM,SAAS,mFAAyC,CAAC"}
package/lib/retry.js CHANGED
@@ -1,32 +1 @@
1
- import { throttlingFactory, transientFactory } from "@distilled.cloud/core/retry";
2
- /**
3
- * Stripe retry configuration.
4
- *
5
- * Defines the per-SDK `Retry` Context.Service tag that generated operations
6
- * wire into `API.make`. Callers can install a blanket retry policy at the
7
- * layer level and have every Stripe API call below it pick it up:
8
- *
9
- * @example
10
- * ```ts
11
- * import * as Stripe from "@distilled.cloud/stripe";
12
- *
13
- * myEffect.pipe(Stripe.Retry.transient);
14
- * Effect.provide(myEffect, Layer.succeed(Stripe.Retry.Retry, customPolicy));
15
- * ```
16
- */
17
- import * as Context from "effect/Context";
18
- import * as Effect from "effect/Effect";
19
- import * as Layer from "effect/Layer";
20
- export { makeDefault, jittered, capped, throttlingOptions, transientOptions, throttlingFactory, transientFactory, } from "@distilled.cloud/core/retry";
21
- /** Context tag for configuring retry behavior of Stripe API calls. */
22
- export class Retry extends Context.Service()("StripeRetry") {
23
- }
24
- /** Provides a custom retry policy to every Stripe API call below it. */
25
- export const policy = (optionsOrFactory) => Effect.provide(Layer.succeed(Retry, optionsOrFactory));
26
- /** Disables all automatic retries. */
27
- export const none = Effect.provide(Layer.succeed(Retry, { while: () => false }));
28
- /** Apply the throttling retry policy (retries throttling errors indefinitely). */
29
- export const throttling = policy(throttlingFactory);
30
- /** Apply the transient retry policy (retries all transient errors indefinitely). */
31
- export const transient = policy(transientFactory);
32
- //# sourceMappingURL=retry.js.map
1
+ export { retry$Retry as Retry, retry$capped as capped, retry$jittered as jittered, retry$makeDefault as makeDefault, retry$none as none, retry$policy as policy, retry$throttling as throttling, retry$throttlingFactory as throttlingFactory, retry$throttlingOptions as throttlingOptions, retry$transient as transient, retry$transientFactory as transientFactory, retry$transientOptions as transientOptions } from "./_bundle/sdk.js";
@@ -1,3 +1 @@
1
- // AUTO-GENERATED by scripts/generate.ts. Do not edit.
2
1
  export * as stripe from "./stripe.js";
3
- //# sourceMappingURL=index.js.map