@distilled.cloud/stripe 1.0.0-rc.13 → 1.0.0-rc.14

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 (44) hide show
  1. package/lib/credentials.d.ts +2 -2
  2. package/lib/credentials.d.ts.map +1 -1
  3. package/lib/credentials.js +2 -2
  4. package/lib/credentials.js.map +1 -1
  5. package/lib/errors.d.ts +1 -1
  6. package/lib/errors.d.ts.map +1 -1
  7. package/lib/errors.js +1 -1
  8. package/lib/errors.js.map +1 -1
  9. package/lib/protocol.d.ts +3 -3
  10. package/lib/protocol.d.ts.map +1 -1
  11. package/lib/protocol.js +13 -18
  12. package/lib/protocol.js.map +1 -1
  13. package/lib/protocol.test.d.ts +2 -0
  14. package/lib/protocol.test.d.ts.map +1 -0
  15. package/lib/protocol.test.js +353 -0
  16. package/lib/protocol.test.js.map +1 -0
  17. package/lib/retry.d.ts +1 -1
  18. package/lib/retry.d.ts.map +1 -1
  19. package/lib/retry.js +1 -1
  20. package/lib/retry.js.map +1 -1
  21. package/lib/services/stripe.d.ts +4970 -1571
  22. package/lib/services/stripe.d.ts.map +1 -1
  23. package/lib/services/stripe.js +5608 -6855
  24. package/lib/services/stripe.js.map +1 -1
  25. package/lib/traits.d.ts.map +1 -1
  26. package/lib/traits.js +1 -1
  27. package/lib/traits.js.map +1 -1
  28. package/lib/webhooks.d.ts.map +1 -1
  29. package/lib/webhooks.js +4 -4
  30. package/lib/webhooks.js.map +1 -1
  31. package/package.json +12 -10
  32. package/src/credentials.ts +6 -7
  33. package/src/errors.ts +20 -29
  34. package/src/protocol.test.ts +519 -0
  35. package/src/protocol.ts +54 -104
  36. package/src/retry.ts +2 -8
  37. package/src/services/stripe.ts +40402 -47044
  38. package/src/traits.ts +1 -4
  39. package/src/webhooks.ts +11 -30
  40. package/lib/response-validation.test.d.ts +0 -4
  41. package/lib/response-validation.test.d.ts.map +0 -1
  42. package/lib/response-validation.test.js +0 -38
  43. package/lib/response-validation.test.js.map +0 -1
  44. package/src/response-validation.test.ts +0 -52
package/src/protocol.ts CHANGED
@@ -1,3 +1,28 @@
1
+ import * as API from "@distilled.cloud/core/api";
2
+ import {
3
+ ConfigError,
4
+ HTTP_STATUS_MAP,
5
+ InternalServerError,
6
+ type DefaultErrors as CoreDefaultErrors,
7
+ BadRequest,
8
+ Conflict,
9
+ Forbidden,
10
+ Locked,
11
+ NotFound,
12
+ UnprocessableEntity,
13
+ } from "@distilled.cloud/core/errors";
14
+ import {
15
+ buildRequest,
16
+ getAnn,
17
+ getProps,
18
+ hasPropAnn,
19
+ mapKeys,
20
+ matchTypedError,
21
+ nameOf,
22
+ } from "@distilled.cloud/core/protocol-http";
23
+ import { unwrapRedactedDeep, wrapSensitive } from "@distilled.cloud/core/protocol-rest";
24
+ import { validateResponse } from "@distilled.cloud/core/response-validation";
25
+ import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
1
26
  /**
2
27
  * StripeProtocol — hand-written.
3
28
  *
@@ -31,43 +56,15 @@
31
56
  */
32
57
  import * as Context from "effect/Context";
33
58
  import * as Effect from "effect/Effect";
34
- import * as Layer from "effect/Layer";
35
- import * as Option from "effect/Option";
36
- import * as Redacted from "effect/Redacted";
37
- import type * as AST from "effect/SchemaAST";
59
+ import * as HttpBody from "effect/http/HttpBody";
38
60
  import type * as HttpClient from "effect/http/HttpClient";
39
61
  import type * as HttpClientError from "effect/http/HttpClientError";
40
- import * as HttpBody from "effect/http/HttpBody";
41
62
  import * as HttpClientRequest from "effect/http/HttpClientRequest";
