@clocknext/sdk 0.14.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/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.14.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/filters.ts
434
- function activeQuery(active) {
435
- return active === true ? "true" : void 0;
436
- }
437
- function filterByActive(rows, active) {
438
- return active === false ? rows.filter((row) => !row.isActive) : rows;
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
- // --- Wallet & billing config --------------------------------------------
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. Returns the remaining balance.
706
- * `POST …/:id/credits/adjust`. */
707
- async adjustCredit(id, input) {
708
- const res = await this.transport.request({
709
- method: "POST",
710
- path: `/api/v1/customers/${encodeURIComponent(id)}/credits/adjust`,
711
- body: input
712
- });
713
- return { remaining: res.remaining };
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
- /** Grant or claw back an outcome balance. Returns the remaining balance. */
716
- async adjustOutcome(id, input) {
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: `/api/v1/customers/${encodeURIComponent(id)}/outcomes/adjust`,
720
- body: input
710
+ path,
711
+ idempotencyKey,
712
+ body: { ...input, idempotencyKey },
713
+ retry: true
721
714
  });
722
- return { remaining: res.remaining };
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
- /** Grant or claw back a unit balance. Returns the remaining balance. */
725
- async adjustUnit(id, input) {
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: "POST",
728
- path: `/api/v1/customers/${encodeURIComponent(id)}/units/adjust`,
733
+ method: "PUT",
734
+ path: `/api/v1/customers/${encodeURIComponent(id)}/recurring-grant`,
729
735
  body: input
730
736
  });
731
- return { remaining: res.remaining };
737
+ return toRecurringGrantResult(res);
732
738
  }
