@clocknext/sdk 0.13.0 → 0.15.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/README.md +200 -140
- package/dist/index.cjs +213 -438
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +394 -812
- package/dist/index.d.ts +394 -812
- package/dist/index.js +213 -438
- package/dist/index.js.map +1 -1
- package/examples/node-basic.ts +24 -32
- package/package.json +1 -1
- package/src/client.ts +3 -27
- package/src/customer-ref.ts +14 -0
- package/src/errors.ts +8 -1
- package/src/filters.ts +1 -1
- package/src/index.ts +13 -59
- package/src/resources/customers.ts +201 -82
- package/src/resources/invoices.ts +1 -1
- package/src/resources/plans.ts +4 -56
- package/src/resources/signals.ts +33 -38
- package/src/types.ts +301 -610
- package/src/resources/composites.ts +0 -47
- package/src/resources/credits.ts +0 -76
- package/src/resources/outcomes.ts +0 -82
- package/src/resources/units.ts +0 -76
- package/src/resources/webhooks.ts +0 -37
- package/src/resources/workspace.ts +0 -33
package/dist/index.js
CHANGED
|
@@ -75,7 +75,8 @@ function translateFieldPaths(message) {
|
|
|
75
75
|
}
|
|
76
76
|
return out;
|
|
77
77
|
}
|
|
78
|
-
var ALLOWANCE_MESSAGE = /\binsufficient\b|\bno allowance left\b|\bno slots left\b|\boutcomes remaining\b|\btop up the (?:allowance|balance)\b/i;
|
|
78
|
+
var ALLOWANCE_MESSAGE = /\binsufficient\b|\bno allowance left\b|\bno slots left\b|\boutcomes remaining\b|\btop up the (?:allowance|balance)\b|\bbelow zero\b/i;
|
|
79
|
+
var IDEMPOTENCY_KEY_REUSED = /\bidempotency key was already used\b/i;
|
|
79
80
|
function isAllowanceFailure(message, code) {
|
|
80
81
|
if (code) return code === "ALLOWANCE_EXHAUSTED";
|
|
81
82
|
return ALLOWANCE_MESSAGE.test(message);
|
|
@@ -99,6 +100,9 @@ function errorFromResponse(status, message, retryAfterMs, meta = {}) {
|
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
if (status === 422) {
|
|
103
|
+
if (IDEMPOTENCY_KEY_REUSED.test(raw)) {
|
|
104
|
+
return new ConflictError(raw, { ...opts, retryable: false });
|
|
105
|
+
}
|
|
102
106
|
return isAllowanceFailure(raw, code) ? new AllowanceError(raw, opts) : new PlanError(raw, opts);
|
|
103
107
|
}
|
|
104
108
|
if (status === 429) return new RateLimitError(raw, { retryAfterMs, idempotencyKey });
|
|
@@ -326,7 +330,7 @@ function sleep(ms) {
|
|
|
326
330
|
}
|
|
327
331
|
|
|
328
332
|
// src/http.ts
|
|
329
|
-
var SDK_VERSION = "0.
|
|
333
|
+
var SDK_VERSION = "0.15.0" ;
|
|
330
334
|
var Transport = class {
|
|
331
335
|
constructor(cfg) {
|
|
332
336
|
this.cfg = cfg;
|
|
@@ -430,105 +434,17 @@ var Transport = class {
|
|
|
430
434
|
}
|
|
431
435
|
};
|
|
432
436
|
|
|
433
|
-
// src/
|
|
434
|
-
function
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
437
|
+
// src/idempotency.ts
|
|
438
|
+
function newKey() {
|
|
439
|
+
const c = globalThis.crypto;
|
|
440
|
+
if (typeof c?.randomUUID === "function") return c.randomUUID();
|
|
441
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
|
|
442
|
+
const r = Math.random() * 16 | 0;
|
|
443
|
+
const v = ch === "x" ? r : r & 3 | 8;
|
|
444
|
+
return v.toString(16);
|
|
445
|
+
});
|
|
439
446
|
}
|
|
440
447
|
|
|
441
|
-
// src/resources/composites.ts
|
|
442
|
-
var Composites = class {
|
|
443
|
-
constructor(transport) {
|
|
444
|
-
this.transport = transport;
|
|
445
|
-
}
|
|
446
|
-
transport;
|
|
447
|
-
/** List composites. Pass `{ active: true }` for only the ones a signal can
|
|
448
|
-
* still be tagged with — the default list INCLUDES archived ones, which
|
|
449
|
-
* keep every row they already own.
|
|
450
|
-
* `{ active: false }` returns only archived ones; omitting it returns
|
|
451
|
-
* both. See `activeQuery` — the API itself only supports `true`. */
|
|
452
|
-
async list(params = {}) {
|
|
453
|
-
const res = await this.transport.request({
|
|
454
|
-
method: "GET",
|
|
455
|
-
path: "/api/v1/composites",
|
|
456
|
-
query: { active: activeQuery(params.active) }
|
|
457
|
-
});
|
|
458
|
-
return filterByActive(res.composites, params.active);
|
|
459
|
-
}
|
|
460
|
-
/** Create a composite. `POST /api/v1/composites`. */
|
|
461
|
-
async create(input) {
|
|
462
|
-
const res = await this.transport.request({
|
|
463
|
-
method: "POST",
|
|
464
|
-
path: "/api/v1/composites",
|
|
465
|
-
body: input
|
|
466
|
-
});
|
|
467
|
-
return res.composite;
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
// src/resources/credits.ts
|
|
472
|
-
var Credits = class {
|
|
473
|
-
constructor(transport) {
|
|
474
|
-
this.transport = transport;
|
|
475
|
-
}
|
|
476
|
-
transport;
|
|
477
|
-
/** List credit types. Pass `{ active: true }` to only return active ones.
|
|
478
|
-
* `{ active: false }` returns only archived ones; omitting it returns
|
|
479
|
-
* both. See `activeQuery` — the API itself only supports `true`. */
|
|
480
|
-
async list(params = {}) {
|
|
481
|
-
const res = await this.transport.request({
|
|
482
|
-
method: "GET",
|
|
483
|
-
path: "/api/v1/credits",
|
|
484
|
-
query: { active: activeQuery(params.active) }
|
|
485
|
-
});
|
|
486
|
-
return filterByActive(res.credits, params.active);
|
|
487
|
-
}
|
|
488
|
-
/** Create a credit type; returns the created credit. `POST /api/v1/credits`. */
|
|
489
|
-
async create(input) {
|
|
490
|
-
const res = await this.transport.request({
|
|
491
|
-
method: "POST",
|
|
492
|
-
path: "/api/v1/credits",
|
|
493
|
-
body: input
|
|
494
|
-
});
|
|
495
|
-
return res.credit;
|
|
496
|
-
}
|
|
497
|
-
/** Fetch one credit type with usage stats. `GET /api/v1/credits/:id`. */
|
|
498
|
-
async get(id) {
|
|
499
|
-
const res = await this.transport.request({
|
|
500
|
-
method: "GET",
|
|
501
|
-
path: `/api/v1/credits/${encodeURIComponent(id)}`
|
|
502
|
-
});
|
|
503
|
-
return res.credit;
|
|
504
|
-
}
|
|
505
|
-
/** Update a credit type's definition; returns the updated credit. `PATCH /api/v1/credits/:id`. */
|
|
506
|
-
async update(id, input) {
|
|
507
|
-
const res = await this.transport.request({
|
|
508
|
-
method: "PATCH",
|
|
509
|
-
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
510
|
-
body: input
|
|
511
|
-
});
|
|
512
|
-
return res.credit;
|
|
513
|
-
}
|
|
514
|
-
/** Activate or deactivate a credit type. */
|
|
515
|
-
async setActive(id, isActive) {
|
|
516
|
-
const res = await this.transport.request({
|
|
517
|
-
method: "PATCH",
|
|
518
|
-
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
519
|
-
body: { isActive }
|
|
520
|
-
});
|
|
521
|
-
return res.credit;
|
|
522
|
-
}
|
|
523
|
-
/** Delete a credit type. Refused while a customer is linked to it. */
|
|
524
|
-
async delete(id) {
|
|
525
|
-
await this.transport.request({
|
|
526
|
-
method: "DELETE",
|
|
527
|
-
path: `/api/v1/credits/${encodeURIComponent(id)}`
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
|
|
532
448
|
// src/resources/customers.ts
|
|
533
449
|
var Customers = class {
|
|
534
450
|
constructor(transport) {
|
|
@@ -582,6 +498,36 @@ var Customers = class {
|
|
|
582
498
|
});
|
|
583
499
|
return res.customer;
|
|
584
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Fetch one customer by YOUR id for them (its `externalId`), instead of
|
|
503
|
+
* ours. Same result as {@link get}. `GET /api/v1/customers/ext/:externalId`.
|
|
504
|
+
* An unknown external id is a `NotFoundError`; only active customers match.
|
|
505
|
+
*/
|
|
506
|
+
async getByExternalId(externalId) {
|
|
507
|
+
const res = await this.transport.request({
|
|
508
|
+
method: "GET",
|
|
509
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`
|
|
510
|
+
});
|
|
511
|
+
return res.customer;
|
|
512
|
+
}
|
|
513
|
+
/** Update a customer (partial), addressed by its `externalId`. Same body as
|
|
514
|
+
* {@link update}. `PATCH /api/v1/customers/ext/:externalId`. */
|
|
515
|
+
async updateByExternalId(externalId, input) {
|
|
516
|
+
const res = await this.transport.request({
|
|
517
|
+
method: "PATCH",
|
|
518
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`,
|
|
519
|
+
body: input
|
|
520
|
+
});
|
|
521
|
+
return res.customer;
|
|
522
|
+
}
|
|
523
|
+
/** {@link delete}, addressing the customer by its `externalId`.
|
|
524
|
+
* `DELETE /api/v1/customers/ext/:externalId`. */
|
|
525
|
+
async deleteByExternalId(externalId) {
|
|
526
|
+
await this.transport.request({
|
|
527
|
+
method: "DELETE",
|
|
528
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`
|
|
529
|
+
});
|
|
530
|
+
}
|
|
585
531
|
/** Delete a customer (members, invitations, usage logs cascade). */
|
|
586
532
|
async delete(id) {
|
|
587
533
|
await this.transport.request({
|
|
@@ -589,15 +535,6 @@ var Customers = class {
|
|
|
589
535
|
path: `/api/v1/customers/${encodeURIComponent(id)}`
|
|
590
536
|
});
|
|
591
537
|
}
|
|
592
|
-
/** A customer's usage history. `GET /api/v1/usage?customerId=`. */
|
|
593
|
-
async usage(id, params = {}) {
|
|
594
|
-
const res = await this.transport.request({
|
|
595
|
-
method: "GET",
|
|
596
|
-
path: `/api/v1/usage`,
|
|
597
|
-
query: { customerId: id, limit: params.limit }
|
|
598
|
-
});
|
|
599
|
-
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
600
|
-
}
|
|
601
538
|
/** Wallet / credit / outcome / unit balances. `GET …/:id/balances`. */
|
|
602
539
|
balances(id) {
|
|
603
540
|
return this.transport.request({
|
|
@@ -605,6 +542,14 @@ var Customers = class {
|
|
|
605
542
|
path: `/api/v1/customers/${encodeURIComponent(id)}/balances`
|
|
606
543
|
});
|
|
607
544
|
}
|
|
545
|
+
/** {@link balances}, addressing the customer by its `externalId`.
|
|
546
|
+
* `GET /api/v1/customers/ext/:externalId/balances`. */
|
|
547
|
+
balancesByExternalId(externalId) {
|
|
548
|
+
return this.transport.request({
|
|
549
|
+
method: "GET",
|
|
550
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/balances`
|
|
551
|
+
});
|
|
552
|
+
}
|
|
608
553
|
/**
|
|
609
554
|
* One credit balance for a customer, matched by `creditId` or `creditName`;
|
|
610
555
|
* `null` when the customer has no plan or no matching credit. Convenience
|
|
@@ -643,6 +588,14 @@ var Customers = class {
|
|
|
643
588
|
path: `/api/v1/customers/${encodeURIComponent(id)}/plan`
|
|
644
589
|
});
|
|
645
590
|
}
|
|
591
|
+
/** {@link plan}, addressing the customer by its `externalId`.
|
|
592
|
+
* `GET /api/v1/customers/ext/:externalId/plan`. */
|
|
593
|
+
planByExternalId(externalId) {
|
|
594
|
+
return this.transport.request({
|
|
595
|
+
method: "GET",
|
|
596
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/plan`
|
|
597
|
+
});
|
|
598
|
+
}
|
|
646
599
|
// --- Members -------------------------------------------------------------
|
|
647
600
|
/** List a customer's members. `GET …/:id/members`. */
|
|
648
601
|
async listMembers(id) {
|
|
@@ -678,72 +631,129 @@ var Customers = class {
|
|
|
678
631
|
});
|
|
679
632
|
return res.member;
|
|
680
633
|
}
|
|
681
|
-
// ---
|
|
682
|
-
/** The customer's wallet balance + transactions. `GET …/:id/wallet`. */
|
|
683
|
-
wallet(id, params = {}) {
|
|
684
|
-
return this.transport.request({
|
|
685
|
-
method: "GET",
|
|
686
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/wallet`,
|
|
687
|
-
query: { limit: params.limit }
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* Record a manual wallet entry (top-up or deduction). `amount` is always
|
|
692
|
-
* positive; the sign comes from `type`. `POST …/:id/wallet`.
|
|
693
|
-
*/
|
|
694
|
-
async addWalletEntry(id, input) {
|
|
695
|
-
return this.transport.request({
|
|
696
|
-
method: "POST",
|
|
697
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/wallet`,
|
|
698
|
-
body: input
|
|
699
|
-
});
|
|
700
|
-
}
|
|
634
|
+
// --- Billing config -----------------------------------------------------
|
|
701
635
|
// Note: a customer's currency is set through `update(id, { currencyCode })`
|
|
702
636
|
// (PATCH …/:id) — there is no separate currency endpoint. Credit-type
|
|
703
637
|
// assignment has no public API.
|
|
704
638
|
// --- Balance adjustments -------------------------------------------------
|
|
705
|
-
/** Grant or claw back a credit balance.
|
|
706
|
-
* `
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
639
|
+
/** Grant or claw back a credit balance. The credit must be a prepaid part of
|
|
640
|
+
* the customer's current plan. Pass `idempotencyKey` to make it safe to
|
|
641
|
+
* retry. `POST …/:id/credits/adjust`. */
|
|
642
|
+
adjustCredit(id, input) {
|
|
643
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/credits/adjust`, input);
|
|
644
|
+
}
|
|
645
|
+
/** Grant or claw back an outcome balance. The outcome must be a prepaid part
|
|
646
|
+
* of the customer's current plan. `POST …/:id/outcomes/adjust`. */
|
|
647
|
+
adjustOutcome(id, input) {
|
|
648
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/outcomes/adjust`, input);
|
|
649
|
+
}
|
|
650
|
+
/** Grant or claw back a unit balance. The unit must be a prepaid part of the
|
|
651
|
+
* customer's current plan. `POST …/:id/units/adjust`. */
|
|
652
|
+
adjustUnit(id, input) {
|
|
653
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/units/adjust`, input);
|
|
654
|
+
}
|
|
655
|
+
/** Grant or claw back slots on a customer's ADVANCE composite pool for the
|
|
656
|
+
* current billing cycle. `remaining` is the resulting slot count.
|
|
657
|
+
* `POST …/:id/composites/adjust`. */
|
|
658
|
+
adjustComposite(id, input) {
|
|
659
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/composites/adjust`, input);
|
|
714
660
|
}
|
|
715
|
-
/**
|
|
716
|
-
|
|
661
|
+
/**
|
|
662
|
+
* Top up (positive `delta`) or draw down (negative `delta`) a customer's
|
|
663
|
+
* wallet, in USD — allowed whatever the customer's plan. `remaining` is the
|
|
664
|
+
* resulting USD balance. No `agentKey` — a customer has exactly one wallet.
|
|
665
|
+
* Pass `pool: "RESERVED"` to move the Reserved Wallet instead (then
|
|
666
|
+
* `remaining` is its balance). `POST …/:id/wallet/adjust`.
|
|
667
|
+
*/
|
|
668
|
+
adjustWallet(id, input) {
|
|
669
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/wallet/adjust`, input);
|
|
670
|
+
}
|
|
671
|
+
/** {@link adjustCredit}, addressing the customer by its `externalId` (`id`
|
|
672
|
+
* here). `POST /api/v1/customers/ext/:externalId/credits/adjust`. */
|
|
673
|
+
adjustCreditByExternalId(id, input) {
|
|
674
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/credits/adjust`, input);
|
|
675
|
+
}
|
|
676
|
+
/** {@link adjustOutcome}, addressing the customer by its `externalId` (`id`
|
|
677
|
+
* here). `POST /api/v1/customers/ext/:externalId/outcomes/adjust`. */
|
|
678
|
+
adjustOutcomeByExternalId(id, input) {
|
|
679
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/outcomes/adjust`, input);
|
|
680
|
+
}
|
|
681
|
+
/** {@link adjustUnit}, addressing the customer by its `externalId` (`id`
|
|
682
|
+
* here). `POST /api/v1/customers/ext/:externalId/units/adjust`. */
|
|
683
|
+
adjustUnitByExternalId(id, input) {
|
|
684
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/units/adjust`, input);
|
|
685
|
+
}
|
|
686
|
+
/** {@link adjustComposite}, addressing the customer by its `externalId`
|
|
687
|
+
* (`id` here). `POST /api/v1/customers/ext/:externalId/composites/adjust`. */
|
|
688
|
+
adjustCompositeByExternalId(id, input) {
|
|
689
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/composites/adjust`, input);
|
|
690
|
+
}
|
|
691
|
+
/** {@link adjustWallet}, addressing the customer by its `externalId` (`id`
|
|
692
|
+
* here). `POST /api/v1/customers/ext/:externalId/wallet/adjust`. */
|
|
693
|
+
adjustWalletByExternalId(id, input) {
|
|
694
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/wallet/adjust`, input);
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* The one body behind all ten adjust calls.
|
|
698
|
+
*
|
|
699
|
+
* Every adjustment carries an idempotency key — the caller's, or one
|
|
700
|
+
* generated here ONCE per call, exactly like signals. The server
|
|
701
|
+
* deduplicates on it, so a transient failure is safe to retry: the same key
|
|
702
|
+
* rides every attempt, and a retry of one that already landed comes back as
|
|
703
|
+
* `replayed: true` instead of adjusting again. The key is also copied onto
|
|
704
|
+
* any thrown error (`error.idempotencyKey`) so the caller can replay safely.
|
|
705
|
+
*/
|
|
706
|
+
async adjust(path, input) {
|
|
707
|
+
const idempotencyKey = input.idempotencyKey ?? newKey();
|
|
717
708
|
const res = await this.transport.request({
|
|
718
709
|
method: "POST",
|
|
719
|
-
path
|
|
720
|
-
|
|
710
|
+
path,
|
|
711
|
+
idempotencyKey,
|
|
712
|
+
body: { ...input, idempotencyKey },
|
|
713
|
+
retry: true
|
|
721
714
|
});
|
|
722
|
-
|
|
715
|
+
const result = {
|
|
716
|
+
remaining: res.remaining,
|
|
717
|
+
replayed: res.replayed === true,
|
|
718
|
+
customerArchived: res.customerArchived === true
|
|
719
|
+
};
|
|
720
|
+
if (result.replayed && typeof res.adjustedAt === "string") {
|
|
721
|
+
result.adjustedAt = res.adjustedAt;
|
|
722
|
+
}
|
|
723
|
+
return result;
|
|
723
724
|
}
|
|
724
|
-
|
|
725
|
-
|
|
725
|
+
// --- Recurring grants ----------------------------------------------------
|
|
726
|
+
/**
|
|
727
|
+
* Change how much a customer is granted every billing cycle (wallet top-up,
|
|
728
|
+
* credits, outcomes, units or a composite pool). Any increase or decrease
|
|
729
|
+
* applies to their current balance immediately. `PUT …/:id/recurring-grant`.
|
|
730
|
+
*/
|
|
731
|
+
async updateRecurringGrant(id, input) {
|
|
726
732
|
const res = await this.transport.request({
|
|
727
|
-
method: "
|
|
728
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/
|
|
733
|
+
method: "PUT",
|
|
734
|
+
path: `/api/v1/customers/${encodeURIComponent(id)}/recurring-grant`,
|
|
729
735
|
body: input
|
|
730
736
|
});
|
|
731
|
-
return
|
|
737
|
+
return toRecurringGrantResult(res);
|
|
732
738
|
}
|
|
733
|
-
/**
|
|
734
|
-
*
|
|
735
|
-
|
|
736
|
-
* `POST …/:id/composites/adjust`.
|
|
737
|
-
*/
|
|
738
|
-
async adjustComposite(id, input) {
|
|
739
|
+
/** {@link updateRecurringGrant}, addressing the customer by its
|
|
740
|
+
* `externalId`. `PUT /api/v1/customers/ext/:externalId/recurring-grant`. */
|
|
741
|
+
async updateRecurringGrantByExternalId(externalId, input) {
|
|
739
742
|
const res = await this.transport.request({
|
|
740
|
-
method: "
|
|
741
|
-
path: `/api/v1/customers/${encodeURIComponent(
|
|
743
|
+
method: "PUT",
|
|
744
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/recurring-grant`,
|
|
742
745
|
body: input
|
|
743
746
|
});
|
|
744
|
-
return
|
|
747
|
+
return toRecurringGrantResult(res);
|
|
745
748
|
}
|
|
746
749
|
};
|
|
750
|
+
function toRecurringGrantResult(res) {
|
|
751
|
+
return {
|
|
752
|
+
kind: res.kind,
|
|
753
|
+
quantity: res.quantity,
|
|
754
|
+
...res.balanceUsd !== void 0 ? { balanceUsd: res.balanceUsd } : {}
|
|
755
|
+
};
|
|
756
|
+
}
|
|
747
757
|
|
|
748
758
|
// src/resources/invoices.ts
|
|
749
759
|
var Invoices = class {
|
|
@@ -772,7 +782,7 @@ var Invoices = class {
|
|
|
772
782
|
});
|
|
773
783
|
}
|
|
774
784
|
/**
|
|
775
|
-
* Mint a hosted pay link for an OPEN invoice. PAID/VOID invoices are rejected
|
|
785
|
+
* Mint a hosted pay link for an OPEN invoice. PAID/VOID/AUTO_CLOSED invoices are rejected
|
|
776
786
|
* with a `ConflictError`. `GET /api/v1/invoices/:id/pay-link`.
|
|
777
787
|
*/
|
|
778
788
|
payLink(id) {
|
|
@@ -783,67 +793,6 @@ var Invoices = class {
|
|
|
783
793
|
}
|
|
784
794
|
};
|
|
785
795
|
|
|
786
|
-
// src/resources/outcomes.ts
|
|
787
|
-
var Outcomes = class {
|
|
788
|
-
constructor(transport) {
|
|
789
|
-
this.transport = transport;
|
|
790
|
-
}
|
|
791
|
-
transport;
|
|
792
|
-
/** List outcome types. Pass `{ active: true }` to only return active ones.
|
|
793
|
-
* `{ active: false }` returns only archived ones; omitting it returns
|
|
794
|
-
* both. See `activeQuery` — the API itself only supports `true`. */
|
|
795
|
-
async list(params = {}) {
|
|
796
|
-
const res = await this.transport.request({
|
|
797
|
-
method: "GET",
|
|
798
|
-
path: "/api/v1/outcomes",
|
|
799
|
-
query: { active: activeQuery(params.active) }
|
|
800
|
-
});
|
|
801
|
-
return filterByActive(res.outcomes, params.active);
|
|
802
|
-
}
|
|
803
|
-
/** Create an outcome type with its steps. `POST /api/v1/outcomes`. */
|
|
804
|
-
async create(input) {
|
|
805
|
-
const res = await this.transport.request({
|
|
806
|
-
method: "POST",
|
|
807
|
-
path: "/api/v1/outcomes",
|
|
808
|
-
body: input
|
|
809
|
-
});
|
|
810
|
-
return res.outcome;
|
|
811
|
-
}
|
|
812
|
-
/** Fetch one outcome type with steps + stats. `GET /api/v1/outcomes/:id`. */
|
|
813
|
-
async get(id) {
|
|
814
|
-
const res = await this.transport.request({
|
|
815
|
-
method: "GET",
|
|
816
|
-
path: `/api/v1/outcomes/${encodeURIComponent(id)}`
|
|
817
|
-
});
|
|
818
|
-
return res.outcome;
|
|
819
|
-
}
|
|
820
|
-
/** Update an outcome type's definition. `PATCH /api/v1/outcomes/:id`. */
|
|
821
|
-
async update(id, input) {
|
|
822
|
-
const res = await this.transport.request({
|
|
823
|
-
method: "PATCH",
|
|
824
|
-
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
825
|
-
body: input
|
|
826
|
-
});
|
|
827
|
-
return res.outcome;
|
|
828
|
-
}
|
|
829
|
-
/** Activate or deactivate an outcome type; returns the updated outcome. */
|
|
830
|
-
async setActive(id, isActive) {
|
|
831
|
-
const res = await this.transport.request({
|
|
832
|
-
method: "PATCH",
|
|
833
|
-
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
834
|
-
body: { isActive }
|
|
835
|
-
});
|
|
836
|
-
return res.outcome;
|
|
837
|
-
}
|
|
838
|
-
/** Delete an outcome type. */
|
|
839
|
-
async delete(id) {
|
|
840
|
-
await this.transport.request({
|
|
841
|
-
method: "DELETE",
|
|
842
|
-
path: `/api/v1/outcomes/${encodeURIComponent(id)}`
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
};
|
|
846
|
-
|
|
847
796
|
// src/resources/payments.ts
|
|
848
797
|
var Payments = class {
|
|
849
798
|
constructor(transport) {
|
|
@@ -868,6 +817,14 @@ var Payments = class {
|
|
|
868
817
|
}
|
|
869
818
|
};
|
|
870
819
|
|
|
820
|
+
// src/filters.ts
|
|
821
|
+
function activeQuery(active) {
|
|
822
|
+
return active === true ? "true" : void 0;
|
|
823
|
+
}
|
|
824
|
+
function filterByActive(rows, active) {
|
|
825
|
+
return active === false ? rows.filter((row) => !row.isActive) : rows;
|
|
826
|
+
}
|
|
827
|
+
|
|
871
828
|
// src/resources/plans.ts
|
|
872
829
|
var Plans = class {
|
|
873
830
|
constructor(transport) {
|
|
@@ -885,48 +842,6 @@ var Plans = class {
|
|
|
885
842
|
});
|
|
886
843
|
return filterByActive(res.plans, params.active);
|
|
887
844
|
}
|
|
888
|
-
/** Create a plan. `POST /api/v1/plans`. */
|
|
889
|
-
async create(input) {
|
|
890
|
-
const res = await this.transport.request({
|
|
891
|
-
method: "POST",
|
|
892
|
-
path: "/api/v1/plans",
|
|
893
|
-
body: input
|
|
894
|
-
});
|
|
895
|
-
return res.plan;
|
|
896
|
-
}
|
|
897
|
-
/** Fetch one plan with aggregate subscriber/invoice stats. `GET /api/v1/plans/:id`. */
|
|
898
|
-
async get(id) {
|
|
899
|
-
const res = await this.transport.request({
|
|
900
|
-
method: "GET",
|
|
901
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`
|
|
902
|
-
});
|
|
903
|
-
return res.plan;
|
|
904
|
-
}
|
|
905
|
-
/** Replace a plan's definition (components + settings). `PATCH /api/v1/plans/:id`. */
|
|
906
|
-
async update(id, input) {
|
|
907
|
-
const res = await this.transport.request({
|
|
908
|
-
method: "PATCH",
|
|
909
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
910
|
-
body: input
|
|
911
|
-
});
|
|
912
|
-
return res.plan;
|
|
913
|
-
}
|
|
914
|
-
/** Activate or deactivate a plan without rewriting it. */
|
|
915
|
-
async setActive(id, isActive) {
|
|
916
|
-
const res = await this.transport.request({
|
|
917
|
-
method: "PATCH",
|
|
918
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
919
|
-
body: { isActive }
|
|
920
|
-
});
|
|
921
|
-
return res.plan;
|
|
922
|
-
}
|
|
923
|
-
/** Delete a plan. Refused once any customer has purchased it. */
|
|
924
|
-
async delete(id) {
|
|
925
|
-
await this.transport.request({
|
|
926
|
-
method: "DELETE",
|
|
927
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`
|
|
928
|
-
});
|
|
929
|
-
}
|
|
930
845
|
};
|
|
931
846
|
|
|
932
847
|
// src/resources/portal.ts
|
|
@@ -1009,15 +924,12 @@ var Purchases = class {
|
|
|
1009
924
|
}
|
|
1010
925
|
};
|
|
1011
926
|
|
|
1012
|
-
// src/
|
|
1013
|
-
function
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
const v = ch === "x" ? r : r & 3 | 8;
|
|
1019
|
-
return v.toString(16);
|
|
1020
|
-
});
|
|
927
|
+
// src/customer-ref.ts
|
|
928
|
+
function customerRefToWire(ref) {
|
|
929
|
+
return {
|
|
930
|
+
...ref.customerId != null ? { customerId: ref.customerId } : {},
|
|
931
|
+
...ref.externalId != null ? { externalId: ref.externalId } : {}
|
|
932
|
+
};
|
|
1021
933
|
}
|
|
1022
934
|
|
|
1023
935
|
// src/resources/signals.ts
|
|
@@ -1029,10 +941,11 @@ var SIGNAL_PATHS = {
|
|
|
1029
941
|
var UNIT_PATH = "/api/v1/signal/unit";
|
|
1030
942
|
var COMPOSITE_COMPLETE_PATH = "/api/v1/signal/composite/complete";
|
|
1031
943
|
var OUTCOME_COMPLETE_PATH = "/api/v1/signal/outcome/complete";
|
|
944
|
+
var USAGE_LOG_PATH = "/api/v1/signal/usage-log";
|
|
1032
945
|
function signalToWire(signal) {
|
|
1033
946
|
const t = signal.tokens;
|
|
1034
947
|
const body = {
|
|
1035
|
-
|
|
948
|
+
...customerRefToWire(signal),
|
|
1036
949
|
// `usage` is required on all three model-priced kinds. input/output are
|
|
1037
950
|
// always sent; `cacheTokens` only when provided (the server defaults 0).
|
|
1038
951
|
usage: {
|
|
@@ -1143,9 +1056,8 @@ var Signals = class {
|
|
|
1143
1056
|
path: OUTCOME_COMPLETE_PATH,
|
|
1144
1057
|
idempotencyKey,
|
|
1145
1058
|
body: {
|
|
1146
|
-
|
|
1059
|
+
...customerRefToWire(input),
|
|
1147
1060
|
runId: input.runId,
|
|
1148
|
-
complete: true,
|
|
1149
1061
|
...input.member ? { member: input.member } : {},
|
|
1150
1062
|
idempotencyKey
|
|
1151
1063
|
},
|
|
@@ -1160,23 +1072,6 @@ var Signals = class {
|
|
|
1160
1072
|
...handles(res)
|
|
1161
1073
|
};
|
|
1162
1074
|
}
|
|
1163
|
-
/**
|
|
1164
|
-
* Recent usage logs + totals for a customer. `GET /api/v1/usage`.
|
|
1165
|
-
*
|
|
1166
|
-
* Still the legacy path, deliberately. The `/api/v1/signal/*` family is
|
|
1167
|
-
* POST-only — it replaced how usage is INGESTED, not how it is read — so
|
|
1168
|
-
* `GET /api/v1/usage` has no successor and is not deprecated. It is also the
|
|
1169
|
-
* only way to prove a signal landed, which matters more now that ingestion
|
|
1170
|
-
* answers `202` for everything.
|
|
1171
|
-
*/
|
|
1172
|
-
async list(params) {
|
|
1173
|
-
const res = await this.transport.request({
|
|
1174
|
-
method: "GET",
|
|
1175
|
-
path: "/api/v1/usage",
|
|
1176
|
-
query: { customerId: params.customerId, limit: params.limit }
|
|
1177
|
-
});
|
|
1178
|
-
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
1179
|
-
}
|
|
1180
1075
|
/**
|
|
1181
1076
|
* Record one unit-metered event (a fixed-price meter with no tokens),
|
|
1182
1077
|
* addressed to a catalog unit by its `agentKey`. Sent immediately — unit
|
|
@@ -1196,7 +1091,7 @@ var Signals = class {
|
|
|
1196
1091
|
path: UNIT_PATH,
|
|
1197
1092
|
idempotencyKey,
|
|
1198
1093
|
body: {
|
|
1199
|
-
|
|
1094
|
+
...customerRefToWire(input),
|
|
1200
1095
|
agentKey: input.agentKey,
|
|
1201
1096
|
...input.quantity != null ? { quantity: input.quantity } : {},
|
|
1202
1097
|
...input.member ? { member: input.member } : {},
|
|
@@ -1253,7 +1148,7 @@ var Signals = class {
|
|
|
1253
1148
|
path: COMPOSITE_COMPLETE_PATH,
|
|
1254
1149
|
idempotencyKey,
|
|
1255
1150
|
body: {
|
|
1256
|
-
|
|
1151
|
+
...customerRefToWire(input),
|
|
1257
1152
|
composite: { [input.composite.ref]: input.composite.value },
|
|
1258
1153
|
// Auto-assigned like the others. A retry here could not double-BILL
|
|
1259
1154
|
// even without it — closing a closed occurrence is a server-side
|
|
@@ -1275,147 +1170,45 @@ var Signals = class {
|
|
|
1275
1170
|
};
|
|
1276
1171
|
}
|
|
1277
1172
|
/**
|
|
1278
|
-
*
|
|
1173
|
+
* One customer's usage history, merged from every meter kind — credit,
|
|
1174
|
+
* outcome, unit, wallet, and completed composite occurrences — into one
|
|
1175
|
+
* feed sorted by time. `GET /api/v1/signal/usage-log`. Exactly the same
|
|
1176
|
+
* rows the customer portal's own "Usage logs" table shows, so a caller can
|
|
1177
|
+
* build against this instead of the portal UI.
|
|
1178
|
+
*
|
|
1179
|
+
* Cursor-paginated, NOT page-numbered: `limit` + `cursor` in, `nextCursor`
|
|
1180
|
+
* out. Omit `cursor` for the first page; pass the previous page's
|
|
1181
|
+
* `nextCursor` back to fetch the next one, and stop once it comes back
|
|
1182
|
+
* `null`. Unlike offset pagination, the cost of a page never grows with how
|
|
1183
|
+
* deep you've paged — each page only asks for rows strictly before the
|
|
1184
|
+
* cursor's position.
|
|
1279
1185
|
*
|
|
1280
|
-
*
|
|
1281
|
-
*
|
|
1186
|
+
* Read-only; unlike {@link track}/{@link unit}/etc., there is nothing to
|
|
1187
|
+
* buffer or retry here.
|
|
1282
1188
|
*/
|
|
1283
|
-
|
|
1189
|
+
usageLog(params) {
|
|
1284
1190
|
return this.transport.request({
|
|
1285
1191
|
method: "GET",
|
|
1286
|
-
path:
|
|
1287
|
-
query: {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
this.transport = transport;
|
|
1296
|
-
}
|
|
1297
|
-
transport;
|
|
1298
|
-
/** List unit types. Pass `{ active: true }` to only return active ones.
|
|
1299
|
-
* `{ active: false }` returns only archived ones; omitting it returns
|
|
1300
|
-
* both. See `activeQuery` — the API itself only supports `true`. */
|
|
1301
|
-
async list(params = {}) {
|
|
1302
|
-
const res = await this.transport.request({
|
|
1303
|
-
method: "GET",
|
|
1304
|
-
path: "/api/v1/units-catalog",
|
|
1305
|
-
query: { active: activeQuery(params.active) }
|
|
1306
|
-
});
|
|
1307
|
-
return filterByActive(res.units, params.active);
|
|
1308
|
-
}
|
|
1309
|
-
/** Create a unit type. `POST /api/v1/units-catalog`. */
|
|
1310
|
-
async create(input) {
|
|
1311
|
-
const res = await this.transport.request({
|
|
1312
|
-
method: "POST",
|
|
1313
|
-
path: "/api/v1/units-catalog",
|
|
1314
|
-
body: input
|
|
1315
|
-
});
|
|
1316
|
-
return res.unit;
|
|
1317
|
-
}
|
|
1318
|
-
/** Fetch one unit type with stats. `GET /api/v1/units-catalog/:id`. */
|
|
1319
|
-
async get(id) {
|
|
1320
|
-
const res = await this.transport.request({
|
|
1321
|
-
method: "GET",
|
|
1322
|
-
path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
|
|
1323
|
-
});
|
|
1324
|
-
return res.unit;
|
|
1325
|
-
}
|
|
1326
|
-
/** Update a unit type's definition. `PATCH /api/v1/units-catalog/:id`. */
|
|
1327
|
-
async update(id, input) {
|
|
1328
|
-
const res = await this.transport.request({
|
|
1329
|
-
method: "PATCH",
|
|
1330
|
-
path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
|
|
1331
|
-
body: input
|
|
1332
|
-
});
|
|
1333
|
-
return res.unit;
|
|
1334
|
-
}
|
|
1335
|
-
/** Activate or deactivate a unit type. */
|
|
1336
|
-
async setActive(id, isActive) {
|
|
1337
|
-
const res = await this.transport.request({
|
|
1338
|
-
method: "PATCH",
|
|
1339
|
-
path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
|
|
1340
|
-
body: { isActive }
|
|
1341
|
-
});
|
|
1342
|
-
return res.unit;
|
|
1343
|
-
}
|
|
1344
|
-
/** Delete a unit type. */
|
|
1345
|
-
async delete(id) {
|
|
1346
|
-
await this.transport.request({
|
|
1347
|
-
method: "DELETE",
|
|
1348
|
-
path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
|
|
1349
|
-
});
|
|
1350
|
-
}
|
|
1351
|
-
};
|
|
1352
|
-
|
|
1353
|
-
// src/resources/webhooks.ts
|
|
1354
|
-
var Webhooks = class {
|
|
1355
|
-
constructor(transport) {
|
|
1356
|
-
this.transport = transport;
|
|
1357
|
-
}
|
|
1358
|
-
transport;
|
|
1359
|
-
/** List configured webhooks. `GET /api/v1/webhooks`. */
|
|
1360
|
-
async list() {
|
|
1361
|
-
const res = await this.transport.request({
|
|
1362
|
-
method: "GET",
|
|
1363
|
-
path: "/api/v1/webhooks"
|
|
1364
|
-
});
|
|
1365
|
-
return res.webhooks;
|
|
1366
|
-
}
|
|
1367
|
-
/** Create or replace the webhook for a kind. `POST /api/v1/webhooks`. */
|
|
1368
|
-
async upsert(input) {
|
|
1369
|
-
const res = await this.transport.request({
|
|
1370
|
-
method: "POST",
|
|
1371
|
-
path: "/api/v1/webhooks",
|
|
1372
|
-
body: input
|
|
1373
|
-
});
|
|
1374
|
-
return res.webhook;
|
|
1375
|
-
}
|
|
1376
|
-
/** Delete the webhook for a kind (idempotent). `DELETE /api/v1/webhooks/:kind`. */
|
|
1377
|
-
async delete(kind) {
|
|
1378
|
-
await this.transport.request({
|
|
1379
|
-
method: "DELETE",
|
|
1380
|
-
path: `/api/v1/webhooks/${encodeURIComponent(kind)}`
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
};
|
|
1384
|
-
|
|
1385
|
-
// src/resources/workspace.ts
|
|
1386
|
-
var Workspace = class {
|
|
1387
|
-
constructor(transport) {
|
|
1388
|
-
this.transport = transport;
|
|
1389
|
-
}
|
|
1390
|
-
transport;
|
|
1391
|
-
/** Identify the org + key behind the request, incl. `sandbox` | `live`. */
|
|
1392
|
-
me() {
|
|
1393
|
-
return this.transport.request({
|
|
1394
|
-
method: "GET",
|
|
1395
|
-
path: "/api/v1/me"
|
|
1396
|
-
});
|
|
1397
|
-
}
|
|
1398
|
-
/** The org's enabled models with live prices. `{ active: true }` returns only
|
|
1399
|
-
* the models that can be metered right now.
|
|
1400
|
-
* `{ active: false }` returns only archived ones; omitting it returns
|
|
1401
|
-
* both. See `activeQuery` — the API itself only supports `true`. */
|
|
1402
|
-
async models(params = {}) {
|
|
1403
|
-
const res = await this.transport.request({
|
|
1404
|
-
method: "GET",
|
|
1405
|
-
path: "/api/v1/models",
|
|
1406
|
-
query: { active: activeQuery(params.active) }
|
|
1192
|
+
path: USAGE_LOG_PATH,
|
|
1193
|
+
query: {
|
|
1194
|
+
customerId: params.customerId,
|
|
1195
|
+
limit: params.limit,
|
|
1196
|
+
cursor: params.cursor,
|
|
1197
|
+
period: params.period,
|
|
1198
|
+
from: params.from,
|
|
1199
|
+
to: params.to
|
|
1200
|
+
}
|
|
1407
1201
|
});
|
|
1408
|
-
return filterByActive(res.models, params.active);
|
|
1409
1202
|
}
|
|
1410
1203
|
};
|
|
1411
1204
|
|
|
1412
1205
|
// src/client.ts
|
|
1413
1206
|
var ClockNext = class {
|
|
1414
|
-
/** Record
|
|
1207
|
+
/** Record usage signals (credit / wallet / outcome / unit) and read the usage log. */
|
|
1415
1208
|
signals;
|
|
1416
|
-
/** Manage customers, their members,
|
|
1209
|
+
/** Manage customers, their members, and balances. */
|
|
1417
1210
|
customers;
|
|
1418
|
-
/**
|
|
1211
|
+
/** List billing plans. */
|
|
1419
1212
|
plans;
|
|
1420
1213
|
/** Subscribe customers to plans (purchases). */
|
|
1421
1214
|
purchases;
|
|
@@ -1423,20 +1216,8 @@ var ClockNext = class {
|
|
|
1423
1216
|
invoices;
|
|
1424
1217
|
/** Read payments (paid invoices). */
|
|
1425
1218
|
payments;
|
|
1426
|
-
/** Manage the credit-type catalog. */
|
|
1427
|
-
credits;
|
|
1428
|
-
/** Manage the composite catalog — bundles billed as one thing. */
|
|
1429
|
-
composites;
|
|
1430
|
-
/** Manage the outcome-type catalog. */
|
|
1431
|
-
outcomes;
|
|
1432
|
-
/** Manage the unit-type catalog. */
|
|
1433
|
-
units;
|
|
1434
|
-
/** Configure threshold webhooks. */
|
|
1435
|
-
webhooks;
|
|
1436
1219
|
/** Mint customer-portal embed tokens. */
|
|
1437
1220
|
portal;
|
|
1438
|
-
/** Identify the workspace (sandbox/live) + list its models. `/me`, `/models`. */
|
|
1439
|
-
workspace;
|
|
1440
1221
|
cfg;
|
|
1441
1222
|
flusher;
|
|
1442
1223
|
constructor(config) {
|
|
@@ -1454,13 +1235,7 @@ var ClockNext = class {
|
|
|
1454
1235
|
this.purchases = new Purchases(transport);
|
|
1455
1236
|
this.invoices = new Invoices(transport);
|
|
1456
1237
|
this.payments = new Payments(transport);
|
|
1457
|
-
this.credits = new Credits(transport);
|
|
1458
|
-
this.composites = new Composites(transport);
|
|
1459
|
-
this.outcomes = new Outcomes(transport);
|
|
1460
|
-
this.units = new Units(transport);
|
|
1461
|
-
this.webhooks = new Webhooks(transport);
|
|
1462
1238
|
this.portal = new Portal(transport);
|
|
1463
|
-
this.workspace = new Workspace(transport);
|
|
1464
1239
|
}
|
|
1465
1240
|
/** Number of signals currently buffered (async mode). */
|
|
1466
1241
|
get pending() {
|