@clocknext/sdk 0.3.0 → 0.5.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 +12 -9
- package/dist/index.cjs +114 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +388 -88
- package/dist/index.d.ts +388 -88
- package/dist/index.js +114 -44
- package/dist/index.js.map +1 -1
- package/package.json +13 -5
package/dist/index.js
CHANGED
|
@@ -227,7 +227,7 @@ function sleep(ms) {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
// src/http.ts
|
|
230
|
-
var SDK_VERSION = "0.
|
|
230
|
+
var SDK_VERSION = "0.5.0" ;
|
|
231
231
|
var Transport = class {
|
|
232
232
|
constructor(cfg) {
|
|
233
233
|
this.cfg = cfg;
|
|
@@ -337,13 +337,14 @@ var Credits = class {
|
|
|
337
337
|
});
|
|
338
338
|
return res.credits;
|
|
339
339
|
}
|
|
340
|
-
/** Create a credit type. `POST /api/v1/credits`. */
|
|
340
|
+
/** Create a credit type; returns the created credit. `POST /api/v1/credits`. */
|
|
341
341
|
async create(input) {
|
|
342
|
-
await this.transport.request({
|
|
342
|
+
const res = await this.transport.request({
|
|
343
343
|
method: "POST",
|
|
344
344
|
path: "/api/v1/credits",
|
|
345
345
|
body: input
|
|
346
346
|
});
|
|
347
|
+
return res.credit;
|
|
347
348
|
}
|
|
348
349
|
/** Fetch one credit type with usage stats. `GET /api/v1/credits/:id`. */
|
|
349
350
|
async get(id) {
|
|
@@ -353,13 +354,14 @@ var Credits = class {
|
|
|
353
354
|
});
|
|
354
355
|
return res.credit;
|
|
355
356
|
}
|
|
356
|
-
/** Update a credit type's definition. `PATCH /api/v1/credits/:id`. */
|
|
357
|
+
/** Update a credit type's definition; returns the updated credit. `PATCH /api/v1/credits/:id`. */
|
|
357
358
|
async update(id, input) {
|
|
358
|
-
await this.transport.request({
|
|
359
|
+
const res = await this.transport.request({
|
|
359
360
|
method: "PATCH",
|
|
360
361
|
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
361
362
|
body: input
|
|
362
363
|
});
|
|
364
|
+
return res.credit;
|
|
363
365
|
}
|
|
364
366
|
/** Activate or deactivate a credit type. */
|
|
365
367
|
async setActive(id, isActive) {
|
|
@@ -439,12 +441,12 @@ var Customers = class {
|
|
|
439
441
|
path: `/api/v1/customers/${encodeURIComponent(id)}`
|
|
440
442
|
});
|
|
441
443
|
}
|
|
442
|
-
/** A customer's usage history. `GET /api/v1/
|
|
444
|
+
/** A customer's usage history. `GET /api/v1/usage?customerId=`. */
|
|
443
445
|
async usage(id, params = {}) {
|
|
444
446
|
const res = await this.transport.request({
|
|
445
447
|
method: "GET",
|
|
446
|
-
path: `/api/v1/
|
|
447
|
-
query: { limit: params.limit }
|
|
448
|
+
path: `/api/v1/usage`,
|
|
449
|
+
query: { customerId: id, limit: params.limit }
|
|
448
450
|
});
|
|
449
451
|
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
450
452
|
}
|
|
@@ -455,6 +457,37 @@ var Customers = class {
|
|
|
455
457
|
path: `/api/v1/customers/${encodeURIComponent(id)}/balances`
|
|
456
458
|
});
|
|
457
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* One credit balance for a customer, matched by `creditId` or `creditName`;
|
|
462
|
+
* `null` when the customer has no plan or no matching credit. Convenience
|
|
463
|
+
* over `balances()` + `Array.find` — it fetches the FULL balances under the
|
|
464
|
+
* hood (there is no server-side scoped read), so prefer `balances()` when you
|
|
465
|
+
* need several rows from the same customer.
|
|
466
|
+
*/
|
|
467
|
+
async creditBalance(customerId, match) {
|
|
468
|
+
const { credits } = await this.balances(customerId);
|
|
469
|
+
return credits.find(
|
|
470
|
+
(c) => match.creditId != null && c.creditId === match.creditId || match.creditName != null && c.creditName === match.creditName
|
|
471
|
+
) ?? null;
|
|
472
|
+
}
|
|
473
|
+
/** One outcome balance for a customer, matched by `outcomeId` or
|
|
474
|
+
* `outcomeName`; `null` when absent. See {@link creditBalance} for the
|
|
475
|
+
* fetch-then-filter caveat. */
|
|
476
|
+
async outcomeBalance(customerId, match) {
|
|
477
|
+
const { outcomes } = await this.balances(customerId);
|
|
478
|
+
return outcomes.find(
|
|
479
|
+
(o) => match.outcomeId != null && o.outcomeId === match.outcomeId || match.outcomeName != null && o.outcomeName === match.outcomeName
|
|
480
|
+
) ?? null;
|
|
481
|
+
}
|
|
482
|
+
/** One unit balance for a customer, matched by `unitId` or `unitName`;
|
|
483
|
+
* `null` when absent. See {@link creditBalance} for the fetch-then-filter
|
|
484
|
+
* caveat. */
|
|
485
|
+
async unitBalance(customerId, match) {
|
|
486
|
+
const { units } = await this.balances(customerId);
|
|
487
|
+
return units.find(
|
|
488
|
+
(u) => match.unitId != null && u.unitId === match.unitId || match.unitName != null && u.unitName === match.unitName
|
|
489
|
+
) ?? null;
|
|
490
|
+
}
|
|
458
491
|
/** The customer's current plan. `GET …/:id/plan`. */
|
|
459
492
|
plan(id) {
|
|
460
493
|
return this.transport.request({
|
|
@@ -462,14 +495,6 @@ var Customers = class {
|
|
|
462
495
|
path: `/api/v1/customers/${encodeURIComponent(id)}/plan`
|
|
463
496
|
});
|
|
464
497
|
}
|
|
465
|
-
/** Revenue / cost / profit / margin over a window. `GET …/:id/revenue`. */
|
|
466
|
-
revenue(id, params = {}) {
|
|
467
|
-
return this.transport.request({
|
|
468
|
-
method: "GET",
|
|
469
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/revenue`,
|
|
470
|
-
query: { range: params.range }
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
498
|
// --- Members -------------------------------------------------------------
|
|
474
499
|
/** List a customer's members. `GET …/:id/members`. */
|
|
475
500
|
async listMembers(id) {
|
|
@@ -524,22 +549,9 @@ var Customers = class {
|
|
|
524
549
|
body: input
|
|
525
550
|
});
|
|
526
551
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
method: "PUT",
|
|
531
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/currency`,
|
|
532
|
-
body: { currencyCode }
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
/** Set which credit types the customer is billed against. `PUT …/:id/credits`. */
|
|
536
|
-
async setCreditTypes(id, creditIds) {
|
|
537
|
-
await this.transport.request({
|
|
538
|
-
method: "PUT",
|
|
539
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/credits`,
|
|
540
|
-
body: { creditIds }
|
|
541
|
-
});
|
|
542
|
-
}
|
|
552
|
+
// Note: a customer's currency is set through `update(id, { currencyCode })`
|
|
553
|
+
// (PATCH …/:id) — there is no separate currency endpoint. Credit-type
|
|
554
|
+
// assignment has no public API.
|
|
543
555
|
// --- Balance adjustments -------------------------------------------------
|
|
544
556
|
/** Grant or claw back a credit balance. `POST …/:id/credits/adjust`. */
|
|
545
557
|
async adjustCredit(id, input) {
|
|
@@ -648,13 +660,14 @@ var Outcomes = class {
|
|
|
648
660
|
});
|
|
649
661
|
return res.outcome;
|
|
650
662
|
}
|
|
651
|
-
/** Activate or deactivate an outcome type. */
|
|
663
|
+
/** Activate or deactivate an outcome type; returns the updated outcome. */
|
|
652
664
|
async setActive(id, isActive) {
|
|
653
|
-
await this.transport.request({
|
|
665
|
+
const res = await this.transport.request({
|
|
654
666
|
method: "PATCH",
|
|
655
667
|
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
656
668
|
body: { isActive }
|
|
657
669
|
});
|
|
670
|
+
return res.outcome;
|
|
658
671
|
}
|
|
659
672
|
/** Delete an outcome type. */
|
|
660
673
|
async delete(id) {
|
|
@@ -828,6 +841,17 @@ var Purchases = class {
|
|
|
828
841
|
}
|
|
829
842
|
};
|
|
830
843
|
|
|
844
|
+
// src/idempotency.ts
|
|
845
|
+
function newKey() {
|
|
846
|
+
const c = globalThis.crypto;
|
|
847
|
+
if (typeof c?.randomUUID === "function") return c.randomUUID();
|
|
848
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
|
|
849
|
+
const r = Math.random() * 16 | 0;
|
|
850
|
+
const v = ch === "x" ? r : r & 3 | 8;
|
|
851
|
+
return v.toString(16);
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
831
855
|
// src/resources/signals.ts
|
|
832
856
|
function signalToWire(signal) {
|
|
833
857
|
const body = {
|
|
@@ -836,17 +860,15 @@ function signalToWire(signal) {
|
|
|
836
860
|
model: signal.model
|
|
837
861
|
};
|
|
838
862
|
if (signal.member) body.member = signal.member;
|
|
839
|
-
if (signal.status) body.status = signal.status;
|
|
840
863
|
if (signal.custom) body.custom = signal.custom;
|
|
841
864
|
const t = signal.tokens;
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (t.cache != null) body.cacheTokens = t.cache;
|
|
846
|
-
}
|
|
865
|
+
body.inputTokens = t.input;
|
|
866
|
+
body.outputTokens = t.output;
|
|
867
|
+
if (t.cache != null) body.cacheTokens = t.cache;
|
|
847
868
|
if (signal.type === "credit" || signal.type === "outcome") {
|
|
848
869
|
body.agentKey = signal.agentKey;
|
|
849
870
|
}
|
|
871
|
+
if (signal.idempotencyKey) body.idempotencyKey = signal.idempotencyKey;
|
|
850
872
|
return body;
|
|
851
873
|
}
|
|
852
874
|
var Signals = class {
|
|
@@ -860,6 +882,7 @@ var Signals = class {
|
|
|
860
882
|
cfg;
|
|
861
883
|
async track(signal, opts = {}) {
|
|
862
884
|
const body = signalToWire(signal);
|
|
885
|
+
if (body.idempotencyKey == null) body.idempotencyKey = newKey();
|
|
863
886
|
const sendNow = opts.wait || this.cfg.mode === "sync";
|
|
864
887
|
if (!sendNow) {
|
|
865
888
|
this.flusher.enqueue({ body, signal });
|
|
@@ -877,6 +900,23 @@ var Signals = class {
|
|
|
877
900
|
usageLog: res.usageLog ?? null
|
|
878
901
|
};
|
|
879
902
|
}
|
|
903
|
+
/**
|
|
904
|
+
* Validate + price a signal WITHOUT recording it (server `dryRun`). Returns
|
|
905
|
+
* the projected usage log so an integration can preflight before sending real
|
|
906
|
+
* traffic — no inbox row, wallet / outcome writes, or webhooks fire.
|
|
907
|
+
*/
|
|
908
|
+
async verify(signal) {
|
|
909
|
+
const body = signalToWire(signal);
|
|
910
|
+
body.dryRun = true;
|
|
911
|
+
const res = await this.transport.request({
|
|
912
|
+
method: "POST",
|
|
913
|
+
path: "/api/v1/usage",
|
|
914
|
+
body,
|
|
915
|
+
// A dry run writes nothing, so it is always safe to retry.
|
|
916
|
+
retry: true
|
|
917
|
+
});
|
|
918
|
+
return res.usageLog ?? null;
|
|
919
|
+
}
|
|
880
920
|
/** Meter a named credit. */
|
|
881
921
|
credit(input, opts) {
|
|
882
922
|
return this.track({ ...input, type: "credit" }, opts);
|
|
@@ -899,9 +939,9 @@ var Signals = class {
|
|
|
899
939
|
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
900
940
|
}
|
|
901
941
|
/**
|
|
902
|
-
* Record one unit-metered event (a fixed-price meter with no tokens),
|
|
903
|
-
* to a catalog unit by
|
|
904
|
-
* `POST /api/v1/units`.
|
|
942
|
+
* Record one unit-metered event (a fixed-price meter with no tokens),
|
|
943
|
+
* addressed to a catalog unit by its `agentKey`. Sent immediately — unit
|
|
944
|
+
* events are not buffered. `POST /api/v1/units`.
|
|
905
945
|
*/
|
|
906
946
|
async unit(input) {
|
|
907
947
|
return this.transport.request({
|
|
@@ -909,7 +949,7 @@ var Signals = class {
|
|
|
909
949
|
path: "/api/v1/units",
|
|
910
950
|
body: {
|
|
911
951
|
customerId: input.customerId,
|
|
912
|
-
|
|
952
|
+
agentKey: input.agentKey,
|
|
913
953
|
...input.member ? { member: input.member } : {}
|
|
914
954
|
},
|
|
915
955
|
// Best-effort metering opts into retries on transient failures.
|
|
@@ -1017,6 +1057,33 @@ var Webhooks = class {
|
|
|
1017
1057
|
}
|
|
1018
1058
|
};
|
|
1019
1059
|
|
|
1060
|
+
// src/resources/workspace.ts
|
|
1061
|
+
var Workspace = class {
|
|
1062
|
+
constructor(transport) {
|
|
1063
|
+
this.transport = transport;
|
|
1064
|
+
}
|
|
1065
|
+
transport;
|
|
1066
|
+
/** Identify the org + key behind the request, incl. `sandbox` | `live`. */
|
|
1067
|
+
me() {
|
|
1068
|
+
return this.transport.request({
|
|
1069
|
+
method: "GET",
|
|
1070
|
+
path: "/api/v1/me"
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
/** The org's enabled models with live prices. `{ active: true }` returns only
|
|
1074
|
+
* the models that can be metered right now. */
|
|
1075
|
+
async models(params = {}) {
|
|
1076
|
+
const res = await this.transport.request({
|
|
1077
|
+
method: "GET",
|
|
1078
|
+
path: "/api/v1/models",
|
|
1079
|
+
query: {
|
|
1080
|
+
active: params.active === void 0 ? void 0 : String(params.active)
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
return res.models;
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1020
1087
|
// src/client.ts
|
|
1021
1088
|
var ClockNext = class {
|
|
1022
1089
|
/** Record + read usage signals (credit / wallet / outcome / unit). */
|
|
@@ -1041,6 +1108,8 @@ var ClockNext = class {
|
|
|
1041
1108
|
webhooks;
|
|
1042
1109
|
/** Mint customer-portal embed tokens. */
|
|
1043
1110
|
portal;
|
|
1111
|
+
/** Identify the workspace (sandbox/live) + list its models. `/me`, `/models`. */
|
|
1112
|
+
workspace;
|
|
1044
1113
|
cfg;
|
|
1045
1114
|
flusher;
|
|
1046
1115
|
constructor(config) {
|
|
@@ -1063,6 +1132,7 @@ var ClockNext = class {
|
|
|
1063
1132
|
this.units = new Units(transport);
|
|
1064
1133
|
this.webhooks = new Webhooks(transport);
|
|
1065
1134
|
this.portal = new Portal(transport);
|
|
1135
|
+
this.workspace = new Workspace(transport);
|
|
1066
1136
|
}
|
|
1067
1137
|
/** Number of signals currently buffered (async mode). */
|
|
1068
1138
|
get pending() {
|