733
- /**
734
- * Grant or claw back slots on a customer's ADVANCE composite pool for the
735
- * current billing cycle. Returns the resulting `remaining` slot count.
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: "POST",
741
- path: `/api/v1/customers/${encodeURIComponent(id)}/composites/adjust`,
743
+ method: "PUT",
744
+ path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/recurring-grant`,
742
745
  body: input
743
746
  });
744
- return { remaining: res.remaining };
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/idempotency.ts
1013
- function newKey() {
1014
- const c = globalThis.crypto;
1015
- if (typeof c?.randomUUID === "function") return c.randomUUID();
1016
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
1017
- const r = Math.random() * 16 | 0;
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
@@ -1033,7 +945,7 @@ var USAGE_LOG_PATH = "/api/v1/signal/usage-log";
1033
945
  function signalToWire(signal) {
1034
946
  const t = signal.tokens;
1035
947
  const body = {
1036
- customerId: signal.customerId,
948
+ ...customerRefToWire(signal),
1037
949
  // `usage` is required on all three model-priced kinds. input/output are
1038
950
  // always sent; `cacheTokens` only when provided (the server defaults 0).
1039
951
  usage: {
@@ -1144,9 +1056,8 @@ var Signals = class {
1144
1056
  path: OUTCOME_COMPLETE_PATH,
1145
1057
  idempotencyKey,
1146
1058
  body: {
1147
- customerId: input.customerId,
1059
+ ...customerRefToWire(input),
1148
1060
  runId: input.runId,
1149
- complete: true,
1150
1061
  ...input.member ? { member: input.member } : {},
1151
1062
  idempotencyKey
1152
1063
  },
@@ -1161,23 +1072,6 @@ var Signals = class {
1161
1072
  ...handles(res)
1162
1073
  };
1163
1074
  }
1164
- /**
1165
- * Recent usage logs + totals for a customer. `GET /api/v1/usage`.
1166
- *
1167
- * Still the legacy path, deliberately. The `/api/v1/signal/*` family is
1168
- * POST-only — it replaced how usage is INGESTED, not how it is read — so
1169
- * `GET /api/v1/usage` has no successor and is not deprecated. It is also the
1170
- * only way to prove a signal landed, which matters more now that ingestion
1171
- * answers `202` for everything.
1172
- */
1173
- async list(params) {
1174
- const res = await this.transport.request({
1175
- method: "GET",
1176
- path: "/api/v1/usage",
1177
- query: { customerId: params.customerId, limit: params.limit }
1178
- });
1179
- return { customer: res.customer, totals: res.totals, logs: res.logs };
1180
- }
1181
1075
  /**
1182
1076
  * Record one unit-metered event (a fixed-price meter with no tokens),
1183
1077
  * addressed to a catalog unit by its `agentKey`. Sent immediately — unit
@@ -1197,7 +1091,7 @@ var Signals = class {
1197
1091
  path: UNIT_PATH,
1198
1092
  idempotencyKey,
1199
1093
  body: {
1200
- customerId: input.customerId,
1094
+ ...customerRefToWire(input),
1201
1095
  agentKey: input.agentKey,
1202
1096
  ...input.quantity != null ? { quantity: input.quantity } : {},
1203
1097
  ...input.member ? { member: input.member } : {},
@@ -1254,7 +1148,7 @@ var Signals = class {
1254
1148
  path: COMPOSITE_COMPLETE_PATH,
1255
1149
  idempotencyKey,
1256
1150
  body: {
1257
- customerId: input.customerId,
1151
+ ...customerRefToWire(input),
1258
1152
  composite: { [input.composite.ref]: input.composite.value },
1259
1153
  // Auto-assigned like the others. A retry here could not double-BILL
1260
1154
  // even without it — closing a closed occurrence is a server-side
@@ -1275,19 +1169,6 @@ var Signals = class {
1275
1169
  ...handles(res)
1276
1170
  };
1277
1171
  }
1278
- /**
1279
- * A customer's unit balances + recent unit events. `GET /api/v1/units`.
1280
- *
1281
- * Legacy path for the same reason as {@link list}: the signal family is
1282
- * POST-only, so the read side has no successor and is not deprecated.
1283
- */
1284
- unitUsage(params) {
1285
- return this.transport.request({
1286
- method: "GET",
1287
- path: "/api/v1/units",
1288
- query: { customerId: params.customerId, limit: params.limit }
1289
- });
1290
- }
1291
1172
  /**
1292
1173
  * One customer's usage history, merged from every meter kind — credit,
1293
1174
  * outcome, unit, wallet, and completed composite occurrences — into one
@@ -1321,133 +1202,13 @@ var Signals = class {
1321
1202
  }
1322
1203
  };
1323
1204
 
1324
- // src/resources/units.ts
1325
- var Units = class {
1326
- constructor(transport) {
1327
- this.transport = transport;
1328
- }
1329
- transport;
1330
- /** List unit types. Pass `{ active: true }` to only return active ones.
1331
- * `{ active: false }` returns only archived ones; omitting it returns
1332
- * both. See `activeQuery` — the API itself only supports `true`. */
1333
- async list(params = {}) {
1334
- const res = await this.transport.request({
1335
- method: "GET",
1336
- path: "/api/v1/units-catalog",
1337
- query: { active: activeQuery(params.active) }
1338
- });
1339
- return filterByActive(res.units, params.active);
1340
- }
1341
- /** Create a unit type. `POST /api/v1/units-catalog`. */
1342
- async create(input) {
1343
- const res = await this.transport.request({
1344
- method: "POST",
1345
- path: "/api/v1/units-catalog",
1346
- body: input
1347
- });
1348
- return res.unit;
1349
- }
1350
- /** Fetch one unit type with stats. `GET /api/v1/units-catalog/:id`. */
1351
- async get(id) {
1352
- const res = await this.transport.request({
1353
- method: "GET",
1354
- path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
1355
- });
1356
- return res.unit;
1357
- }
1358
- /** Update a unit type's definition. `PATCH /api/v1/units-catalog/:id`. */
1359
- async update(id, input) {
1360
- const res = await this.transport.request({
1361
- method: "PATCH",
1362
- path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
1363
- body: input
1364
- });
1365
- return res.unit;
1366
- }
1367
- /** Activate or deactivate a unit type. */
1368
- async setActive(id, isActive) {
1369
- const res = await this.transport.request({
1370
- method: "PATCH",
1371
- path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
1372
- body: { isActive }
1373
- });
1374
- return res.unit;
1375
- }
1376
- /** Delete a unit type. */
1377
- async delete(id) {
1378
- await this.transport.request({
1379
- method: "DELETE",
1380
- path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
1381
- });
1382
- }
1383
- };
1384
-
1385
- // src/resources/webhooks.ts
1386
- var Webhooks = class {
1387
- constructor(transport) {
1388
- this.transport = transport;
1389
- }
1390
- transport;
1391
- /** List configured webhooks. `GET /api/v1/webhooks`. */
1392
- async list() {
1393
- const res = await this.transport.request({
1394
- method: "GET",
1395
- path: "/api/v1/webhooks"
1396
- });
1397
- return res.webhooks;
1398
- }
1399
- /** Create or replace the webhook for a kind. `POST /api/v1/webhooks`. */
1400
- async upsert(input) {
1401
- const res = await this.transport.request({
1402
- method: "POST",
1403
- path: "/api/v1/webhooks",
1404
- body: input
1405
- });
1406
- return res.webhook;
1407
- }
1408
- /** Delete the webhook for a kind (idempotent). `DELETE /api/v1/webhooks/:kind`. */
1409
- async delete(kind) {
1410
- await this.transport.request({
1411
- method: "DELETE",
1412
- path: `/api/v1/webhooks/${encodeURIComponent(kind)}`
1413
- });
1414
- }
1415
- };
1416
-
1417
- // src/resources/workspace.ts
1418
- var Workspace = class {
1419
- constructor(transport) {
1420
- this.transport = transport;
1421
- }
1422
- transport;
1423
- /** Identify the org + key behind the request, incl. `sandbox` | `live`. */
1424
- me() {
1425
- return this.transport.request({
1426
- method: "GET",
1427
- path: "/api/v1/me"
1428
- });
1429
- }
1430
- /** The org's enabled models with live prices. `{ active: true }` returns only
1431
- * the models that can be metered right now.
1432
- * `{ active: false }` returns only archived ones; omitting it returns
1433
- * both. See `activeQuery` — the API itself only supports `true`. */
1434
- async models(params = {}) {
1435
- const res = await this.transport.request({
1436
- method: "GET",
1437
- path: "/api/v1/models",
1438
- query: { active: activeQuery(params.active) }
1439
- });
1440
- return filterByActive(res.models, params.active);
1441
- }
1442
- };
1443
-
1444
1205
  // src/client.ts