42
63
  import type * as HttpClientResponse from "effect/http/HttpClientResponse";
43
- import * as API from "@distilled.cloud/core/api";
44
- import {
45
- buildRequest,
46
- getAnn,
47
- getProps,
48
- hasPropAnn,
49
- mapKeys,
50
- matchTypedError,
51
- nameOf,
52
- } from "@distilled.cloud/core/protocol-http";
53
- import {
54
- unwrapRedactedDeep,
55
- wrapSensitive,
56
- } from "@distilled.cloud/core/protocol-rest";
57
- import {
58
- ConfigError,
59
- HTTP_STATUS_MAP,
60
- InternalServerError,
61
- type DefaultErrors as CoreDefaultErrors,
62
- BadRequest,
63
- Conflict,
64
- Forbidden,
65
- Locked,
66
- NotFound,
67
- UnprocessableEntity,
68
- } from "@distilled.cloud/core/errors";
69
- import { validateResponse } from "@distilled.cloud/core/response-validation";
70
- import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
64
+ import * as Layer from "effect/Layer";
65
+ import * as Option from "effect/Option";
66
+ import * as Redacted from "effect/Redacted";
67
+ import type * as AST from "effect/SchemaAST";
71
68
  import { Credentials, type Config } from "./credentials.ts";
72
69
  import {
73
70
  ApiError,
@@ -113,10 +110,9 @@ export type StripeRequestOptions = {
113
110
  * call argument; v1 operations take only their input, so options travel on
114
111
  * the calling fiber's context instead — see {@link withRequestOptions}.
115
112
  */
116
- export class RequestOptions extends Context.Service<
117
- RequestOptions,
118
- StripeRequestOptions
119
- >()("StripeRequestOptions") {}
113
+ export class RequestOptions extends Context.Service<RequestOptions, StripeRequestOptions>()(
114
+ "StripeRequestOptions",
115
+ ) {}
120
116
 
121
117
  /**
122
118
  * Provide {@link StripeRequestOptions} to every Stripe API call below it.
@@ -186,8 +182,7 @@ export type StripeOpContext = Credentials | HttpClient.HttpClient;
186
182
  // Stripe failures are real typed errors that an operation re-surfaces via its
187
183
  // `errors: [...]` list / StripeOpError annotation. Fail with the instance and
188
184
  // erase the error type here; the generated annotations reintroduce it.
189
- const fail = (e: unknown): Effect.Effect<never> =>
190
- Effect.fail(e) as Effect.Effect<never>;
185
+ const fail = (e: unknown): Effect.Effect<never> => Effect.fail(e) as Effect.Effect<never>;
191
186
 
192
187
  // =============================================================================
193
188
  // Stripe query / form encoding (ported from distilled v0)
@@ -195,36 +190,23 @@ const fail = (e: unknown): Effect.Effect<never> =>
195
190
 
196
191
  const BODYLESS = new Set(["GET", "HEAD"]);
197
192
 
198
- const appendQueryValue = (
199
- query: URLSearchParams,
200
- key: string,
201
- value: unknown,
202
- ): void => {
193
+ const appendQueryValue = (query: URLSearchParams, key: string, value: unknown): void => {
203
194
  if (value === undefined || value === null) return;
204
- query.append(
205
- key,
206
- typeof value === "boolean" ? (value ? "true" : "false") : String(value),
207
- );
195
+ query.append(key, typeof value === "boolean" ? (value ? "true" : "false") : String(value));
208
196
  };
209
197
 
210
198
  /**
211
199
  * Stripe GET-query bracket expansion (v0's `appendStripeQuery`): arrays as
212
200
  * repeated `key[]` entries, nested objects as `key[nested]`, recursively.
213
201
  */
214
- const appendStripeQuery = (
215
- query: URLSearchParams,
216
- key: string,
217
- value: unknown,
218
- ): void => {
202
+ const appendStripeQuery = (query: URLSearchParams, key: string, value: unknown): void => {
219
203
  if (value === undefined || value === null) return;
220
204
  if (Array.isArray(value)) {
221
205
  for (const item of value) appendQueryValue(query, `${key}[]`, item);
222
206
  return;
223
207
  }
224
208
  if (typeof value === "object" && !(value instanceof Date)) {
225
- for (const [nestedKey, nestedValue] of Object.entries(
226
- value as Record<string, unknown>,
227
- )) {
209
+ for (const [nestedKey, nestedValue] of Object.entries(value as Record<string, unknown>)) {
228
210
  appendStripeQuery(query, `${key}[${nestedKey}]`, nestedValue);
229
211
  }
230
212
  return;
@@ -262,20 +244,13 @@ const flattenToFormPairs = (
262
244
  typeof item === "object" &&
263
245
  !Array.isArray(item)
264
246
  ) {
265
- pairs.push(
266
- ...flattenToFormPairs(
267
- item as Record<string, unknown>,
268
- `${fullKey}[${i}]`,
269
- ),
270
- );
247
+ pairs.push(...flattenToFormPairs(item as Record<string, unknown>, `${fullKey}[${i}]`));
271
248
  } else if (item !== undefined && item !== null) {
272
249
  pairs.push([`${fullKey}[${i}]`, String(item)]);
273
250
  }
274
251
  }
275
252
  } else if (typeof value === "object") {
276
- pairs.push(
277
- ...flattenToFormPairs(value as Record<string, unknown>, fullKey),
278
- );
253
+ pairs.push(...flattenToFormPairs(value as Record<string, unknown>, fullKey));
279
254
  } else if (typeof value === "boolean") {
280
255
  pairs.push([fullKey, value ? "true" : "false"]);
281
256
  } else {
@@ -304,19 +279,11 @@ const buildFormUrlEncoded = (body: Record<string, unknown>): string => {
304
279
  // per-call RequestOptions) from the calling fiber's context on every
305
280
  // request. The requirement is erased at this boundary and reintroduced for
306
281
  // callers by the generated `StripeOpContext` annotations.
307
- const encode = ({
308
- input,
309
- inputAst,
310
- }: {
311
- readonly input: unknown;
312
- readonly inputAst: AST.AST;
313
- }) =>
282
+ const encode = ({ input, inputAst }: { readonly input: unknown; readonly inputAst: AST.AST }) =>
314
283
  Effect.gen(function* () {
315
284
  const resolveCredentials = yield* Credentials;
316
285
  const creds = yield* resolveCredentials as Effect.Effect<Config>;
317
- const options = Option.getOrUndefined(
318
- yield* Effect.serviceOption(RequestOptions),
319
- );
286
+ const options = Option.getOrUndefined(yield* Effect.serviceOption(RequestOptions));
320
287
 
321
288
  const http = getAnn(inputAst, httpSymbol) as HttpTrait | undefined;
322
289
  if (!http) {
@@ -341,10 +308,7 @@ const encode = ({
341
308
  });
342
309
  }
343
310
 
344
- const inputObj = (unwrapRedactedDeep(input) ?? {}) as Record<
345
- string,
346
- unknown
347
- >;
311
+ const inputObj = (unwrapRedactedDeep(input) ?? {}) as Record<string, unknown>;
348
312
  const headers: Record<string, string> = { ...baseHeaders };
349
313
  const body: Record<string, unknown> = {};
350
314
  const query = new URLSearchParams();
@@ -405,10 +369,7 @@ const encode = ({
405
369
  http.contentType === "form-urlencoded"
406
370
  ? request.pipe(
407
371
  HttpClientRequest.setBody(
408
- HttpBody.text(
409
- buildFormUrlEncoded(body),
410
- "application/x-www-form-urlencoded",
411
- ),
372
+ HttpBody.text(buildFormUrlEncoded(body), "application/x-www-form-urlencoded"),
412
373
  ),
413
374
  )
414
375
  : // The /v2/* operations are plain JSON.
@@ -421,22 +382,17 @@ const encode = ({
421
382
  // Response decoding / error matching (ported from v0's matchError)
422
383
  // =============================================================================
423
384
 
424
- const str = (v: unknown): string | undefined =>
425
- typeof v === "string" ? v : undefined;
385
+ const str = (v: unknown): string | undefined => (typeof v === "string" ? v : undefined);
426
386
 
427
387
  // Structural views of the status maps for numeric lookup (the const objects'
428
388
  // per-status class types don't unify without widening the constructor).
429
- const stripeStatusMap: Readonly<
430
- Record<number, (new (args: any) => unknown) | undefined>
431
- > = STRIPE_HTTP_STATUS_MAP;
432
- const coreStatusMap: Readonly<
433
- Record<number, (new (args: any) => unknown) | undefined>
434
- > = HTTP_STATUS_MAP;
389
+ const stripeStatusMap: Readonly<Record<number, (new (args: any) => unknown) | undefined>> =
390
+ STRIPE_HTTP_STATUS_MAP;
391
+ const coreStatusMap: Readonly<Record<number, (new (args: any) => unknown) | undefined>> =
392
+ HTTP_STATUS_MAP;
435
393
 
436
394
  /** Stripe's `{ error: { type, message, … } }` object, when present. */
437
- const stripeErrorEnvelope = (
438
- errorBody: unknown,
439
- ): Record<string, unknown> | undefined => {
395
+ const stripeErrorEnvelope = (errorBody: unknown): Record<string, unknown> | undefined => {
440
396
  const envelope =
441
397
  errorBody !== null && typeof errorBody === "object"
442
398
  ? (errorBody as Record<string, unknown>).error
@@ -506,15 +462,11 @@ const matchStripeError = (
506
462
  return new StripeErrorClass({
507
463
  message: common.message,
508
464
  code: common.code,
509
- ...(str(err.decline_code) !== undefined
510
- ? { decline_code: str(err.decline_code) }
511
- : {}),
465
+ ...(str(err.decline_code) !== undefined ? { decline_code: str(err.decline_code) } : {}),
512
466
  ...(str(err.charge) !== undefined ? { charge: str(err.charge) } : {}),
513
467
  ...(str(err.param) !== undefined ? { param: str(err.param) } : {}),
514
468
  ...(common.doc_url !== undefined ? { doc_url: common.doc_url } : {}),
515
- ...(common.request_log_url !== undefined
516
- ? { request_log_url: common.request_log_url }
517
- : {}),
469
+ ...(common.request_log_url !== undefined ? { request_log_url: common.request_log_url } : {}),
518
470
  });
519
471
  }
520
472
 
@@ -575,8 +527,7 @@ const decode = ({
575
527
  if (status >= 400) {
576
528
  const errorBody: unknown = nonJson ? text : json;
577
529
  const message =
578
- stripeErrorMessage(errorBody) ??
579
- (nonJson && text.trim() ? text.trim() : `HTTP ${status}`);
530
+ stripeErrorMessage(errorBody) ?? (nonJson && text.trim() ? text.trim() : `HTTP ${status}`);
580
531
  const typed = matchTypedError(errorClasses, status, [{ message }], {
581
532
  body: nonJson ? text : json,
582
533
  headers,
@@ -601,8 +552,7 @@ export const StripeProtocol: Layer.Layer<API.Protocol> = Layer.succeed(
601
552
  API.Protocol,
602
553
  API.Protocol.of({
603
554
  // Erase encode's Credentials requirement (see comment above).
604
- encode: (args) =>
605
- encode(args) as Effect.Effect<HttpClientRequest.HttpClientRequest>,
555
+ encode: (args) => encode(args) as Effect.Effect<HttpClientRequest.HttpClientRequest>,
606
556
  decode,
607
557
  }),
608
558
  );
package/src/retry.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type Policy, throttlingFactory, transientFactory } from "@distilled.cloud/core/retry";
1
2
  /**
2
3
  * Stripe retry configuration.
3
4
  *
@@ -16,11 +17,6 @@
16
17
  import * as Context from "effect/Context";
17
18
  import * as Effect from "effect/Effect";
18
19
  import * as Layer from "effect/Layer";
19
- import {
20
- type Policy,
21
- throttlingFactory,
22
- transientFactory,
23
- } from "@distilled.cloud/core/retry";
24
20
 
25
21
  export {
26
22
  type Options,
@@ -43,9 +39,7 @@ export const policy = (optionsOrFactory: Policy) =>
43
39
  Effect.provide(Layer.succeed(Retry, optionsOrFactory));
44
40
 
45
41
  /** Disables all automatic retries. */
46
- export const none = Effect.provide(
47
- Layer.succeed(Retry, { while: () => false }),
48
- );
42
+ export const none = Effect.provide(Layer.succeed(Retry, { while: () => false }));
49
43
 
50
44
  /** Apply the throttling retry policy (retries throttling errors indefinitely). */
51
45
  export const throttling = policy(throttlingFactory);