@clocknext/sdk 0.15.0 → 0.17.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 +94 -8
- package/dist/index.cjs +334 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +474 -30
- package/dist/index.d.ts +474 -30
- package/dist/index.js +334 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +17 -1
- package/src/errors.ts +2 -1
- package/src/index.ts +26 -0
- package/src/resources/composites.ts +82 -0
- package/src/resources/credits.ts +81 -0
- package/src/resources/customers.ts +1 -1
- package/src/resources/outcomes.ts +81 -0
- package/src/resources/plans.ts +62 -4
- package/src/resources/signals.ts +3 -1
- package/src/resources/units.ts +76 -0
- package/src/types.ts +346 -22
package/README.md
CHANGED
|
@@ -193,6 +193,22 @@ Signals are billable usage events. Each kind posts to its own route.
|
|
|
193
193
|
`signals.track(signal)` is the underlying call the four convenience methods wrap;
|
|
194
194
|
use it when the kind is dynamic.
|
|
195
195
|
|
|
196
|
+
`tokens` takes `input` and `output` (required), plus two optional prompt-cache
|
|
197
|
+
counts that each default to 0:
|
|
198
|
+
|
|
199
|
+
- `cache` — tokens **read** from the prompt cache, priced at the model's cache-read rate.
|
|
200
|
+
- `cacheWrite` — tokens **written** into the prompt cache, priced at the model's
|
|
201
|
+
separate cache-write rate.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
await cnk.signals.credit({
|
|
205
|
+
customerId,
|
|
206
|
+
model: "claude-sonnet-4-5",
|
|
207
|
+
agentKey: "api_credit",
|
|
208
|
+
tokens: { input: 1200, output: 340, cache: 800, cacheWrite: 2000 },
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
196
212
|
Every signal method can take `externalId` (your own id for the customer — see
|
|
197
213
|
[Your own customer ids](#your-own-customer-ids)) instead of `customerId`.
|
|
198
214
|
|
|
@@ -528,10 +544,12 @@ signal log tells you why an individual signal did not.
|
|
|
528
544
|
|
|
529
545
|
```ts
|
|
530
546
|
const balances = await cnk.customers.balances(customerId);
|
|
531
|
-
balances.wallet
|
|
547
|
+
balances.wallet.balance; // USD; always present
|
|
548
|
+
balances.wallet.reservedBalance; // USD; undefined unless Reserved Wallet is on
|
|
532
549
|
balances.credits; // granted, used, remaining
|
|
533
550
|
balances.outcomes; // granted, remaining, steps
|
|
534
551
|
balances.units; // granted, remaining
|
|
552
|
+
balances.composites; // prepaid composite pools: refId, granted, used, remaining
|
|
535
553
|
|
|
536
554
|
// Convenience lookups — these fetch the full snapshot, so prefer `balances()`
|
|
537
555
|
// when you need more than one row from the same customer.
|
|
@@ -584,19 +602,20 @@ the customer's ordinary wallet (Settings → Organisation → "Enable Reserved
|
|
|
584
602
|
balance in wallet"). When a wallet-funded Arrear charge comes in, it draws from
|
|
585
603
|
the Wallet first, then from the Reserved Wallet down to 0, and anything still
|
|
586
604
|
left pushes the Wallet negative. The Reserved Wallet itself never goes
|
|
587
|
-
negative, and a normal (`
|
|
605
|
+
negative, and a normal (`main`) wallet adjustment never touches it.
|
|
588
606
|
|
|
589
607
|
```ts
|
|
590
608
|
// Top up (or, with a negative delta, reduce) the Reserved Wallet.
|
|
591
|
-
const { remaining } = await cnk.customers.adjustWallet(customerId, { delta: 500, pool: "
|
|
609
|
+
const { remaining } = await cnk.customers.adjustWallet(customerId, { delta: 500, pool: "reserved" });
|
|
592
610
|
// `remaining` is the Reserved balance. Reducing below 0 is refused with an
|
|
593
|
-
// AllowanceError (down to exactly 0 is fine); any
|
|
611
|
+
// AllowanceError (down to exactly 0 is fine); any "reserved" call when the
|
|
594
612
|
// workspace hasn't enabled the feature is a PlanError.
|
|
595
613
|
|
|
596
|
-
const {
|
|
614
|
+
const { wallet } = await cnk.customers.balances(customerId);
|
|
615
|
+
wallet.reservedBalance; // number | undefined
|
|
597
616
|
```
|
|
598
617
|
|
|
599
|
-
|
|
618
|
+
When the feature is off, `wallet.reservedBalance` is left out of `balances()`.
|
|
600
619
|
|
|
601
620
|
To change how much a customer is granted **every billing cycle** (not just
|
|
602
621
|
their balance right now), use `updateRecurringGrant`. Any increase or decrease
|
|
@@ -685,8 +704,75 @@ Customer objects carry `externalId`. Everything else — `signals.usageLog()`,
|
|
|
685
704
|
the invoice, payment and purchase lists, `portal.createToken()` and members —
|
|
686
705
|
still takes ClockNext's id.
|
|
687
706
|
|
|
688
|
-
|
|
689
|
-
|
|
707
|
+
## Catalogue: credits, outcomes, units, composites and plans
|
|
708
|
+
|
|
709
|
+
Each of `cnk.credits`, `cnk.outcomes`, `cnk.units`, `cnk.composites` and
|
|
710
|
+
`cnk.plans` has the same six calls: `list()`, `get(id)`, `create(input)`,
|
|
711
|
+
`update(id, input)`, `archive(id)` and `unarchive(id)`.
|
|
712
|
+
|
|
713
|
+
- **Nothing is deleted.** There is no `delete()`: retire an item with
|
|
714
|
+
`archive()`, bring it back with `unarchive()`. Usage history never loses
|
|
715
|
+
what it points at.
|
|
716
|
+
- **`update()` is partial** — only the fields you send change. A list you do
|
|
717
|
+
send (`modelBundle`, `steps`, `tiers`, `entitlements`) is the complete new
|
|
718
|
+
list.
|
|
719
|
+
- **Prices are never typed in.** A credit or outcome step sends a
|
|
720
|
+
`modelBundle` — one line per model — and ClockNext works the price out from
|
|
721
|
+
the models' live prices.
|
|
722
|
+
- **A plan's currency** is your workspace's primary currency; it can't be set.
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
const credit = await cnk.credits.create({
|
|
726
|
+
name: "Deep Research",
|
|
727
|
+
agentKey: "deep_research",
|
|
728
|
+
marginPercent: 20,
|
|
729
|
+
modelBundle: [
|
|
730
|
+
{ modelId: "claude-sonnet-4-5", averageTokensPerLLMCall: 100000, input: 60, output: 30, cache: 5, cacheWrite: 5 },
|
|
731
|
+
],
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
const outcome = await cnk.outcomes.create({
|
|
735
|
+
name: "Contract review",
|
|
736
|
+
agentKey: "contract_review",
|
|
737
|
+
marginPercent: 100,
|
|
738
|
+
steps: [
|
|
739
|
+
{ name: "Extract clauses", agentKey: "contract_review.extract",
|
|
740
|
+
modelBundle: [{ modelId: "claude-sonnet-4-5", averageTokensPerLLMCall: 50000, input: 70, output: 30, cache: 0 }] },
|
|
741
|
+
],
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const unit = await cnk.units.create({
|
|
745
|
+
name: "API calls",
|
|
746
|
+
agentKey: "api_calls",
|
|
747
|
+
pricingType: "SLAB",
|
|
748
|
+
tiers: [{ upTo: 1000, price: 0.01 }, { upTo: null, price: 0.005 }], // last tier: "and above"
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const composite = await cnk.composites.create({
|
|
752
|
+
name: "Voice AI call",
|
|
753
|
+
refId: "voice_ai",
|
|
754
|
+
price: 2.5,
|
|
755
|
+
entitlements: { creditIds: [credit.id] },
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
const plan = await cnk.plans.create({
|
|
759
|
+
name: "Pro",
|
|
760
|
+
billingCycle: "MONTHLY",
|
|
761
|
+
entitlements: [
|
|
762
|
+
{ type: "CREDIT", billingMode: "ADVANCE", creditId: credit.id, quantity: 1000, rollover: true },
|
|
763
|
+
{ type: "OUTCOME", billingMode: "ARREAR", outcomeId: outcome.id },
|
|
764
|
+
{ type: "PRICING_METRIC", billingMode: "ADVANCE", compositeId: composite.id, quantity: 50 },
|
|
765
|
+
{ type: "WALLET", billingMode: "ADVANCE", amount: 25 },
|
|
766
|
+
],
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
await cnk.credits.update(credit.id, { marginPercent: 50 }); // only the margin changes
|
|
770
|
+
await cnk.units.archive(unit.id); // retire it
|
|
771
|
+
await cnk.units.unarchive(unit.id); // and bring it back
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
Models are enabled in the ClockNext dashboard. A bundle line names its model by
|
|
775
|
+
`modelId` — the same id you send as `usage.model` on a signal.
|
|
690
776
|
|
|
691
777
|
## Customer portal
|
|
692
778
|
|
package/dist/index.cjs
CHANGED
|
@@ -65,6 +65,7 @@ var FIELD_PATHS = [
|
|
|
65
65
|
[/\busage\.inputTokens\b/g, "tokens.input"],
|
|
66
66
|
[/\busage\.outputTokens\b/g, "tokens.output"],
|
|
67
67
|
[/\busage\.cacheTokens\b/g, "tokens.cache"],
|
|
68
|
+
[/\busage\.cacheWriteTokens\b/g, "tokens.cacheWrite"],
|
|
68
69
|
[/\busage\.model\b/g, "model"],
|
|
69
70
|
// A missing/invalid `usage` block as a whole: the caller's equivalent is
|
|
70
71
|
// `tokens` (plus `model`, which the SDK hoists to the top level).
|
|
@@ -332,7 +333,7 @@ function sleep(ms) {
|
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
// src/http.ts
|
|
335
|
-
var SDK_VERSION = "0.
|
|
336
|
+
var SDK_VERSION = "0.17.0" ;
|
|
336
337
|
var Transport = class {
|
|
337
338
|
constructor(cfg) {
|
|
338
339
|
this.cfg = cfg;
|
|
@@ -436,6 +437,143 @@ var Transport = class {
|
|
|
436
437
|
}
|
|
437
438
|
};
|
|
438
439
|
|
|
440
|
+
// src/filters.ts
|
|
441
|
+
function activeQuery(active) {
|
|
442
|
+
return active === true ? "true" : void 0;
|
|
443
|
+
}
|
|
444
|
+
function filterByActive(rows, active) {
|
|
445
|
+
return active === false ? rows.filter((row) => !row.isActive) : rows;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/resources/composites.ts
|
|
449
|
+
var Composites = class {
|
|
450
|
+
constructor(transport) {
|
|
451
|
+
this.transport = transport;
|
|
452
|
+
}
|
|
453
|
+
transport;
|
|
454
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
455
|
+
* only archived ones; omit it for both. */
|
|
456
|
+
async list(params = {}) {
|
|
457
|
+
const res = await this.transport.request({
|
|
458
|
+
method: "GET",
|
|
459
|
+
path: "/api/v1/composites",
|
|
460
|
+
query: { active: activeQuery(params.active) }
|
|
461
|
+
});
|
|
462
|
+
return filterByActive(res.composites, params.active);
|
|
463
|
+
}
|
|
464
|
+
/** One composite's configuration. */
|
|
465
|
+
async get(id) {
|
|
466
|
+
const res = await this.transport.request({
|
|
467
|
+
method: "GET",
|
|
468
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}`
|
|
469
|
+
});
|
|
470
|
+
return res.composite;
|
|
471
|
+
}
|
|
472
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
473
|
+
* create a second row. */
|
|
474
|
+
async create(input) {
|
|
475
|
+
const res = await this.transport.request({
|
|
476
|
+
method: "POST",
|
|
477
|
+
path: "/api/v1/composites",
|
|
478
|
+
body: input
|
|
479
|
+
});
|
|
480
|
+
return res.composite;
|
|
481
|
+
}
|
|
482
|
+
/** PARTIAL update: only the fields you send change. `entitlements`, when
|
|
483
|
+
* sent, is the complete new set. Renaming `refId` cuts live traffic over at
|
|
484
|
+
* once — ship the new tag to your callers first. */
|
|
485
|
+
async update(id, input) {
|
|
486
|
+
const res = await this.transport.request({
|
|
487
|
+
method: "PATCH",
|
|
488
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}`,
|
|
489
|
+
body: input
|
|
490
|
+
});
|
|
491
|
+
return res.composite;
|
|
492
|
+
}
|
|
493
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
494
|
+
async archive(id) {
|
|
495
|
+
const res = await this.transport.request({
|
|
496
|
+
method: "POST",
|
|
497
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}/archive`,
|
|
498
|
+
retry: true
|
|
499
|
+
});
|
|
500
|
+
return res.composite;
|
|
501
|
+
}
|
|
502
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
503
|
+
async unarchive(id) {
|
|
504
|
+
const res = await this.transport.request({
|
|
505
|
+
method: "POST",
|
|
506
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}/unarchive`,
|
|
507
|
+
retry: true
|
|
508
|
+
});
|
|
509
|
+
return res.composite;
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// src/resources/credits.ts
|
|
514
|
+
var Credits = class {
|
|
515
|
+
constructor(transport) {
|
|
516
|
+
this.transport = transport;
|
|
517
|
+
}
|
|
518
|
+
transport;
|
|
519
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
520
|
+
* only archived ones; omit it for both. */
|
|
521
|
+
async list(params = {}) {
|
|
522
|
+
const res = await this.transport.request({
|
|
523
|
+
method: "GET",
|
|
524
|
+
path: "/api/v1/credits",
|
|
525
|
+
query: { active: activeQuery(params.active) }
|
|
526
|
+
});
|
|
527
|
+
return filterByActive(res.credits, params.active);
|
|
528
|
+
}
|
|
529
|
+
/** One credit's configuration. */
|
|
530
|
+
async get(id) {
|
|
531
|
+
const res = await this.transport.request({
|
|
532
|
+
method: "GET",
|
|
533
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}`
|
|
534
|
+
});
|
|
535
|
+
return res.credit;
|
|
536
|
+
}
|
|
537
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
538
|
+
* create a second row. */
|
|
539
|
+
async create(input) {
|
|
540
|
+
const res = await this.transport.request({
|
|
541
|
+
method: "POST",
|
|
542
|
+
path: "/api/v1/credits",
|
|
543
|
+
body: input
|
|
544
|
+
});
|
|
545
|
+
return res.credit;
|
|
546
|
+
}
|
|
547
|
+
/** PARTIAL update: only the fields you send change. Send `modelBundle` to
|
|
548
|
+
* re-price; leave it out to keep the stored base price. */
|
|
549
|
+
async update(id, input) {
|
|
550
|
+
const res = await this.transport.request({
|
|
551
|
+
method: "PATCH",
|
|
552
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
553
|
+
body: input
|
|
554
|
+
});
|
|
555
|
+
return res.credit;
|
|
556
|
+
}
|
|
557
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
558
|
+
async archive(id) {
|
|
559
|
+
const res = await this.transport.request({
|
|
560
|
+
method: "POST",
|
|
561
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}/archive`,
|
|
562
|
+
retry: true
|
|
563
|
+
});
|
|
564
|
+
return res.credit;
|
|
565
|
+
}
|
|
566
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
567
|
+
async unarchive(id) {
|
|
568
|
+
const res = await this.transport.request({
|
|
569
|
+
method: "POST",
|
|
570
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}/unarchive`,
|
|
571
|
+
retry: true
|
|
572
|
+
});
|
|
573
|
+
return res.credit;
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
439
577
|
// src/idempotency.ts
|
|
440
578
|
function newKey() {
|
|
441
579
|
const c = globalThis.crypto;
|
|
@@ -664,7 +802,7 @@ var Customers = class {
|
|
|
664
802
|
* Top up (positive `delta`) or draw down (negative `delta`) a customer's
|
|
665
803
|
* wallet, in USD — allowed whatever the customer's plan. `remaining` is the
|
|
666
804
|
* resulting USD balance. No `agentKey` — a customer has exactly one wallet.
|
|
667
|
-
* Pass `pool: "
|
|
805
|
+
* Pass `pool: "reserved"` to move the Reserved Wallet instead (then
|
|
668
806
|
* `remaining` is its balance). `POST …/:id/wallet/adjust`.
|
|
669
807
|
*/
|
|
670
808
|
adjustWallet(id, input) {
|
|
@@ -795,6 +933,71 @@ var Invoices = class {
|
|
|
795
933
|
}
|
|
796
934
|
};
|
|
797
935
|
|
|
936
|
+
// src/resources/outcomes.ts
|
|
937
|
+
var Outcomes = class {
|
|
938
|
+
constructor(transport) {
|
|
939
|
+
this.transport = transport;
|
|
940
|
+
}
|
|
941
|
+
transport;
|
|
942
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
943
|
+
* only archived ones; omit it for both. */
|
|
944
|
+
async list(params = {}) {
|
|
945
|
+
const res = await this.transport.request({
|
|
946
|
+
method: "GET",
|
|
947
|
+
path: "/api/v1/outcomes",
|
|
948
|
+
query: { active: activeQuery(params.active) }
|
|
949
|
+
});
|
|
950
|
+
return filterByActive(res.outcomes, params.active);
|
|
951
|
+
}
|
|
952
|
+
/** One outcome's configuration, with every step in full. */
|
|
953
|
+
async get(id) {
|
|
954
|
+
const res = await this.transport.request({
|
|
955
|
+
method: "GET",
|
|
956
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}`
|
|
957
|
+
});
|
|
958
|
+
return res.outcome;
|
|
959
|
+
}
|
|
960
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
961
|
+
* create a second row. */
|
|
962
|
+
async create(input) {
|
|
963
|
+
const res = await this.transport.request({
|
|
964
|
+
method: "POST",
|
|
965
|
+
path: "/api/v1/outcomes",
|
|
966
|
+
body: input
|
|
967
|
+
});
|
|
968
|
+
return res.outcome;
|
|
969
|
+
}
|
|
970
|
+
/** PARTIAL update: only the fields you send change. Leave `steps` out to
|
|
971
|
+
* leave the steps alone; send it and it is the complete list — pass each
|
|
972
|
+
* existing step's `id` (or its same `agentKey`) to keep it. */
|
|
973
|
+
async update(id, input) {
|
|
974
|
+
const res = await this.transport.request({
|
|
975
|
+
method: "PATCH",
|
|
976
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
977
|
+
body: input
|
|
978
|
+
});
|
|
979
|
+
return res.outcome;
|
|
980
|
+
}
|
|
981
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
982
|
+
async archive(id) {
|
|
983
|
+
const res = await this.transport.request({
|
|
984
|
+
method: "POST",
|
|
985
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}/archive`,
|
|
986
|
+
retry: true
|
|
987
|
+
});
|
|
988
|
+
return res.outcome;
|
|
989
|
+
}
|
|
990
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
991
|
+
async unarchive(id) {
|
|
992
|
+
const res = await this.transport.request({
|
|
993
|
+
method: "POST",
|
|
994
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}/unarchive`,
|
|
995
|
+
retry: true
|
|
996
|
+
});
|
|
997
|
+
return res.outcome;
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
|
|
798
1001
|
// src/resources/payments.ts
|
|
799
1002
|
var Payments = class {
|
|
800
1003
|
constructor(transport) {
|
|
@@ -819,14 +1022,6 @@ var Payments = class {
|
|
|
819
1022
|
}
|
|
820
1023
|
};
|
|
821
1024
|
|
|
822
|
-
// src/filters.ts
|
|
823
|
-
function activeQuery(active) {
|
|
824
|
-
return active === true ? "true" : void 0;
|
|
825
|
-
}
|
|
826
|
-
function filterByActive(rows, active) {
|
|
827
|
-
return active === false ? rows.filter((row) => !row.isActive) : rows;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
1025
|
// src/resources/plans.ts
|
|
831
1026
|
var Plans = class {
|
|
832
1027
|
constructor(transport) {
|
|
@@ -844,6 +1039,54 @@ var Plans = class {
|
|
|
844
1039
|
});
|
|
845
1040
|
return filterByActive(res.plans, params.active);
|
|
846
1041
|
}
|
|
1042
|
+
/** One plan's configuration. */
|
|
1043
|
+
async get(id) {
|
|
1044
|
+
const res = await this.transport.request({
|
|
1045
|
+
method: "GET",
|
|
1046
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}`
|
|
1047
|
+
});
|
|
1048
|
+
return res.plan;
|
|
1049
|
+
}
|
|
1050
|
+
/** Create a plan. It starts active. Not retried on failure — a retry could
|
|
1051
|
+
* create a second plan. */
|
|
1052
|
+
async create(input) {
|
|
1053
|
+
const res = await this.transport.request({
|
|
1054
|
+
method: "POST",
|
|
1055
|
+
path: "/api/v1/plans",
|
|
1056
|
+
body: input
|
|
1057
|
+
});
|
|
1058
|
+
return res.plan;
|
|
1059
|
+
}
|
|
1060
|
+
/** PARTIAL update: only the fields you send change. `entitlements`, when
|
|
1061
|
+
* sent, is the complete new list — the list `get()` returned can be sent
|
|
1062
|
+
* back as it is. Changes apply to new purchases only. */
|
|
1063
|
+
async update(id, input) {
|
|
1064
|
+
const res = await this.transport.request({
|
|
1065
|
+
method: "PATCH",
|
|
1066
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
1067
|
+
body: input
|
|
1068
|
+
});
|
|
1069
|
+
return res.plan;
|
|
1070
|
+
}
|
|
1071
|
+
/** Retire a plan (`isActive` → false): it can't be bought any more; customers
|
|
1072
|
+
* already on it are unaffected. Safe to retry. */
|
|
1073
|
+
async archive(id) {
|
|
1074
|
+
const res = await this.transport.request({
|
|
1075
|
+
method: "POST",
|
|
1076
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}/archive`,
|
|
1077
|
+
retry: true
|
|
1078
|
+
});
|
|
1079
|
+
return res.plan;
|
|
1080
|
+
}
|
|
1081
|
+
/** Make an archived plan purchasable again (`isActive` → true). Safe to retry. */
|
|
1082
|
+
async unarchive(id) {
|
|
1083
|
+
const res = await this.transport.request({
|
|
1084
|
+
method: "POST",
|
|
1085
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}/unarchive`,
|
|
1086
|
+
retry: true
|
|
1087
|
+
});
|
|
1088
|
+
return res.plan;
|
|
1089
|
+
}
|
|
847
1090
|
};
|
|
848
1091
|
|
|
849
1092
|
// src/resources/portal.ts
|
|
@@ -949,12 +1192,14 @@ function signalToWire(signal) {
|
|
|
949
1192
|
const body = {
|
|
950
1193
|
...customerRefToWire(signal),
|
|
951
1194
|
// `usage` is required on all three model-priced kinds. input/output are
|
|
952
|
-
// always sent; `cacheTokens` only when provided (the
|
|
1195
|
+
// always sent; `cacheTokens` / `cacheWriteTokens` only when provided (the
|
|
1196
|
+
// server defaults each to 0).
|
|
953
1197
|
usage: {
|
|
954
1198
|
model: signal.model,
|
|
955
1199
|
inputTokens: t.input,
|
|
956
1200
|
outputTokens: t.output,
|
|
957
|
-
...t.cache != null ? { cacheTokens: t.cache } : {}
|
|
1201
|
+
...t.cache != null ? { cacheTokens: t.cache } : {},
|
|
1202
|
+
...t.cacheWrite != null ? { cacheWriteTokens: t.cacheWrite } : {}
|
|
958
1203
|
}
|
|
959
1204
|
};
|
|
960
1205
|
if (signal.member) body.member = signal.member;
|
|
@@ -1204,14 +1449,86 @@ var Signals = class {
|
|
|
1204
1449
|
}
|
|
1205
1450
|
};
|
|
1206
1451
|
|
|
1452
|
+
// src/resources/units.ts
|
|
1453
|
+
var Units = class {
|
|
1454
|
+
constructor(transport) {
|
|
1455
|
+
this.transport = transport;
|
|
1456
|
+
}
|
|
1457
|
+
transport;
|
|
1458
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
1459
|
+
* only archived ones; omit it for both. */
|
|
1460
|
+
async list(params = {}) {
|
|
1461
|
+
const res = await this.transport.request({
|
|
1462
|
+
method: "GET",
|
|
1463
|
+
path: "/api/v1/units",
|
|
1464
|
+
query: { active: activeQuery(params.active) }
|
|
1465
|
+
});
|
|
1466
|
+
return filterByActive(res.units, params.active);
|
|
1467
|
+
}
|
|
1468
|
+
/** One unit's configuration. */
|
|
1469
|
+
async get(id) {
|
|
1470
|
+
const res = await this.transport.request({
|
|
1471
|
+
method: "GET",
|
|
1472
|
+
path: `/api/v1/units/${encodeURIComponent(id)}`
|
|
1473
|
+
});
|
|
1474
|
+
return res.unit;
|
|
1475
|
+
}
|
|
1476
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
1477
|
+
* create a second row. */
|
|
1478
|
+
async create(input) {
|
|
1479
|
+
const res = await this.transport.request({
|
|
1480
|
+
method: "POST",
|
|
1481
|
+
path: "/api/v1/units",
|
|
1482
|
+
body: input
|
|
1483
|
+
});
|
|
1484
|
+
return res.unit;
|
|
1485
|
+
}
|
|
1486
|
+
/** PARTIAL update: only the fields you send change. `tiers`, when sent, is
|
|
1487
|
+
* the complete new tier list. */
|
|
1488
|
+
async update(id, input) {
|
|
1489
|
+
const res = await this.transport.request({
|
|
1490
|
+
method: "PATCH",
|
|
1491
|
+
path: `/api/v1/units/${encodeURIComponent(id)}`,
|
|
1492
|
+
body: input
|
|
1493
|
+
});
|
|
1494
|
+
return res.unit;
|
|
1495
|
+
}
|
|
1496
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
1497
|
+
async archive(id) {
|
|
1498
|
+
const res = await this.transport.request({
|
|
1499
|
+
method: "POST",
|
|
1500
|
+
path: `/api/v1/units/${encodeURIComponent(id)}/archive`,
|
|
1501
|
+
retry: true
|
|
1502
|
+
});
|
|
1503
|
+
return res.unit;
|
|
1504
|
+
}
|
|
1505
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
1506
|
+
async unarchive(id) {
|
|
1507
|
+
const res = await this.transport.request({
|
|
1508
|
+
method: "POST",
|
|
1509
|
+
path: `/api/v1/units/${encodeURIComponent(id)}/unarchive`,
|
|
1510
|
+
retry: true
|
|
1511
|
+
});
|
|
1512
|
+
return res.unit;
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1207
1516
|
// src/client.ts
|
|
1208
1517
|
var ClockNext = class {
|
|
1209
1518
|
/** Record usage signals (credit / wallet / outcome / unit) and read the usage log. */
|
|
1210
1519
|
signals;
|
|
1211
1520
|
/** Manage customers, their members, and balances. */
|
|
1212
1521
|
customers;
|
|
1213
|
-
/**
|
|
1522
|
+
/** Billing plans: list, get, create, update, archive, unarchive. */
|
|
1214
1523
|
plans;
|
|
1524
|
+
/** Credits: list, get, create, update, archive, unarchive (no delete). */
|
|
1525
|
+
credits;
|
|
1526
|
+
/** Outcomes: list, get, create, update, archive, unarchive (no delete). */
|
|
1527
|
+
outcomes;
|
|
1528
|
+
/** Units: list, get, create, update, archive, unarchive (no delete). */
|
|
1529
|
+
units;
|
|
1530
|
+
/** Composites: list, get, create, update, archive, unarchive (no delete). */
|
|
1531
|
+
composites;
|
|
1215
1532
|
/** Subscribe customers to plans (purchases). */
|
|
1216
1533
|
purchases;
|
|
1217
1534
|
/** Read invoices and mint hosted pay links. */
|
|
@@ -1234,6 +1551,10 @@ var ClockNext = class {
|
|
|
1234
1551
|
this.signals = new Signals(transport, this.flusher, this.cfg);
|
|
1235
1552
|
this.customers = new Customers(transport);
|
|
1236
1553
|
this.plans = new Plans(transport);
|
|
1554
|
+
this.credits = new Credits(transport);
|
|
1555
|
+
this.outcomes = new Outcomes(transport);
|
|
1556
|
+
this.units = new Units(transport);
|
|
1557
|
+
this.composites = new Composites(transport);
|
|
1237
1558
|
this.purchases = new Purchases(transport);
|
|
1238
1559
|
this.invoices = new Invoices(transport);
|
|
1239
1560
|
this.payments = new Payments(transport);
|