@usebillow/sdk 0.5.0 → 0.6.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.
- package/CHANGELOG.md +11 -0
- package/README.md +9 -0
- package/dist/billing-B-VyZCXV.d.cts +371 -0
- package/dist/billing-CgjcWmvb.d.ts +371 -0
- package/dist/{chunk-Z6VXPONT.js → chunk-DYWGZRE2.js} +197 -15
- package/dist/chunk-DYWGZRE2.js.map +1 -0
- package/dist/config.d.cts +4 -3
- package/dist/config.d.ts +4 -3
- package/dist/{credits-C3Fe3TO0.d.ts → hosted-domains-BtCd-Rur.d.cts} +43 -1
- package/dist/{credits-C3Fe3TO0.d.cts → hosted-domains-CrVDsk2i.d.ts} +43 -1
- package/dist/index.cjs +195 -13
- package/dist/index.cjs.map +1 -1
- package/dist/{billing-C4RIMgH_.d.ts → index.d-CKQAhQfJ.d.cts} +180 -374
- package/dist/{billing-DZ4rIyg7.d.cts → index.d-CKQAhQfJ.d.ts} +180 -374
- package/dist/index.d.cts +547 -42
- package/dist/index.d.ts +547 -42
- package/dist/index.js +1 -1
- package/dist/ingestion.d.cts +3 -2
- package/dist/ingestion.d.ts +3 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -1
- package/dist/react.d.ts +2 -1
- package/dist/react.js +1 -1
- package/dist/server.d.cts +3 -2
- package/dist/server.d.ts +3 -2
- package/dist/webhooks.cjs +10 -2
- package/dist/webhooks.cjs.map +1 -1
- package/dist/webhooks.d.cts +37 -21
- package/dist/webhooks.d.ts +37 -21
- package/dist/webhooks.js +10 -3
- package/dist/webhooks.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-Z6VXPONT.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -133,10 +133,10 @@ function resolveBaseUrl(explicit) {
|
|
|
133
133
|
const fromEnv = typeof process !== "undefined" ? process.env?.["BILLOW_URL"] : void 0;
|
|
134
134
|
return (explicit || fromEnv || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
135
135
|
}
|
|
136
|
-
async function apiRequest(ctx, method,
|
|
137
|
-
return (await apiRequestWithStatus(ctx, method,
|
|
136
|
+
async function apiRequest(ctx, method, path2, body, options) {
|
|
137
|
+
return (await apiRequestWithStatus(ctx, method, path2, body, options)).data;
|
|
138
138
|
}
|
|
139
|
-
async function apiRequestWithStatus(ctx, method,
|
|
139
|
+
async function apiRequestWithStatus(ctx, method, path2, body, options) {
|
|
140
140
|
const init = {
|
|
141
141
|
method,
|
|
142
142
|
headers: {
|
|
@@ -146,7 +146,7 @@ async function apiRequestWithStatus(ctx, method, path, body, options) {
|
|
|
146
146
|
}
|
|
147
147
|
};
|
|
148
148
|
if (body) init.body = JSON.stringify(body);
|
|
149
|
-
const res = await sendWithResilience(ctx, `${ctx.baseUrl}${
|
|
149
|
+
const res = await sendWithResilience(ctx, `${ctx.baseUrl}${path2}`, init, {
|
|
150
150
|
timeoutMs: options?.timeoutMs ?? ctx.timeoutMs,
|
|
151
151
|
safeToRepeat: safeToRepeat(method, !!options?.idempotencyKey),
|
|
152
152
|
callerSignal: options?.signal
|
|
@@ -192,10 +192,10 @@ function errorFrom(res, data) {
|
|
|
192
192
|
requestIdOf(res)
|
|
193
193
|
);
|
|
194
194
|
}
|
|
195
|
-
async function apiRequestBinary(ctx, method,
|
|
195
|
+
async function apiRequestBinary(ctx, method, path2, options) {
|
|
196
196
|
const res = await sendWithResilience(
|
|
197
197
|
ctx,
|
|
198
|
-
`${ctx.baseUrl}${
|
|
198
|
+
`${ctx.baseUrl}${path2}`,
|
|
199
199
|
{ method, headers: { authorization: `Bearer ${ctx.bearer}` } },
|
|
200
200
|
{
|
|
201
201
|
timeoutMs: options?.timeoutMs ?? ctx.timeoutMs,
|
|
@@ -534,11 +534,14 @@ function createCreditsResource(ctx) {
|
|
|
534
534
|
* checkout to send the buyer to. Credits are granted when the payment succeeds (listen for
|
|
535
535
|
* `credit_top_up.succeeded`). The `idempotencyKey` is required and must identify this one
|
|
536
536
|
* purchase: a retry under it answers the same top-up as it now stands (`replayed: true`) and
|
|
537
|
-
* buys nothing again
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
537
|
+
* buys nothing again - asking the payment provider again for a checkout the first attempt
|
|
538
|
+
* could not open, within its page's 40 minutes (Stripe only in the first 10, while 30
|
|
539
|
+
* remain: it answers a timed-out first attempt with the checkout it made, or makes one never
|
|
540
|
+
* made; Paymob only if the first attempt never made one); reusing it for another purchase
|
|
541
|
+
* throws `idempotency_conflict` (409). A retry can also throw `conflict` (409), with
|
|
542
|
+
* `details.reason`: `checkout_in_progress` - another request is still opening the
|
|
543
|
+
* checkout, so retry the same key shortly - or `checkout_unavailable` - its checkout could
|
|
544
|
+
* not be opened and never will be, so buy again under a new key.
|
|
542
545
|
*/
|
|
543
546
|
create: async (input, options) => {
|
|
544
547
|
const { status, data } = await apiRequestWithStatus(
|
|
@@ -620,6 +623,155 @@ function createCreditsResource(ctx) {
|
|
|
620
623
|
void 0,
|
|
621
624
|
options
|
|
622
625
|
)
|
|
626
|
+
},
|
|
627
|
+
rateCards: {
|
|
628
|
+
/**
|
|
629
|
+
* Publish a new Rate Card version: what each Credit Action costs, as
|
|
630
|
+
* `ceil(units * unitPrice / perUnits)` microcredits a line. Versions are immutable - a price
|
|
631
|
+
* change is a new version - and take effect in order, at `effectiveAt` (now when omitted).
|
|
632
|
+
*/
|
|
633
|
+
publish: (input, options) => apiRequest(ctx, "POST", "/v1/credits/rate-cards", input, options),
|
|
634
|
+
/** The version in effect now (`not_found` before the first takes effect). */
|
|
635
|
+
current: (options) => apiRequest(
|
|
636
|
+
ctx,
|
|
637
|
+
"GET",
|
|
638
|
+
"/v1/credits/rate-cards/current",
|
|
639
|
+
void 0,
|
|
640
|
+
options
|
|
641
|
+
),
|
|
642
|
+
/** One version, by its number. */
|
|
643
|
+
get: (version, options) => apiRequest(
|
|
644
|
+
ctx,
|
|
645
|
+
"GET",
|
|
646
|
+
`/v1/credits/rate-cards/${encodeURIComponent(String(version))}`,
|
|
647
|
+
void 0,
|
|
648
|
+
options
|
|
649
|
+
),
|
|
650
|
+
/**
|
|
651
|
+
* The published versions, newest first. Auto-paginating by cursor: `await` the first page,
|
|
652
|
+
* `for await (…)` every version, or `.listAll()` to collect them.
|
|
653
|
+
*/
|
|
654
|
+
list: (params = {}, options) => makeCursorListPromise(
|
|
655
|
+
(p) => apiRequest(
|
|
656
|
+
ctx,
|
|
657
|
+
"GET",
|
|
658
|
+
`/v1/credits/rate-cards${toQuery(p)}`,
|
|
659
|
+
void 0,
|
|
660
|
+
options
|
|
661
|
+
),
|
|
662
|
+
params
|
|
663
|
+
)
|
|
664
|
+
},
|
|
665
|
+
quotes: {
|
|
666
|
+
/**
|
|
667
|
+
* Price a customer's Credit Actions (all of one category) at the current Rate Card version
|
|
668
|
+
* and keep the price for 15 minutes: a reservation over the quote holds exactly its
|
|
669
|
+
* `amount`, and its commit prices at the version the quote pinned. A quote holds nothing.
|
|
670
|
+
*/
|
|
671
|
+
create: (input, options) => apiRequest(ctx, "POST", "/v1/credits/quotes", input, options),
|
|
672
|
+
/** A quote as it was made. */
|
|
673
|
+
get: (quoteId, options) => apiRequest(
|
|
674
|
+
ctx,
|
|
675
|
+
"GET",
|
|
676
|
+
`/v1/credits/quotes/${encodeURIComponent(quoteId)}`,
|
|
677
|
+
void 0,
|
|
678
|
+
options
|
|
679
|
+
)
|
|
680
|
+
},
|
|
681
|
+
reservations: {
|
|
682
|
+
/**
|
|
683
|
+
* Hold credits for one operation: over a `quoteId`, or over `items` priced at the current
|
|
684
|
+
* Rate Card version. The `idempotencyKey` is required: a retry under it - after a lost
|
|
685
|
+
* reply, even once the quote expired - answers the same reservation (`replayed: true`) and
|
|
686
|
+
* holds nothing again. Reusing it for another request, or a new key with an `operationKey`
|
|
687
|
+
* the customer already used (`details.reason: "operation_key_used"`), throws
|
|
688
|
+
* `idempotency_conflict` (409). Throws `insufficient_credits` (402), `account_frozen`
|
|
689
|
+
* (423), `account_closed` (409), `conflict` (409, `details.reason: "quote_expired"`), or
|
|
690
|
+
* `validation_error` (422) - e.g. `details.reason: "zero_amount"` when the items cost nothing.
|
|
691
|
+
* The `operationKey` is an operation id, never personal data: erasure replaces it.
|
|
692
|
+
*/
|
|
693
|
+
create: async (input, options) => {
|
|
694
|
+
const { status, data } = await apiRequestWithStatus(
|
|
695
|
+
ctx,
|
|
696
|
+
"POST",
|
|
697
|
+
"/v1/credits/reservations",
|
|
698
|
+
input,
|
|
699
|
+
options
|
|
700
|
+
);
|
|
701
|
+
return { ...data, replayed: status === 200 };
|
|
702
|
+
},
|
|
703
|
+
/** A reservation as it now stands. */
|
|
704
|
+
get: (reservationId, options) => apiRequest(
|
|
705
|
+
ctx,
|
|
706
|
+
"GET",
|
|
707
|
+
`/v1/credits/reservations/${encodeURIComponent(reservationId)}`,
|
|
708
|
+
void 0,
|
|
709
|
+
options
|
|
710
|
+
),
|
|
711
|
+
/**
|
|
712
|
+
* A customer's reservation (by external id) made with `operationKey` - how to find one whose
|
|
713
|
+
* reply was lost. Throws `not_found` (404) when there is none.
|
|
714
|
+
*/
|
|
715
|
+
findByOperationKey: (customer, operationKey, options) => apiRequest(
|
|
716
|
+
ctx,
|
|
717
|
+
"GET",
|
|
718
|
+
`/v1/credits/reservations${toQuery({ customer, operationKey })}`,
|
|
719
|
+
void 0,
|
|
720
|
+
options
|
|
721
|
+
),
|
|
722
|
+
/**
|
|
723
|
+
* Commit what the operation used: lines priced at the reservation's Rate Card version,
|
|
724
|
+
* consuming at most what it holds (`commit_exceeds_hold`, 409) and releasing the rest; lines
|
|
725
|
+
* that cost nothing in all consume nothing (`consumed: "0"`, `consumptionId: null`). The
|
|
726
|
+
* same commit again answers it again, so it is safe to retry; anything else after it throws
|
|
727
|
+
* `invalid_state_transition` (409) with the reservation in `details` - with
|
|
728
|
+
* `details.reason: "reservation_expired"` once the hold is past its `expiresAt`.
|
|
729
|
+
*/
|
|
730
|
+
commit: (reservationId, items, options) => apiRequest(
|
|
731
|
+
ctx,
|
|
732
|
+
"POST",
|
|
733
|
+
`/v1/credits/reservations/${encodeURIComponent(reservationId)}/commit`,
|
|
734
|
+
{ items },
|
|
735
|
+
options
|
|
736
|
+
),
|
|
737
|
+
/** Release the whole hold. Safe to retry; after a commit it throws (409). */
|
|
738
|
+
release: (reservationId, options) => apiRequest(
|
|
739
|
+
ctx,
|
|
740
|
+
"POST",
|
|
741
|
+
`/v1/credits/reservations/${encodeURIComponent(reservationId)}/release`,
|
|
742
|
+
void 0,
|
|
743
|
+
options
|
|
744
|
+
),
|
|
745
|
+
/**
|
|
746
|
+
* Protect a held reservation whose operation was paid for and is still being fulfilled: it
|
|
747
|
+
* never expires (commit or release it when done). Safe to retry. A hold already past its
|
|
748
|
+
* `expiresAt` throws `invalid_state_transition` (409, `details.reason: "reservation_expired"`).
|
|
749
|
+
*/
|
|
750
|
+
protect: (reservationId, options) => apiRequest(
|
|
751
|
+
ctx,
|
|
752
|
+
"POST",
|
|
753
|
+
`/v1/credits/reservations/${encodeURIComponent(reservationId)}/protect`,
|
|
754
|
+
void 0,
|
|
755
|
+
options
|
|
756
|
+
)
|
|
757
|
+
},
|
|
758
|
+
consumptions: {
|
|
759
|
+
/**
|
|
760
|
+
* Give back part or all of a commit's consumption (`consumptionId` on the committed
|
|
761
|
+
* reservation), never more than is left (`reversal_exceeds_consumption`, 409). The
|
|
762
|
+
* `idempotencyKey` is required: a retry under it answers the same reversal
|
|
763
|
+
* (`replayed: true`) and gives nothing back again.
|
|
764
|
+
*/
|
|
765
|
+
reverse: async (consumptionId, input, options) => {
|
|
766
|
+
const { status, data } = await apiRequestWithStatus(
|
|
767
|
+
ctx,
|
|
768
|
+
"POST",
|
|
769
|
+
`/v1/credits/consumptions/${encodeURIComponent(consumptionId)}/reverse`,
|
|
770
|
+
input,
|
|
771
|
+
options
|
|
772
|
+
);
|
|
773
|
+
return { ...data, replayed: status === 200 };
|
|
774
|
+
}
|
|
623
775
|
}
|
|
624
776
|
};
|
|
625
777
|
}
|
|
@@ -732,6 +884,33 @@ function createDeliverabilityResource(ctx) {
|
|
|
732
884
|
};
|
|
733
885
|
}
|
|
734
886
|
|
|
887
|
+
// src/resources/hosted-domains.ts
|
|
888
|
+
var path = (id, action = "") => `/v1/hosted-domains/${encodeURIComponent(id)}${action}`;
|
|
889
|
+
function createHostedDomainsResource(ctx) {
|
|
890
|
+
return {
|
|
891
|
+
/** The Project's domains, and whether its plan allows adding more (`whiteLabel`). */
|
|
892
|
+
list: (options) => apiRequest(ctx, "GET", "/v1/hosted-domains", void 0, options),
|
|
893
|
+
/**
|
|
894
|
+
* Add a subdomain such as `billing.example.com`. Answers the domain with the TXT and CNAME
|
|
895
|
+
* `records` to create. Needs a plan with white-label branding (`permission_denied` otherwise).
|
|
896
|
+
*/
|
|
897
|
+
create: (input, options) => apiRequest(ctx, "POST", "/v1/hosted-domains", input, options),
|
|
898
|
+
get: (id, options) => apiRequest(ctx, "GET", path(id), void 0, options),
|
|
899
|
+
/** Check the DNS records now (2 per minute per domain); answers the refreshed domain. */
|
|
900
|
+
verify: (id, options) => apiRequest(ctx, "POST", path(id, "/verify"), void 0, options),
|
|
901
|
+
/** Make an active domain the default host for new portal sessions. */
|
|
902
|
+
makePrimary: (id, options) => apiRequest(ctx, "POST", path(id, "/primary"), void 0, options),
|
|
903
|
+
/** Remove a domain; the portal sessions on it end immediately. */
|
|
904
|
+
remove: (id, options) => apiRequest(
|
|
905
|
+
ctx,
|
|
906
|
+
"DELETE",
|
|
907
|
+
path(id),
|
|
908
|
+
void 0,
|
|
909
|
+
options
|
|
910
|
+
)
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
|
|
735
914
|
// src/resources/invoices.ts
|
|
736
915
|
function createInvoicesResource(ctx) {
|
|
737
916
|
return {
|
|
@@ -1197,6 +1376,8 @@ var Billow = class {
|
|
|
1197
1376
|
portalSessions;
|
|
1198
1377
|
deliverability;
|
|
1199
1378
|
marketplace;
|
|
1379
|
+
/** Custom domains for the hosted customer portal (live keys, behind a rollout flag). */
|
|
1380
|
+
hostedDomains;
|
|
1200
1381
|
/**
|
|
1201
1382
|
* Organization settings (Phase D3, F) — the configurable dunning schedule, usage settlement grace,
|
|
1202
1383
|
* and the cross-currency reporting currency + FX-rate registry (ADR-0013).
|
|
@@ -1217,10 +1398,11 @@ var Billow = class {
|
|
|
1217
1398
|
this.portalSessions = createPortalSessionsResource(this.#ctx);
|
|
1218
1399
|
this.deliverability = createDeliverabilityResource(this.#ctx);
|
|
1219
1400
|
this.marketplace = createMarketplaceResource(this.#ctx);
|
|
1401
|
+
this.hostedDomains = createHostedDomainsResource(this.#ctx);
|
|
1220
1402
|
this.settings = createSettingsResource(this.#ctx);
|
|
1221
1403
|
}
|
|
1222
|
-
#request(method,
|
|
1223
|
-
return apiRequest(this.#ctx, method,
|
|
1404
|
+
#request(method, path2, body, options) {
|
|
1405
|
+
return apiRequest(this.#ctx, method, path2, body, options);
|
|
1224
1406
|
}
|
|
1225
1407
|
coupons = {
|
|
1226
1408
|
/** Define a coupon (a reusable discount template). */
|