1445
1206
  var ClockNext = class {
1446
- /** Record + read usage signals (credit / wallet / outcome / unit). */
1207
+ /** Record usage signals (credit / wallet / outcome / unit) and read the usage log. */
1447
1208
  signals;
1448
- /** Manage customers, their members, wallet, and balances. */
1209
+ /** Manage customers, their members, and balances. */
1449
1210
  customers;
1450
- /** Define and manage billing plans. */
1211
+ /** List billing plans. */
1451
1212
  plans;
1452
1213
  /** Subscribe customers to plans (purchases). */
1453
1214
  purchases;
@@ -1455,20 +1216,8 @@ var ClockNext = class {
1455
1216
  invoices;
1456
1217
  /** Read payments (paid invoices). */
1457
1218
  payments;
1458
- /** Manage the credit-type catalog. */
1459
- credits;
1460
- /** Manage the composite catalog — bundles billed as one thing. */
1461
- composites;
1462
- /** Manage the outcome-type catalog. */
1463
- outcomes;
1464
- /** Manage the unit-type catalog. */
1465
- units;
1466
- /** Configure threshold webhooks. */
1467
- webhooks;
1468
1219
  /** Mint customer-portal embed tokens. */
1469
1220
  portal;
1470
- /** Identify the workspace (sandbox/live) + list its models. `/me`, `/models`. */
1471
- workspace;
1472
1221
  cfg;
1473
1222
  flusher;
1474
1223
  constructor(config) {
@@ -1486,13 +1235,7 @@ var ClockNext = class {
1486
1235
  this.purchases = new Purchases(transport);
1487
1236
  this.invoices = new Invoices(transport);
1488
1237
  this.payments = new Payments(transport);
1489
- this.credits = new Credits(transport);
1490
- this.composites = new Composites(transport);
1491
- this.outcomes = new Outcomes(transport);
1492
- this.units = new Units(transport);
1493
- this.webhooks = new Webhooks(transport);
1494
1238
  this.portal = new Portal(transport);
1495
- this.workspace = new Workspace(transport);
1496
1239
  }
1497
1240
  /** Number of signals currently buffered (async mode). */
1498
1241
  get pending() {