@boelabs/billete-sdk 0.3.0

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.
@@ -0,0 +1,568 @@
1
+ //#region ../contracts/src/environment.d.ts
2
+ /**
3
+ * Environments and the credentials that name them. Kept free of runtime dependencies: the public
4
+ * SDK bundles this module to check API keys.
5
+ */
6
+ /**
7
+ * Where an account operates. `test` is always available and moves no money; `production`
8
+ * charges for real. Every resource carries it, and secret keys name it: `sk_test_`, `sk_prod_`.
9
+ */
10
+ declare const ENVIRONMENTS: readonly ["test", "production"];
11
+ type Environment = (typeof ENVIRONMENTS)[number];
12
+ /** Credentials that name their environment: secret keys and customer session tokens. */
13
+ type TokenKind = "sk" | "cst";
14
+ /** The prefix of a token for an environment, e.g. `sk_prod_`. */
15
+ declare function tokenPrefix(kind: TokenKind, environment: Environment): string;
16
+ /**
17
+ * The environment a token belongs to by its prefix, or `null` when it is not that kind of token.
18
+ */
19
+ declare function tokenEnvironment(kind: TokenKind, token: string): Environment | null;
20
+ //#endregion
21
+ //#region ../contracts/src/common.d.ts
22
+ /** Currencies Billete can price in. Availability depends on the registered payment providers. */
23
+ declare const CURRENCIES: readonly ["VES", "USD", "EUR", "USDT"];
24
+ type Currency = (typeof CURRENCIES)[number];
25
+ /** Billing cycles, expressed in months, that a plan can offer. */
26
+ declare const BILLING_MONTHS: readonly [1, 3, 6, 9, 12];
27
+ type BillingMonths = (typeof BILLING_MONTHS)[number];
28
+ /** Grace periods, in days, a merchant can grant after a renewal is missed. */
29
+ declare const GRACE_PERIOD_DAYS: readonly [1, 3, 7];
30
+ type GracePeriodDays = (typeof GRACE_PERIOD_DAYS)[number];
31
+ /** `inclusive`: the price already contains the account tax. `exclusive`: tax is added on top. */
32
+ declare const TAX_BEHAVIORS: readonly ["inclusive", "exclusive"];
33
+ type TaxBehavior = (typeof TAX_BEHAVIORS)[number];
34
+ type Metadata = Record<string, string>;
35
+ /** A postal address as stored and returned. */
36
+ interface Address {
37
+ line1: string;
38
+ line2?: string;
39
+ city: string;
40
+ state: string;
41
+ postalCode?: string;
42
+ /** ISO 3166-1 alpha-2. */
43
+ country: string;
44
+ }
45
+ /** An address as sent: `country` defaults to `VE`. */
46
+ interface AddressInput {
47
+ line1: string;
48
+ line2?: string;
49
+ city: string;
50
+ state: string;
51
+ postalCode?: string;
52
+ country?: string;
53
+ }
54
+ /** Venezuelan mobile operators by prefix. */
55
+ declare const MOBILE_PREFIXES: readonly [{
56
+ readonly prefix: "0412";
57
+ readonly operator: "Digitel";
58
+ }, {
59
+ readonly prefix: "0414";
60
+ readonly operator: "Movistar";
61
+ }, {
62
+ readonly prefix: "0416";
63
+ readonly operator: "Movilnet";
64
+ }, {
65
+ readonly prefix: "0422";
66
+ readonly operator: "Digitel";
67
+ }, {
68
+ readonly prefix: "0424";
69
+ readonly operator: "Movistar";
70
+ }, {
71
+ readonly prefix: "0426";
72
+ readonly operator: "Movilnet";
73
+ }];
74
+ type MobilePrefix = (typeof MOBILE_PREFIXES)[number]["prefix"];
75
+ /** Digits of a Venezuelan number in its national form: `+58 414-123.45.67` → `04141234567`. */
76
+ declare function nationalPhone(value: string): string;
77
+ /** `04141234567`: a known operator prefix and seven digits. */
78
+ declare function isMobilePhone(value: string): boolean;
79
+ /** `02121234567`: an area code starting with 02 and seven digits. */
80
+ declare function isLandlinePhone(value: string): boolean;
81
+ interface ListQuery {
82
+ /** 1-100, default 20. */
83
+ limit?: number;
84
+ cursor?: string;
85
+ }
86
+ interface List<T> {
87
+ data: T[];
88
+ /** Pass as `cursor` to fetch the next page; `null` on the last page. */
89
+ nextCursor: string | null;
90
+ }
91
+ /** ISO 8601 timestamp in UTC. */
92
+ type Timestamp = string;
93
+ //#endregion
94
+ //#region ../contracts/src/errors.d.ts
95
+ declare const API_ERROR_TYPES: readonly ["invalid_request", "authentication", "permission", "not_found", "conflict", "validation", "rate_limit", "provider", "internal"];
96
+ type ApiErrorType = (typeof API_ERROR_TYPES)[number];
97
+ interface ApiErrorBody {
98
+ type: ApiErrorType;
99
+ code: string;
100
+ message: string;
101
+ /** The request field that caused the error, when there is one. */
102
+ param?: string;
103
+ requestId?: string;
104
+ }
105
+ interface ApiErrorEnvelope {
106
+ error: ApiErrorBody;
107
+ }
108
+ /** Normalized payment failure codes, independent of the provider that produced them. */
109
+ declare const PAYMENT_FAILURE_CODES: readonly ["insufficient_funds", "payment_not_found", "amount_mismatch", "invalid_details", "declined", "provider_unavailable"];
110
+ type PaymentFailureCode = (typeof PAYMENT_FAILURE_CODES)[number];
111
+ //#endregion
112
+ //#region ../contracts/src/resources.d.ts
113
+ interface Resource<TObject extends string> {
114
+ id: string;
115
+ object: TObject;
116
+ environment: Environment;
117
+ createdAt: Timestamp;
118
+ }
119
+ interface Customer extends Resource<"customer"> {
120
+ email: string;
121
+ name: string | null;
122
+ phone: string | null;
123
+ externalId: string | null;
124
+ address: Address | null;
125
+ metadata: Metadata;
126
+ updatedAt: Timestamp;
127
+ }
128
+ declare const PRODUCT_CATEGORIES: readonly ["digital", "physical", "service", "event", "other"];
129
+ type ProductCategory = (typeof PRODUCT_CATEGORIES)[number];
130
+ /** Who performed an action: a dashboard user or an API key. */
131
+ type Actor = {
132
+ type: "user" | "api_key";
133
+ id: string;
134
+ };
135
+ interface Retirement {
136
+ retiredAt: Timestamp | null;
137
+ retiredBy: Actor | null;
138
+ retirementReason: string | null;
139
+ }
140
+ interface ProductVariant extends Retirement {
141
+ id: string;
142
+ name: string;
143
+ /** Free-form descriptors such as `{ color: "Rojo", talla: "M" }`. */
144
+ attributes: Record<string, string>;
145
+ amount: number;
146
+ /** Available units; null means unlimited. */
147
+ stock: number | null;
148
+ reserved: number;
149
+ isDefault: boolean;
150
+ active: boolean;
151
+ }
152
+ interface Product extends Resource<"product">, Retirement {
153
+ name: string;
154
+ description: string | null;
155
+ imageUrl: string | null;
156
+ category: ProductCategory;
157
+ currency: Currency;
158
+ /** Null when price and inventory belong to variants. */
159
+ amount: number | null;
160
+ stock: number | null;
161
+ reserved: number;
162
+ taxBehavior: TaxBehavior;
163
+ variants: ProductVariant[];
164
+ active: boolean;
165
+ metadata: Metadata;
166
+ updatedAt: Timestamp;
167
+ }
168
+ interface PlanPrice {
169
+ months: BillingMonths;
170
+ amount: number;
171
+ }
172
+ /**
173
+ * What a plan grants per feature key: `true`/`false` for `boolean`; a limit, or `null` for
174
+ * unlimited, for `metered` and `count`; the value itself for `number`.
175
+ */
176
+ type PlanFeatureValues = Record<string, boolean | number | null>;
177
+ interface Plan extends Resource<"plan"> {
178
+ name: string;
179
+ description: string | null;
180
+ currency: Currency;
181
+ prices: PlanPrice[];
182
+ trialDays: number;
183
+ gracePeriodDays: GracePeriodDays;
184
+ taxBehavior: TaxBehavior;
185
+ /** Marketing bullet points shown on checkout pages. */
186
+ highlights: string[];
187
+ features: PlanFeatureValues;
188
+ active: boolean;
189
+ metadata: Metadata;
190
+ updatedAt: Timestamp;
191
+ }
192
+ /**
193
+ * What a feature measures:
194
+ * - `boolean`: access, on or off (export to PDF, priority support).
195
+ * - `metered`: consumed and restored on a schedule (AI tokens, emails per day).
196
+ * - `count`: what the customer has now; it goes up and down and never resets (folders, seats).
197
+ * - `number`: a value the plan sets, with no usage (maximum upload size, days of history).
198
+ */
199
+ declare const FEATURE_TYPES: readonly ["boolean", "metered", "count", "number"];
200
+ type FeatureType = (typeof FEATURE_TYPES)[number];
201
+ /** Types whose usage is recorded with `consume`, `release` and `set`. */
202
+ declare const USAGE_FEATURE_TYPES: readonly ["metered", "count"];
203
+ /** How often a `metered` feature restores its usage. */
204
+ declare const RESET_FREQUENCIES: readonly ["billing", "day", "week", "month"];
205
+ type ResetFrequency = (typeof RESET_FREQUENCIES)[number];
206
+ /** ISO weekday: 1 is Monday, 7 is Sunday. */
207
+ type Weekday = 1 | 2 | 3 | 4 | 5 | 6 | 7;
208
+ /**
209
+ * When a `metered` feature starts over. `billing` follows each subscription's period; the others
210
+ * run on the account's clock (its time zone), at `hour`:00, every `interval` days, weeks or months
211
+ * counted from when the schedule was set.
212
+ */
213
+ type FeatureReset = {
214
+ every: "billing";
215
+ } | {
216
+ every: "day";
217
+ interval: number;
218
+ hour: number;
219
+ } | {
220
+ every: "week";
221
+ interval: number;
222
+ hour: number;
223
+ weekday: Weekday;
224
+ } | {
225
+ every: "month";
226
+ interval: number;
227
+ hour: number;
228
+ day: number;
229
+ };
230
+ interface Feature extends Resource<"feature"> {
231
+ key: string;
232
+ name: string;
233
+ type: FeatureType;
234
+ /** What is counted, for display (`tokens`, `carpetas`, `MB`). */
235
+ unit: string | null;
236
+ /** Only for `metered`; `null` otherwise. */
237
+ reset: FeatureReset | null;
238
+ /**
239
+ * Next restore of a clock-based schedule; `null` for `billing` (it depends on each subscription)
240
+ * and for the other types.
241
+ */
242
+ nextResetAt: Timestamp | null;
243
+ }
244
+ /** What a customer can do with a feature right now, across all of their ongoing subscriptions. */
245
+ interface CustomerFeature {
246
+ key: string;
247
+ name: string;
248
+ type: FeatureType;
249
+ unit: string | null;
250
+ enabled: boolean;
251
+ /** `metered` and `count`: the limit, `null` meaning unlimited. `null` for the other types. */
252
+ limit: number | null;
253
+ /** `number`: the granted value (`null` when no plan grants it). `null` for the other types. */
254
+ value: number | null;
255
+ used: number;
256
+ /** `null` when unlimited or not a usage type. */
257
+ remaining: number | null;
258
+ /** When `metered` usage restores next; `null` for the other types. */
259
+ resetsAt: Timestamp | null;
260
+ }
261
+ interface FeatureUsageResult {
262
+ /** `false` when the requested consumption would exceed the limit; usage is then unchanged. */
263
+ allowed: boolean;
264
+ feature: CustomerFeature;
265
+ }
266
+ declare const SUBSCRIPTION_STATUSES: readonly ["trialing", "active", "past_due", "canceled", "expired"];
267
+ type SubscriptionStatus = (typeof SUBSCRIPTION_STATUSES)[number];
268
+ interface SubscriptionRenewal {
269
+ /** `upcoming`: not payable yet. `due`: payable before `dueAt`. `overdue`: in the grace period. */
270
+ status: "upcoming" | "due" | "overdue";
271
+ opensAt: Timestamp;
272
+ dueAt: Timestamp;
273
+ graceEndsAt: Timestamp;
274
+ /** Whole days left until access is lost (`dueAt` or, when overdue, `graceEndsAt`). */
275
+ daysRemaining: number;
276
+ amount: number;
277
+ currency: Currency;
278
+ checkoutId: string | null;
279
+ checkoutUrl: string | null;
280
+ }
281
+ interface Subscription extends Resource<"subscription"> {
282
+ customerId: string;
283
+ planId: string;
284
+ status: SubscriptionStatus;
285
+ months: BillingMonths;
286
+ amount: number;
287
+ currency: Currency;
288
+ currentPeriodStart: Timestamp;
289
+ currentPeriodEnd: Timestamp;
290
+ trialEndsAt: Timestamp | null;
291
+ cancelAtPeriodEnd: boolean;
292
+ canceledAt: Timestamp | null;
293
+ endedAt: Timestamp | null;
294
+ /** A plan or cycle change that takes effect on the next renewal. */
295
+ pendingChange: {
296
+ planId: string;
297
+ months: BillingMonths;
298
+ } | null;
299
+ renewal: SubscriptionRenewal | null;
300
+ metadata: Metadata;
301
+ updatedAt: Timestamp;
302
+ }
303
+ interface Coupon extends Resource<"coupon"> {
304
+ code: string;
305
+ name: string | null;
306
+ percentOff: number | null;
307
+ amountOff: number | null;
308
+ currency: Currency | null;
309
+ /** `forever` keeps discounting every renewal of a subscription bought with it. */
310
+ duration: "once" | "forever";
311
+ appliesTo: "all" | "products" | "plans";
312
+ maxRedemptions: number | null;
313
+ redemptions: number;
314
+ expiresAt: Timestamp | null;
315
+ active: boolean;
316
+ }
317
+ interface CollectSettings {
318
+ name: boolean;
319
+ phone: boolean;
320
+ address: boolean;
321
+ }
322
+ interface CustomField {
323
+ key: string;
324
+ label: string;
325
+ type: "text" | "number" | "select";
326
+ required: boolean;
327
+ options: string[] | null;
328
+ }
329
+ type AfterCompletion = {
330
+ type: "message";
331
+ message: string | null;
332
+ } | {
333
+ type: "redirect";
334
+ url: string;
335
+ };
336
+ declare const SUBMIT_LABELS: readonly ["pay", "subscribe", "book", "donate"];
337
+ type SubmitLabel = (typeof SUBMIT_LABELS)[number];
338
+ interface QuantitySettings {
339
+ adjustable: boolean;
340
+ min: number;
341
+ max: number;
342
+ }
343
+ interface PaymentLink extends Resource<"payment_link">, Retirement {
344
+ url: string;
345
+ type: "product" | "plan";
346
+ productId: string | null;
347
+ /** Variants offered for a product link; `null` offers every active variant. */
348
+ variantIds: string[] | null;
349
+ quantity: QuantitySettings | null;
350
+ planId: string | null;
351
+ /** Billing cycles offered for a plan link; `null` offers every plan price. */
352
+ months: BillingMonths[] | null;
353
+ collect: CollectSettings;
354
+ customFields: CustomField[];
355
+ allowCoupons: boolean;
356
+ submitLabel: SubmitLabel;
357
+ afterCompletion: AfterCompletion;
358
+ maxPayments: number | null;
359
+ paymentCount: number;
360
+ active: boolean;
361
+ metadata: Metadata;
362
+ updatedAt: Timestamp;
363
+ }
364
+ interface CheckoutItem {
365
+ type: "product" | "plan";
366
+ productId: string | null;
367
+ variantId: string | null;
368
+ planId: string | null;
369
+ months: BillingMonths | null;
370
+ name: string;
371
+ quantity: number;
372
+ unitAmount: number;
373
+ amount: number;
374
+ }
375
+ interface CustomerDetails {
376
+ name: string | null;
377
+ phone: string | null;
378
+ address: Address | null;
379
+ }
380
+ declare const CHECKOUT_PURPOSES: readonly ["product", "plan", "renewal"];
381
+ type CheckoutPurpose = (typeof CHECKOUT_PURPOSES)[number];
382
+ interface Checkout extends Resource<"checkout"> {
383
+ url: string;
384
+ purpose: CheckoutPurpose;
385
+ status: "open" | "completed" | "expired";
386
+ customerId: string | null;
387
+ email: string | null;
388
+ items: CheckoutItem[];
389
+ currency: Currency;
390
+ subtotal: number;
391
+ discount: number;
392
+ tax: number;
393
+ total: number;
394
+ taxBehavior: TaxBehavior;
395
+ /**
396
+ * Plan checkouts with a free trial: nothing is due today and the subscription starts trialing.
397
+ */
398
+ trialDays: number | null;
399
+ couponCode: string | null;
400
+ subscriptionId: string | null;
401
+ paymentLinkId: string | null;
402
+ paymentId: string | null;
403
+ collect: CollectSettings;
404
+ customFields: CustomField[];
405
+ customFieldValues: Record<string, string | number>;
406
+ customerDetails: CustomerDetails;
407
+ successUrl: string | null;
408
+ expiresAt: Timestamp;
409
+ completedAt: Timestamp | null;
410
+ metadata: Metadata;
411
+ }
412
+ declare const RISK_LEVELS: readonly ["normal", "elevated", "high"];
413
+ type RiskLevel = (typeof RISK_LEVELS)[number];
414
+ interface PaymentFailure {
415
+ code: PaymentFailureCode;
416
+ message: string;
417
+ providerCode: string | null;
418
+ }
419
+ interface PaymentAttempt {
420
+ id: string;
421
+ status: "pending" | "succeeded" | "failed";
422
+ method: string;
423
+ amount: number;
424
+ currency: Currency;
425
+ exchangeRate: string | null;
426
+ providerReference: string | null;
427
+ failure: PaymentFailure | null;
428
+ createdAt: Timestamp;
429
+ completedAt: Timestamp | null;
430
+ }
431
+ declare const PAYMENT_STATUSES: readonly ["pending", "failed", "succeeded", "refunded", "partially_refunded"];
432
+ type PaymentStatus = (typeof PAYMENT_STATUSES)[number];
433
+ /** How the money actually moved: the charged currency, conversion, Billete fee and merchant net. */
434
+ interface PaymentSettlement {
435
+ amount: number;
436
+ currency: Currency;
437
+ exchangeRate: string | null;
438
+ fee: number;
439
+ net: number;
440
+ }
441
+ interface Payment extends Resource<"payment"> {
442
+ checkoutId: string;
443
+ customerId: string;
444
+ subscriptionId: string | null;
445
+ status: PaymentStatus;
446
+ /** Checkout total in the price currency. */
447
+ amount: number;
448
+ currency: Currency;
449
+ tax: number;
450
+ settlement: PaymentSettlement | null;
451
+ amountRefunded: number;
452
+ method: string | null;
453
+ /** Masked, display-safe payment details (bank, last phone digits…). */
454
+ methodDetails: Record<string, string> | null;
455
+ failure: PaymentFailure | null;
456
+ risk: {
457
+ level: RiskLevel;
458
+ reasons: string[];
459
+ };
460
+ origin: {
461
+ ip: string | null;
462
+ userAgent: string | null;
463
+ };
464
+ attempts: PaymentAttempt[];
465
+ metadata: Metadata;
466
+ succeededAt: Timestamp | null;
467
+ updatedAt: Timestamp;
468
+ }
469
+ interface Refund extends Resource<"refund"> {
470
+ paymentId: string;
471
+ amount: number;
472
+ currency: Currency;
473
+ reason: string | null;
474
+ /** `manual`: the method cannot refund automatically; the merchant returned the funds. */
475
+ mode: "provider" | "manual";
476
+ status: "pending" | "succeeded" | "failed";
477
+ }
478
+ interface BalanceAmount {
479
+ amount: number;
480
+ currency: Currency;
481
+ }
482
+ interface Balance {
483
+ object: "balance";
484
+ environment: Environment;
485
+ /** Funds that can be paid out. */
486
+ available: BalanceAmount[];
487
+ /** Funds still inside the settlement hold. */
488
+ pending: BalanceAmount[];
489
+ }
490
+ interface Payout extends Resource<"payout"> {
491
+ amount: number;
492
+ currency: Currency;
493
+ status: "pending" | "in_transit" | "paid" | "failed" | "canceled";
494
+ automatic: boolean;
495
+ arrivalAt: Timestamp | null;
496
+ failureMessage: string | null;
497
+ }
498
+ interface WebhookEndpoint extends Resource<"webhook_endpoint"> {
499
+ url: string;
500
+ events: string[];
501
+ enabled: boolean;
502
+ /** Returned only when the endpoint is created. */
503
+ secret?: string;
504
+ }
505
+ interface Event<TData = Record<string, unknown>> extends Resource<"event"> {
506
+ type: string;
507
+ data: TData;
508
+ }
509
+ interface ExchangeRate {
510
+ object: "exchange_rate";
511
+ base: Currency;
512
+ quote: Currency;
513
+ rate: string;
514
+ source: string;
515
+ effectiveAt: Timestamp;
516
+ }
517
+ interface CurrencyAvailability {
518
+ object: "currency";
519
+ code: Currency;
520
+ active: boolean;
521
+ /** Payment methods that can settle a price in this currency. */
522
+ methods: string[];
523
+ }
524
+ interface CustomerSession {
525
+ object: "customer_session";
526
+ token: string;
527
+ customerId: string;
528
+ expiresAt: Timestamp;
529
+ }
530
+ //#endregion
531
+ //#region ../contracts/src/events.d.ts
532
+ interface EventDataMap {
533
+ "product.retired": Product;
534
+ "product.updated": Product;
535
+ "payment_link.retired": PaymentLink;
536
+ "customer.created": Customer;
537
+ "customer.updated": Customer;
538
+ "checkout.completed": Checkout;
539
+ "checkout.expired": Checkout;
540
+ "payment.succeeded": Payment;
541
+ "payment.failed": Payment;
542
+ "payment.refunded": Payment;
543
+ "refund.created": Refund;
544
+ "subscription.created": Subscription;
545
+ "subscription.updated": Subscription;
546
+ /** The renewal checkout is open; reminders start going out to the customer. */
547
+ "subscription.renewal_due": Subscription;
548
+ "subscription.renewed": Subscription;
549
+ /** The period ended unpaid; the customer keeps access until the grace period ends. */
550
+ "subscription.past_due": Subscription;
551
+ "subscription.canceled": Subscription;
552
+ /** Grace period over without payment; access is revoked. */
553
+ "subscription.expired": Subscription;
554
+ }
555
+ type EventType = keyof EventDataMap;
556
+ declare const EVENT_TYPES: readonly ["product.retired", "product.updated", "payment_link.retired", "customer.created", "customer.updated", "checkout.completed", "checkout.expired", "payment.succeeded", "payment.failed", "payment.refunded", "refund.created", "subscription.created", "subscription.updated", "subscription.renewal_due", "subscription.renewed", "subscription.past_due", "subscription.canceled", "subscription.expired"];
557
+ /** A delivered webhook, discriminated by `type` so `data` narrows automatically. */
558
+ type WebhookEvent = { [TType in EventType]: {
559
+ id: string;
560
+ object: "event";
561
+ type: TType;
562
+ environment: Environment;
563
+ createdAt: string;
564
+ data: EventDataMap[TType];
565
+ }; }[EventType];
566
+ //#endregion
567
+ export { Subscription as $, Payment as A, ENVIRONMENTS as At, Product as B, FEATURE_TYPES as C, MobilePrefix as Ct, FeatureUsageResult as D, isLandlinePhone as Dt, FeatureType as E, Timestamp as Et, PaymentStatus as F, RISK_LEVELS as G, ProductVariant as H, Payout as I, Retirement as J, Refund as K, Plan as L, PaymentFailure as M, TokenKind as Mt, PaymentLink as N, tokenEnvironment as Nt, PAYMENT_STATUSES as O, isMobilePhone as Ot, PaymentSettlement as P, tokenPrefix as Pt, SubmitLabel as Q, PlanFeatureValues as R, ExchangeRate as S, Metadata as St, FeatureReset as T, TaxBehavior as Tt, QuantitySettings as U, ProductCategory as V, RESET_FREQUENCIES as W, SUBMIT_LABELS as X, RiskLevel as Y, SUBSCRIPTION_STATUSES as Z, Customer as _, GRACE_PERIOD_DAYS as _t, Actor as a, API_ERROR_TYPES as at, CustomerSession as b, ListQuery as bt, BalanceAmount as c, ApiErrorType as ct, CheckoutItem as d, Address as dt, SubscriptionRenewal as et, CheckoutPurpose as f, AddressInput as ft, CustomField as g, Currency as gt, CurrencyAvailability as h, CURRENCIES as ht, WebhookEvent as i, Weekday as it, PaymentAttempt as j, Environment as jt, PRODUCT_CATEGORIES as k, nationalPhone as kt, CHECKOUT_PURPOSES as l, PAYMENT_FAILURE_CODES as lt, Coupon as m, BillingMonths as mt, EventDataMap as n, USAGE_FEATURE_TYPES as nt, AfterCompletion as o, ApiErrorBody as ot, CollectSettings as p, BILLING_MONTHS as pt, ResetFrequency as q, EventType as r, WebhookEndpoint as rt, Balance as s, ApiErrorEnvelope as st, EVENT_TYPES as t, SubscriptionStatus as tt, Checkout as u, PaymentFailureCode as ut, CustomerDetails as v, GracePeriodDays as vt, Feature as w, TAX_BEHAVIORS as wt, Event as x, MOBILE_PREFIXES as xt, CustomerFeature as y, List as yt, PlanPrice as z };
568
+ //# sourceMappingURL=events-BJuSt_4W.d.ts.map
@@ -0,0 +1,124 @@
1
+ //#region src/errors.ts
2
+ /** Any failed Billete request. `type`/`code` are stable and safe to branch on. */
3
+ var BilleteError = class extends Error {
4
+ type;
5
+ code;
6
+ status;
7
+ param;
8
+ requestId;
9
+ constructor(body, status) {
10
+ super(body.message);
11
+ this.name = "BilleteError";
12
+ this.type = body.type;
13
+ this.code = body.code;
14
+ this.status = status;
15
+ this.param = body.param;
16
+ this.requestId = body.requestId;
17
+ }
18
+ };
19
+ //#endregion
20
+ //#region src/http.ts
21
+ const SDK_VERSION = "0.3.0";
22
+ const DEFAULT_BASE_URL = "https://api.billete.run";
23
+ const RETRYABLE_STATUS = /* @__PURE__ */ new Set([
24
+ 429,
25
+ 500,
26
+ 502,
27
+ 503,
28
+ 504
29
+ ]);
30
+ function backoff(attempt, retryAfter) {
31
+ const seconds = retryAfter ? Number(retryAfter) : NaN;
32
+ return Number.isFinite(seconds) ? seconds * 1e3 : Math.min(500 * 2 ** attempt, 8e3);
33
+ }
34
+ function pause(ms, signal) {
35
+ return new Promise((resolve, reject) => {
36
+ const timer = setTimeout(resolve, ms);
37
+ signal?.addEventListener("abort", () => {
38
+ clearTimeout(timer);
39
+ reject(signal.reason);
40
+ }, { once: true });
41
+ });
42
+ }
43
+ function buildUrl(baseUrl, path, query) {
44
+ const url = new URL(path, baseUrl);
45
+ Object.entries(query ?? {}).filter(([, value]) => value !== void 0).forEach(([key, value]) => url.searchParams.set(key, String(value)));
46
+ return url;
47
+ }
48
+ /** A concurrent request with the same idempotency key is still running: worth retrying. */
49
+ async function inProgress(response) {
50
+ return (await response.clone().json().catch(() => null))?.error.code === "idempotency_request_in_progress";
51
+ }
52
+ async function toError(response) {
53
+ return new BilleteError((await response.json().catch(() => null))?.error ?? {
54
+ type: "internal",
55
+ code: "invalid_response",
56
+ message: `Unexpected HTTP ${response.status} from Billete`,
57
+ requestId: response.headers.get("X-Request-Id") ?? void 0
58
+ }, response.status);
59
+ }
60
+ function createTransport(options) {
61
+ const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
62
+ const fetchImpl = options.fetch ?? ((...args) => globalThis.fetch(...args));
63
+ const timeoutMs = options.timeoutMs ?? 3e4;
64
+ const maxRetries = options.maxRetries ?? 2;
65
+ async function send(request, idempotencyKey, attempt) {
66
+ const token = options.token?.();
67
+ const headers = {
68
+ Accept: "application/json",
69
+ "X-Billete-Client": `billete-js/${SDK_VERSION}`,
70
+ ...token ? { Authorization: `Bearer ${token}` } : {},
71
+ ...request.body === void 0 ? {} : { "Content-Type": "application/json" },
72
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
73
+ };
74
+ const signals = [AbortSignal.timeout(timeoutMs), request.options?.signal].filter((signal) => signal !== void 0);
75
+ const response = await fetchImpl(buildUrl(baseUrl, request.path, request.query), {
76
+ method: request.method,
77
+ headers,
78
+ body: request.body === void 0 ? void 0 : JSON.stringify(request.body),
79
+ signal: AbortSignal.any(signals)
80
+ }).catch((error) => {
81
+ if (request.options?.signal?.aborted) throw error;
82
+ return error instanceof Error ? error : new Error(String(error));
83
+ });
84
+ if ((response instanceof Error || RETRYABLE_STATUS.has(response.status) || response.status === 409 && await inProgress(response)) && attempt < maxRetries) {
85
+ await pause(backoff(attempt, response instanceof Error ? null : response.headers.get("Retry-After")), request.options?.signal);
86
+ return send(request, idempotencyKey, attempt + 1);
87
+ }
88
+ if (response instanceof Error) throw new BilleteError({
89
+ type: "network",
90
+ code: "network_error",
91
+ message: `Could not reach Billete: ${response.message}`
92
+ }, 0);
93
+ if (!response.ok) throw await toError(response);
94
+ return response.status === 204 ? void 0 : await response.json();
95
+ }
96
+ function request(request) {
97
+ return send(request, request.method === "GET" ? void 0 : request.options?.idempotencyKey ?? globalThis.crypto.randomUUID(), 0);
98
+ }
99
+ /** Walks every page of a list endpoint. */
100
+ async function* paginate(path, query = {}) {
101
+ const page = await request({
102
+ method: "GET",
103
+ path,
104
+ query
105
+ });
106
+ yield* page.data;
107
+ if (page.nextCursor) yield* paginate(path, {
108
+ ...query,
109
+ cursor: page.nextCursor
110
+ });
111
+ }
112
+ return {
113
+ request,
114
+ paginate
115
+ };
116
+ }
117
+ /** Encodes a path segment (customer references may be merchant-defined external IDs). */
118
+ function segment(value) {
119
+ return encodeURIComponent(value);
120
+ }
121
+ //#endregion
122
+ export { segment as n, BilleteError as r, createTransport as t };
123
+
124
+ //# sourceMappingURL=http-ChElV20o.js.map