@clocknext/sdk 0.1.0 → 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.
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/config.ts
4
- var DEFAULT_BASE_URL = "https://app.clocknext.com";
4
+ var DEFAULT_BASE_URL = "https://payments.clocknext.com";
5
5
  function num(value, fallback, min) {
6
6
  return typeof value === "number" && Number.isFinite(value) && value >= min ? value : fallback;
7
7
  }
@@ -123,7 +123,8 @@ var Flusher = class {
123
123
  method: "POST",
124
124
  path: "/api/v1/usage",
125
125
  body: item.body,
126
- idempotencyKey: item.idempotencyKey
126
+ // Best-effort metering opts into retries on transient failures.
127
+ retry: true
127
128
  });
128
129
  return true;
129
130
  } catch (error) {
@@ -146,15 +147,12 @@ var Flusher = class {
146
147
  var ClockNextError = class extends Error {
147
148
  /** HTTP status, when the failure came from a server response. */
148
149
  status;
149
- /** The idempotency key of the offending signal, when applicable. */
150
- idempotencyKey;
151
150
  /** Whether the SDK considers this failure worth retrying. */
152
151
  retryable;
153
152
  constructor(message, opts = {}) {
154
153
  super(message);
155
154
  this.name = new.target.name;
156
155
  this.status = opts.status;
157
- this.idempotencyKey = opts.idempotencyKey;
158
156
  this.retryable = opts.retryable ?? false;
159
157
  Object.setPrototypeOf(this, new.target.prototype);
160
158
  }
@@ -174,28 +172,29 @@ var ConflictError = class extends ClockNextError {
174
172
  var RateLimitError = class extends ClockNextError {
175
173
  retryAfterMs;
176
174
  constructor(message, opts = {}) {
177
- super(message, { status: 429, idempotencyKey: opts.idempotencyKey, retryable: true });
175
+ super(message, { status: 429, retryable: true });
178
176
  this.retryAfterMs = opts.retryAfterMs;
179
177
  }
180
178
  };
181
179
  var ServerError = class extends ClockNextError {
182
180
  };
183
181
  var NetworkError = class extends ClockNextError {
184
- constructor(message, opts = {}) {
185
- super(message, { idempotencyKey: opts.idempotencyKey, retryable: true });
182
+ constructor(message) {
183
+ super(message, { retryable: true });
186
184
  }
187
185
  };
188
- function errorFromResponse(status, message, idempotencyKey, retryAfterMs) {
186
+ function errorFromResponse(status, message, retryAfterMs) {
189
187
  const msg = message || `Request failed with status ${status}.`;
190
- const opts = { status, idempotencyKey };
188
+ const opts = { status };
191
189
  if (status === 400) return new ValidationError(msg, opts);
192
190
  if (status === 401) return new AuthError(msg, opts);
193
191
  if (status === 404) return new NotFoundError(msg, opts);
192
+ if (status === 408) return new ClockNextError(msg, { ...opts, retryable: true });
194
193
  if (status === 409) return new ConflictError(msg, { ...opts, retryable: true });
195
194
  if (status === 422) {
196
195
  return /insufficient/i.test(msg) ? new AllowanceError(msg, opts) : new PlanError(msg, opts);
197
196
  }
198
- if (status === 429) return new RateLimitError(msg, { idempotencyKey, retryAfterMs });
197
+ if (status === 429) return new RateLimitError(msg, { retryAfterMs });
199
198
  if (status >= 500) return new ServerError(msg, { ...opts, retryable: true });
200
199
  return new ClockNextError(msg, opts);
201
200
  }
@@ -230,7 +229,7 @@ function sleep(ms) {
230
229
  }
231
230
 
232
231
  // src/http.ts
233
- var SDK_VERSION = "0.1.0";
232
+ var SDK_VERSION = "0.3.0" ;
234
233
  var Transport = class {
235
234
  constructor(cfg) {
236
235
  this.cfg = cfg;
@@ -238,8 +237,9 @@ var Transport = class {
238
237
  cfg;
239
238
  async request(opts) {
240
239
  const url = this.buildUrl(opts.path, opts.query);
241
- const replaySafe = opts.method === "GET" || opts.method === "DELETE" || opts.idempotencyKey != null;
242
- const maxAttempts = opts.retry === false || !replaySafe ? 1 : this.cfg.retry.maxAttempts;
240
+ const replaySafe = opts.method === "GET" || opts.method === "PUT" || opts.method === "DELETE";
241
+ const allowRetry = opts.retry ?? replaySafe;
242
+ const maxAttempts = allowRetry ? this.cfg.retry.maxAttempts : 1;
243
243
  let attempt = 0;
244
244
  while (true) {
245
245
  attempt++;
@@ -273,7 +273,7 @@ var Transport = class {
273
273
  });
274
274
  } catch (err) {
275
275
  const message2 = controller.signal.aborted ? `Request to ${opts.path} timed out after ${this.cfg.timeoutMs}ms.` : `Network error calling ${opts.path}: ${err instanceof Error ? err.message : String(err)}`;
276
- throw new NetworkError(message2, { idempotencyKey: opts.idempotencyKey });
276
+ throw new NetworkError(message2);
277
277
  } finally {
278
278
  clearTimeout(timer);
279
279
  }
@@ -293,24 +293,14 @@ var Transport = class {
293
293
  return obj.result ?? {};
294
294
  }
295
295
  const message2 = detail?.message ?? `Request failed with status ${res.status}.`;
296
- throw errorFromResponse(
297
- res.status,
298
- message2,
299
- opts.idempotencyKey,
300
- parseRetryAfter(res.headers)
301
- );
296
+ throw errorFromResponse(res.status, message2, parseRetryAfter(res.headers));
302
297
  }
303
298
  const envelope = obj;
304
299
  if (res.ok && envelope.ok !== false) {
305
300
  return envelope;
306
301
  }
307
302
  const message = envelope.error ?? text ?? `Request failed with status ${res.status}.`;
308
- throw errorFromResponse(
309
- res.status,
310
- message,
311
- opts.idempotencyKey,
312
- parseRetryAfter(res.headers)
313
- );
303
+ throw errorFromResponse(res.status, message, parseRetryAfter(res.headers));
314
304
  }
315
305
  headers(opts) {
316
306
  const h = {
@@ -318,7 +308,6 @@ var Transport = class {
318
308
  "User-Agent": `clocknext-sdk-js/${SDK_VERSION}`
319
309
  };
320
310
  if (opts.body !== void 0) h["Content-Type"] = "application/json";
321
- if (opts.idempotencyKey) h["Idempotency-Key"] = opts.idempotencyKey;
322
311
  return h;
323
312
  }
324
313
  buildUrl(path, query) {
@@ -335,6 +324,63 @@ var Transport = class {
335
324
  }
336
325
  };
337
326
 
327
+ // src/resources/credits.ts
328
+ var Credits = class {
329
+ constructor(transport) {
330
+ this.transport = transport;
331
+ }
332
+ transport;
333
+ /** List credit types. Pass `{ active: true }` to only return active ones. */
334
+ async list(params = {}) {
335
+ const res = await this.transport.request({
336
+ method: "GET",
337
+ path: "/api/v1/credits",
338
+ query: { active: params.active === void 0 ? void 0 : String(params.active) }
339
+ });
340
+ return res.credits;
341
+ }
342
+ /** Create a credit type. `POST /api/v1/credits`. */
343
+ async create(input) {
344
+ await this.transport.request({
345
+ method: "POST",
346
+ path: "/api/v1/credits",
347
+ body: input
348
+ });
349
+ }
350
+ /** Fetch one credit type with usage stats. `GET /api/v1/credits/:id`. */
351
+ async get(id) {
352
+ const res = await this.transport.request({
353
+ method: "GET",
354
+ path: `/api/v1/credits/${encodeURIComponent(id)}`
355
+ });
356
+ return res.credit;
357
+ }
358
+ /** Update a credit type's definition. `PATCH /api/v1/credits/:id`. */
359
+ async update(id, input) {
360
+ await this.transport.request({
361
+ method: "PATCH",
362
+ path: `/api/v1/credits/${encodeURIComponent(id)}`,
363
+ body: input
364
+ });
365
+ }
366
+ /** Activate or deactivate a credit type. */
367
+ async setActive(id, isActive) {
368
+ const res = await this.transport.request({
369
+ method: "PATCH",
370
+ path: `/api/v1/credits/${encodeURIComponent(id)}`,
371
+ body: { isActive }
372
+ });
373
+ return res.credit;
374
+ }
375
+ /** Delete a credit type. Refused while a customer is linked to it. */
376
+ async delete(id) {
377
+ await this.transport.request({
378
+ method: "DELETE",
379
+ path: `/api/v1/credits/${encodeURIComponent(id)}`
380
+ });
381
+ }
382
+ };
383
+
338
384
  // src/resources/customers.ts
339
385
  var Customers = class {
340
386
  constructor(transport) {
@@ -426,6 +472,282 @@ var Customers = class {
426
472
  query: { range: params.range }
427
473
  });
428
474
  }
475
+ // --- Members -------------------------------------------------------------
476
+ /** List a customer's members. `GET …/:id/members`. */
477
+ async listMembers(id) {
478
+ const res = await this.transport.request({
479
+ method: "GET",
480
+ path: `/api/v1/customers/${encodeURIComponent(id)}/members`
481
+ });
482
+ return res.members;
483
+ }
484
+ /** Add a member to a customer. Duplicate `employeeId` → ConflictError. */
485
+ async addMember(id, input) {
486
+ const res = await this.transport.request({
487
+ method: "POST",
488
+ path: `/api/v1/customers/${encodeURIComponent(id)}/members`,
489
+ body: input
490
+ });
491
+ return res.member;
492
+ }
493
+ /** Update a member's profile (role is fixed). `PATCH …/:id/members/:memberId`. */
494
+ async updateMember(id, memberId, input) {
495
+ const res = await this.transport.request({
496
+ method: "PATCH",
497
+ path: `/api/v1/customers/${encodeURIComponent(id)}/members/${encodeURIComponent(memberId)}`,
498
+ body: input
499
+ });
500
+ return res.member;
501
+ }
502
+ /** Remove a member from a customer. `DELETE …/:id/members/:memberId`. */
503
+ async removeMember(id, memberId) {
504
+ await this.transport.request({
505
+ method: "DELETE",
506
+ path: `/api/v1/customers/${encodeURIComponent(id)}/members/${encodeURIComponent(memberId)}`
507
+ });
508
+ }
509
+ // --- Wallet & billing config --------------------------------------------
510
+ /** The customer's wallet balance + transactions. `GET …/:id/wallet`. */
511
+ wallet(id, params = {}) {
512
+ return this.transport.request({
513
+ method: "GET",
514
+ path: `/api/v1/customers/${encodeURIComponent(id)}/wallet`,
515
+ query: { limit: params.limit }
516
+ });
517
+ }
518
+ /**
519
+ * Record a manual wallet entry (top-up or deduction). `amount` is always
520
+ * positive; the sign comes from `type`. `POST …/:id/wallet`.
521
+ */
522
+ async addWalletEntry(id, input) {
523
+ return this.transport.request({
524
+ method: "POST",
525
+ path: `/api/v1/customers/${encodeURIComponent(id)}/wallet`,
526
+ body: input
527
+ });
528
+ }
529
+ /** Set the customer's currency. `PUT …/:id/currency`. */
530
+ async setCurrency(id, currencyCode) {
531
+ await this.transport.request({
532
+ method: "PUT",
533
+ path: `/api/v1/customers/${encodeURIComponent(id)}/currency`,
534
+ body: { currencyCode }
535
+ });
536
+ }
537
+ /** Set which credit types the customer is billed against. `PUT …/:id/credits`. */
538
+ async setCreditTypes(id, creditIds) {
539
+ await this.transport.request({
540
+ method: "PUT",
541
+ path: `/api/v1/customers/${encodeURIComponent(id)}/credits`,
542
+ body: { creditIds }
543
+ });
544
+ }
545
+ // --- Balance adjustments -------------------------------------------------
546
+ /** Grant or claw back a credit balance. `POST …/:id/credits/adjust`. */
547
+ async adjustCredit(id, input) {
548
+ await this.transport.request({
549
+ method: "POST",
550
+ path: `/api/v1/customers/${encodeURIComponent(id)}/credits/adjust`,
551
+ body: input
552
+ });
553
+ }
554
+ /** Grant or claw back an outcome balance. Returns the remaining balance. */
555
+ async adjustOutcome(id, input) {
556
+ const res = await this.transport.request({
557
+ method: "POST",
558
+ path: `/api/v1/customers/${encodeURIComponent(id)}/outcomes/adjust`,
559
+ body: input
560
+ });
561
+ return { remaining: res.remaining };
562
+ }
563
+ /** Grant or claw back a unit balance. Returns the remaining balance. */
564
+ async adjustUnit(id, input) {
565
+ const res = await this.transport.request({
566
+ method: "POST",
567
+ path: `/api/v1/customers/${encodeURIComponent(id)}/units/adjust`,
568
+ body: input
569
+ });
570
+ return { remaining: res.remaining };
571
+ }
572
+ };
573
+
574
+ // src/resources/invoices.ts
575
+ var Invoices = class {
576
+ constructor(transport) {
577
+ this.transport = transport;
578
+ }
579
+ transport;
580
+ /** List invoices, most-recent first. Filter by customer and/or status. */
581
+ async list(params = {}) {
582
+ const res = await this.transport.request({
583
+ method: "GET",
584
+ path: "/api/v1/invoices",
585
+ query: {
586
+ customerId: params.customerId,
587
+ status: params.status,
588
+ limit: params.limit
589
+ }
590
+ });
591
+ return res.invoices;
592
+ }
593
+ /** Fetch one full invoice + its plan snapshot. `GET /api/v1/invoices/:id`. */
594
+ get(id) {
595
+ return this.transport.request({
596
+ method: "GET",
597
+ path: `/api/v1/invoices/${encodeURIComponent(id)}`
598
+ });
599
+ }
600
+ /**
601
+ * Mint a hosted pay link for an OPEN invoice. PAID/VOID invoices are rejected
602
+ * with a `ConflictError`. `GET /api/v1/invoices/:id/pay-link`.
603
+ */
604
+ payLink(id) {
605
+ return this.transport.request({
606
+ method: "GET",
607
+ path: `/api/v1/invoices/${encodeURIComponent(id)}/pay-link`
608
+ });
609
+ }
610
+ };
611
+
612
+ // src/resources/outcomes.ts
613
+ var Outcomes = class {
614
+ constructor(transport) {
615
+ this.transport = transport;
616
+ }
617
+ transport;
618
+ /** List outcome types. Pass `{ active: true }` to only return active ones. */
619
+ async list(params = {}) {
620
+ const res = await this.transport.request({
621
+ method: "GET",
622
+ path: "/api/v1/outcomes",
623
+ query: { active: params.active === void 0 ? void 0 : String(params.active) }
624
+ });
625
+ return res.outcomes;
626
+ }
627
+ /** Create an outcome type with its steps. `POST /api/v1/outcomes`. */
628
+ async create(input) {
629
+ const res = await this.transport.request({
630
+ method: "POST",
631
+ path: "/api/v1/outcomes",
632
+ body: input
633
+ });
634
+ return res.outcome;
635
+ }
636
+ /** Fetch one outcome type with steps + stats. `GET /api/v1/outcomes/:id`. */
637
+ async get(id) {
638
+ const res = await this.transport.request({
639
+ method: "GET",
640
+ path: `/api/v1/outcomes/${encodeURIComponent(id)}`
641
+ });
642
+ return res.outcome;
643
+ }
644
+ /** Update an outcome type's definition. `PATCH /api/v1/outcomes/:id`. */
645
+ async update(id, input) {
646
+ const res = await this.transport.request({
647
+ method: "PATCH",
648
+ path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
649
+ body: input
650
+ });
651
+ return res.outcome;
652
+ }
653
+ /** Activate or deactivate an outcome type. */
654
+ async setActive(id, isActive) {
655
+ await this.transport.request({
656
+ method: "PATCH",
657
+ path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
658
+ body: { isActive }
659
+ });
660
+ }
661
+ /** Delete an outcome type. */
662
+ async delete(id) {
663
+ await this.transport.request({
664
+ method: "DELETE",
665
+ path: `/api/v1/outcomes/${encodeURIComponent(id)}`
666
+ });
667
+ }
668
+ };
669
+
670
+ // src/resources/payments.ts
671
+ var Payments = class {
672
+ constructor(transport) {
673
+ this.transport = transport;
674
+ }
675
+ transport;
676
+ /** List payments (paid invoices), most-recent first. Filter by customer. */
677
+ async list(params = {}) {
678
+ const res = await this.transport.request({
679
+ method: "GET",
680
+ path: "/api/v1/payments",
681
+ query: { customerId: params.customerId, limit: params.limit }
682
+ });
683
+ return res.payments;
684
+ }
685
+ /** Fetch one payment + its plan snapshot. `GET /api/v1/payments/:id`. */
686
+ get(id) {
687
+ return this.transport.request({
688
+ method: "GET",
689
+ path: `/api/v1/payments/${encodeURIComponent(id)}`
690
+ });
691
+ }
692
+ };
693
+
694
+ // src/resources/plans.ts
695
+ var Plans = class {
696
+ constructor(transport) {
697
+ this.transport = transport;
698
+ }
699
+ transport;
700
+ /** List plans, oldest-first. Pass `{ active: true }` to only return active plans. */
701
+ async list(params = {}) {
702
+ const res = await this.transport.request({
703
+ method: "GET",
704
+ path: "/api/v1/plans",
705
+ query: { active: params.active === void 0 ? void 0 : String(params.active) }
706
+ });
707
+ return res.plans;
708
+ }
709
+ /** Create a plan. `POST /api/v1/plans`. */
710
+ async create(input) {
711
+ const res = await this.transport.request({
712
+ method: "POST",
713
+ path: "/api/v1/plans",
714
+ body: input
715
+ });
716
+ return res.plan;
717
+ }
718
+ /** Fetch one plan with aggregate subscriber/invoice stats. `GET /api/v1/plans/:id`. */
719
+ async get(id) {
720
+ const res = await this.transport.request({
721
+ method: "GET",
722
+ path: `/api/v1/plans/${encodeURIComponent(id)}`
723
+ });
724
+ return res.plan;
725
+ }
726
+ /** Replace a plan's definition (components + settings). `PATCH /api/v1/plans/:id`. */
727
+ async update(id, input) {
728
+ const res = await this.transport.request({
729
+ method: "PATCH",
730
+ path: `/api/v1/plans/${encodeURIComponent(id)}`,
731
+ body: input
732
+ });
733
+ return res.plan;
734
+ }
735
+ /** Activate or deactivate a plan without rewriting it. */
736
+ async setActive(id, isActive) {
737
+ const res = await this.transport.request({
738
+ method: "PATCH",
739
+ path: `/api/v1/plans/${encodeURIComponent(id)}`,
740
+ body: { isActive }
741
+ });
742
+ return res.plan;
743
+ }
744
+ /** Delete a plan. Refused once any customer has purchased it. */
745
+ async delete(id) {
746
+ await this.transport.request({
747
+ method: "DELETE",
748
+ path: `/api/v1/plans/${encodeURIComponent(id)}`
749
+ });
750
+ }
429
751
  };
430
752
 
431
753
  // src/resources/portal.ts
@@ -452,21 +774,61 @@ var Portal = class {
452
774
  }
453
775
  };
454
776
 
455
- // src/idempotency.ts
456
- function newIdempotencyKey() {
457
- const webcrypto = globalThis.crypto;
458
- if (webcrypto?.randomUUID) return webcrypto.randomUUID();
459
- const b = new Uint8Array(16);
460
- if (webcrypto?.getRandomValues) {
461
- webcrypto.getRandomValues(b);
462
- } else {
463
- for (let i = 0; i < 16; i++) b[i] = Math.floor(Math.random() * 256);
464
- }
465
- b[6] = b[6] & 15 | 64;
466
- b[8] = b[8] & 63 | 128;
467
- const hex = Array.from(b, (n) => n.toString(16).padStart(2, "0")).join("");
468
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
469
- }
777
+ // src/resources/purchases.ts
778
+ var Purchases = class {
779
+ constructor(transport) {
780
+ this.transport = transport;
781
+ }
782
+ transport;
783
+ /** List purchases, most-recent first. Filter by customer and/or status. */
784
+ async list(params = {}) {
785
+ const res = await this.transport.request({
786
+ method: "GET",
787
+ path: "/api/v1/purchases",
788
+ query: {
789
+ customerId: params.customerId,
790
+ status: params.status,
791
+ limit: params.limit
792
+ }
793
+ });
794
+ return res.purchases;
795
+ }
796
+ /** Subscribe a customer to a plan. `POST /api/v1/purchases`. */
797
+ async create(input) {
798
+ const res = await this.transport.request({
799
+ method: "POST",
800
+ path: "/api/v1/purchases",
801
+ body: input
802
+ });
803
+ return res.purchase;
804
+ }
805
+ /** Fetch one purchase. `GET /api/v1/purchases/:id`. */
806
+ async get(id) {
807
+ const res = await this.transport.request({
808
+ method: "GET",
809
+ path: `/api/v1/purchases/${encodeURIComponent(id)}`
810
+ });
811
+ return res.purchase;
812
+ }
813
+ /**
814
+ * Turn automatic billing on or off for a purchase. When pausing, an optional
815
+ * `pauseReason` is recorded. `PATCH /api/v1/purchases/:id`.
816
+ */
817
+ async setAutoPayment(id, autoPayment, opts = {}) {
818
+ return this.transport.request({
819
+ method: "PATCH",
820
+ path: `/api/v1/purchases/${encodeURIComponent(id)}`,
821
+ body: { autoPayment, pauseReason: opts.pauseReason }
822
+ });
823
+ }
824
+ /** Cancel a purchase (voids any open invoice). `POST /api/v1/purchases/:id/cancel`. */
825
+ async cancel(id) {
826
+ await this.transport.request({
827
+ method: "POST",
828
+ path: `/api/v1/purchases/${encodeURIComponent(id)}/cancel`
829
+ });
830
+ }
831
+ };
470
832
 
471
833
  // src/resources/signals.ts
472
834
  function signalToWire(signal) {
@@ -478,7 +840,6 @@ function signalToWire(signal) {
478
840
  if (signal.member) body.member = signal.member;
479
841
  if (signal.status) body.status = signal.status;
480
842
  if (signal.custom) body.custom = signal.custom;
481
- if (signal.idempotencyKey) body.idempotencyKey = signal.idempotencyKey;
482
843
  const t = signal.tokens;
483
844
  if (t) {
484
845
  if (t.input != null) body.inputTokens = t.input;
@@ -486,7 +847,7 @@ function signalToWire(signal) {
486
847
  if (t.cache != null) body.cacheTokens = t.cache;
487
848
  }
488
849
  if (signal.type === "credit" || signal.type === "outcome") {
489
- body.key = signal.key;
850
+ body.agentKey = signal.agentKey;
490
851
  }
491
852
  return body;
492
853
  }
@@ -500,21 +861,20 @@ var Signals = class {
500
861
  flusher;
501
862
  cfg;
502
863
  async track(signal, opts = {}) {
503
- const idempotencyKey = signal.idempotencyKey ?? newIdempotencyKey();
504
- const body = signalToWire({ ...signal, idempotencyKey });
864
+ const body = signalToWire(signal);
505
865
  const sendNow = opts.wait || this.cfg.mode === "sync";
506
866
  if (!sendNow) {
507
- this.flusher.enqueue({ body, idempotencyKey, signal });
508
- return { idempotencyKey, queued: true };
867
+ this.flusher.enqueue({ body, signal });
868
+ return { queued: true };
509
869
  }
510
870
  const res = await this.transport.request({
511
871
  method: "POST",
512
872
  path: "/api/v1/usage",
513
873
  body,
514
- idempotencyKey
874
+ // Best-effort metering opts into retries on transient failures.
875
+ retry: true
515
876
  });
516
877
  return {
517
- idempotencyKey,
518
878
  queued: false,
519
879
  usageLog: res.usageLog ?? null
520
880
  };
@@ -540,14 +900,147 @@ var Signals = class {
540
900
  });
541
901
  return { customer: res.customer, totals: res.totals, logs: res.logs };
542
902
  }
903
+ /**
904
+ * Record one unit-metered event (a fixed-price meter with no tokens), matched
905
+ * to a catalog unit by name. Sent immediately — unit events are not buffered.
906
+ * `POST /api/v1/units`.
907
+ */
908
+ async unit(input) {
909
+ return this.transport.request({
910
+ method: "POST",
911
+ path: "/api/v1/units",
912
+ body: {
913
+ customerId: input.customerId,
914
+ unit: input.unit,
915
+ ...input.member ? { member: input.member } : {}
916
+ },
917
+ // Best-effort metering opts into retries on transient failures.
918
+ retry: true
919
+ });
920
+ }
921
+ /** A customer's unit balances + recent unit events. `GET /api/v1/units`. */
922
+ unitUsage(params) {
923
+ return this.transport.request({
924
+ method: "GET",
925
+ path: "/api/v1/units",
926
+ query: { customerId: params.customerId, limit: params.limit }
927
+ });
928
+ }
929
+ };
930
+
931
+ // src/resources/units.ts
932
+ var Units = class {
933
+ constructor(transport) {
934
+ this.transport = transport;
935
+ }
936
+ transport;
937
+ /** List unit types. Pass `{ active: true }` to only return active ones. */
938
+ async list(params = {}) {
939
+ const res = await this.transport.request({
940
+ method: "GET",
941
+ path: "/api/v1/units-catalog",
942
+ query: { active: params.active === void 0 ? void 0 : String(params.active) }
943
+ });
944
+ return res.units;
945
+ }
946
+ /** Create a unit type. `POST /api/v1/units-catalog`. */
947
+ async create(input) {
948
+ const res = await this.transport.request({
949
+ method: "POST",
950
+ path: "/api/v1/units-catalog",
951
+ body: input
952
+ });
953
+ return res.unit;
954
+ }
955
+ /** Fetch one unit type with stats. `GET /api/v1/units-catalog/:id`. */
956
+ async get(id) {
957
+ const res = await this.transport.request({
958
+ method: "GET",
959
+ path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
960
+ });
961
+ return res.unit;
962
+ }
963
+ /** Update a unit type's definition. `PATCH /api/v1/units-catalog/:id`. */
964
+ async update(id, input) {
965
+ const res = await this.transport.request({
966
+ method: "PATCH",
967
+ path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
968
+ body: input
969
+ });
970
+ return res.unit;
971
+ }
972
+ /** Activate or deactivate a unit type. */
973
+ async setActive(id, isActive) {
974
+ const res = await this.transport.request({
975
+ method: "PATCH",
976
+ path: `/api/v1/units-catalog/${encodeURIComponent(id)}`,
977
+ body: { isActive }
978
+ });
979
+ return res.unit;
980
+ }
981
+ /** Delete a unit type. */
982
+ async delete(id) {
983
+ await this.transport.request({
984
+ method: "DELETE",
985
+ path: `/api/v1/units-catalog/${encodeURIComponent(id)}`
986
+ });
987
+ }
988
+ };
989
+
990
+ // src/resources/webhooks.ts
991
+ var Webhooks = class {
992
+ constructor(transport) {
993
+ this.transport = transport;
994
+ }
995
+ transport;
996
+ /** List configured webhooks. `GET /api/v1/webhooks`. */
997
+ async list() {
998
+ const res = await this.transport.request({
999
+ method: "GET",
1000
+ path: "/api/v1/webhooks"
1001
+ });
1002
+ return res.webhooks;
1003
+ }
1004
+ /** Create or replace the webhook for a kind. `POST /api/v1/webhooks`. */
1005
+ async upsert(input) {
1006
+ const res = await this.transport.request({
1007
+ method: "POST",
1008
+ path: "/api/v1/webhooks",
1009
+ body: input
1010
+ });
1011
+ return res.webhook;
1012
+ }
1013
+ /** Delete the webhook for a kind (idempotent). `DELETE /api/v1/webhooks/:kind`. */
1014
+ async delete(kind) {
1015
+ await this.transport.request({
1016
+ method: "DELETE",
1017
+ path: `/api/v1/webhooks/${encodeURIComponent(kind)}`
1018
+ });
1019
+ }
543
1020
  };
544
1021
 
545
1022
  // src/client.ts
546
1023
  var ClockNext = class {
547
- /** Record + read usage signals. */
1024
+ /** Record + read usage signals (credit / wallet / outcome / unit). */
548
1025
  signals;
549
- /** Manage customers and read their insights. */
1026
+ /** Manage customers, their members, wallet, and balances. */
550
1027
  customers;
1028
+ /** Define and manage billing plans. */
1029
+ plans;
1030
+ /** Subscribe customers to plans (purchases). */
1031
+ purchases;
1032
+ /** Read invoices and mint hosted pay links. */
1033
+ invoices;
1034
+ /** Read payments (paid invoices). */
1035
+ payments;
1036
+ /** Manage the credit-type catalog. */
1037
+ credits;
1038
+ /** Manage the outcome-type catalog. */
1039
+ outcomes;
1040
+ /** Manage the unit-type catalog. */
1041
+ units;
1042
+ /** Configure threshold webhooks. */
1043
+ webhooks;
551
1044
  /** Mint customer-portal embed tokens. */
552
1045
  portal;
553
1046
  cfg;
@@ -563,6 +1056,14 @@ var ClockNext = class {
563
1056
  this.flusher = new Flusher(transport, this.cfg);
564
1057
  this.signals = new Signals(transport, this.flusher, this.cfg);
565
1058
  this.customers = new Customers(transport);
1059
+ this.plans = new Plans(transport);
1060
+ this.purchases = new Purchases(transport);
1061
+ this.invoices = new Invoices(transport);
1062
+ this.payments = new Payments(transport);
1063
+ this.credits = new Credits(transport);
1064
+ this.outcomes = new Outcomes(transport);
1065
+ this.units = new Units(transport);
1066
+ this.webhooks = new Webhooks(transport);
566
1067
  this.portal = new Portal(transport);
567
1068
  }
568
1069
  /** Number of signals currently buffered (async mode). */
@@ -590,7 +1091,6 @@ exports.PlanError = PlanError;
590
1091
  exports.RateLimitError = RateLimitError;
591
1092
  exports.ServerError = ServerError;
592
1093
  exports.ValidationError = ValidationError;
593
- exports.newIdempotencyKey = newIdempotencyKey;
594
1094
  exports.signalToWire = signalToWire;
595
1095
  //# sourceMappingURL=index.cjs.map
596
1096
  //# sourceMappingURL=index.cjs.map