@clocknext/sdk 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +200 -140
- package/dist/index.cjs +213 -438
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +394 -812
- package/dist/index.d.ts +394 -812
- package/dist/index.js +213 -438
- package/dist/index.js.map +1 -1
- package/examples/node-basic.ts +24 -32
- package/package.json +1 -1
- package/src/client.ts +3 -27
- package/src/customer-ref.ts +14 -0
- package/src/errors.ts +8 -1
- package/src/filters.ts +1 -1
- package/src/index.ts +13 -59
- package/src/resources/customers.ts +201 -82
- package/src/resources/invoices.ts +1 -1
- package/src/resources/plans.ts +4 -56
- package/src/resources/signals.ts +33 -38
- package/src/types.ts +301 -610
- package/src/resources/composites.ts +0 -47
- package/src/resources/credits.ts +0 -76
- package/src/resources/outcomes.ts +0 -82
- package/src/resources/units.ts +0 -76
- package/src/resources/webhooks.ts +0 -37
- package/src/resources/workspace.ts +0 -33
package/examples/node-basic.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Basic usage: record a few signals from a long-lived Node process.
|
|
3
|
-
* Run with: CLOCKNEXT_API_KEY=cnk_… npx tsx examples/node-basic.ts
|
|
4
3
|
*
|
|
5
4
|
* Note the discovery step first. `customerId`, `model` and `agentKey` are not
|
|
6
5
|
* strings you can invent — they name rows that must already exist in your
|
|
7
6
|
* workspace, and a signal naming one that does not is rejected. So this example
|
|
8
|
-
* reads
|
|
9
|
-
* guaranteed to 422 on someone else's workspace.
|
|
7
|
+
* reads the customer and its agent keys out of the API rather than hard-coding
|
|
8
|
+
* placeholders that are guaranteed to 422 on someone else's workspace. The
|
|
9
|
+
* model id comes from Settings → Models in the dashboard:
|
|
10
|
+
*
|
|
11
|
+
* CLOCKNEXT_API_KEY=cnk_… CLOCKNEXT_MODEL=gpt-4o npx tsx examples/node-basic.ts
|
|
10
12
|
*/
|
|
11
13
|
import { ClockNext } from "@clocknext/sdk";
|
|
12
14
|
|
|
@@ -18,34 +20,28 @@ const cnk = new ClockNext({
|
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
async function main() {
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// 1. Discover real ids instead of guessing them.
|
|
27
|
-
const [models, credits, customers] = await Promise.all([
|
|
28
|
-
cnk.workspace.models({ active: true }),
|
|
29
|
-
cnk.credits.list({ active: true }),
|
|
30
|
-
cnk.customers.list({ limit: 1 }),
|
|
31
|
-
]);
|
|
32
|
-
|
|
33
|
-
const model = models[0];
|
|
34
|
-
const credit = credits[0];
|
|
35
|
-
const customer = customers.customers[0];
|
|
36
|
-
if (!model || !credit || !customer) {
|
|
23
|
+
// 1. Discover real ids instead of guessing them. A customer's balances list
|
|
24
|
+
// every credit and outcome step its plan sells, each with its agentKey.
|
|
25
|
+
const model = process.env.CLOCKNEXT_MODEL;
|
|
26
|
+
const customer = (await cnk.customers.list({ limit: 1 })).customers[0];
|
|
27
|
+
if (!model || !customer) {
|
|
37
28
|
throw new Error(
|
|
38
|
-
"
|
|
29
|
+
"Set CLOCKNEXT_MODEL to a model enabled under Settings → Models, and create at least one customer, before metering anything.",
|
|
39
30
|
);
|
|
40
31
|
}
|
|
41
|
-
|
|
32
|
+
const balances = await cnk.customers.balances(customer.id);
|
|
33
|
+
const credit = balances.credits[0];
|
|
34
|
+
if (!credit) {
|
|
35
|
+
throw new Error("This customer's plan needs at least one credit before it can meter credit usage.");
|
|
36
|
+
}
|
|
37
|
+
console.log(`metering ${credit.agentKey} on ${model}`);
|
|
42
38
|
|
|
43
39
|
// 2. Credit usage — metered against a credit by its stable `agentKey`, priced
|
|
44
40
|
// by tokens. Optionally group it into a composite occurrence, billed once
|
|
45
41
|
// on close.
|
|
46
42
|
await cnk.signals.credit({
|
|
47
43
|
customerId: customer.id,
|
|
48
|
-
model
|
|
44
|
+
model,
|
|
49
45
|
agentKey: credit.agentKey,
|
|
50
46
|
tokens: { input: 1200, output: 340, cache: 0 },
|
|
51
47
|
custom: { feature: "summarize", tier: "pro" },
|
|
@@ -54,23 +50,19 @@ async function main() {
|
|
|
54
50
|
// 3. Wallet usage (debits the customer's USD wallet at model cost).
|
|
55
51
|
await cnk.signals.wallet({
|
|
56
52
|
customerId: customer.id,
|
|
57
|
-
model
|
|
53
|
+
model,
|
|
58
54
|
tokens: { input: 800, output: 5000 },
|
|
59
55
|
});
|
|
60
56
|
|
|
61
57
|
// 4. Outcome run — every step shares a `runId`; a separate, dedicated call
|
|
62
58
|
// (`completeOutcome`) closes and bills the run — never a flag on a step.
|
|
63
|
-
// `agentKey` is the OutcomeStep's key,
|
|
64
|
-
|
|
65
|
-
// `outcomes.list()` returns catalogue rows WITHOUT their steps; the step
|
|
66
|
-
// agent keys — which is what a signal reports against — are on the detail.
|
|
67
|
-
const outcomeRow = (await cnk.outcomes.list({ active: true }))[0];
|
|
68
|
-
const outcome = outcomeRow ? await cnk.outcomes.get(outcomeRow.id) : undefined;
|
|
59
|
+
// `agentKey` is the OutcomeStep's key, read off the same balances.
|
|
60
|
+
const outcome = balances.outcomes[0];
|
|
69
61
|
if (outcome?.steps[0]) {
|
|
70
62
|
const runId = `demo_run_${Date.now()}`;
|
|
71
63
|
await cnk.signals.outcome({
|
|
72
64
|
customerId: customer.id,
|
|
73
|
-
model
|
|
65
|
+
model,
|
|
74
66
|
agentKey: outcome.steps[0].agentKey,
|
|
75
67
|
runId,
|
|
76
68
|
tokens: { input: 600, output: 150 },
|
|
@@ -83,8 +75,8 @@ async function main() {
|
|
|
83
75
|
// asynchronous, so this — not the track() return value — is what proves a
|
|
84
76
|
// signal actually landed.
|
|
85
77
|
await cnk.flush();
|
|
86
|
-
const
|
|
87
|
-
console.log("recent logs:",
|
|
78
|
+
const page = await cnk.signals.usageLog({ customerId: customer.id, limit: 10 });
|
|
79
|
+
console.log("recent logs:", page.usageLogs.length);
|
|
88
80
|
|
|
89
81
|
await cnk.close();
|
|
90
82
|
}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { resolveConfig } from "./config.js";
|
|
2
2
|
import { Flusher } from "./flusher.js";
|
|
3
3
|
import { Transport } from "./http.js";
|
|
4
|
-
import { Composites } from "./resources/composites.js";
|
|
5
|
-
import { Credits } from "./resources/credits.js";
|
|
6
4
|
import { Customers } from "./resources/customers.js";
|
|
7
5
|
import { Invoices } from "./resources/invoices.js";
|
|
8
|
-
import { Outcomes } from "./resources/outcomes.js";
|
|
9
6
|
import { Payments } from "./resources/payments.js";
|
|
10
7
|
import { Plans } from "./resources/plans.js";
|
|
11
8
|
import { Portal } from "./resources/portal.js";
|
|
12
9
|
import { Purchases } from "./resources/purchases.js";
|
|
13
10
|
import { Signals } from "./resources/signals.js";
|
|
14
|
-
import { Units } from "./resources/units.js";
|
|
15
|
-
import { Webhooks } from "./resources/webhooks.js";
|
|
16
|
-
import { Workspace } from "./resources/workspace.js";
|
|
17
11
|
import type { ClockNextConfig, ResolvedConfig } from "./types.js";
|
|
18
12
|
|
|
19
13
|
/**
|
|
@@ -34,11 +28,11 @@ import type { ClockNextConfig, ResolvedConfig } from "./types.js";
|
|
|
34
28
|
* ```
|
|
35
29
|
*/
|
|
36
30
|
export class ClockNext {
|
|
37
|
-
/** Record
|
|
31
|
+
/** Record usage signals (credit / wallet / outcome / unit) and read the usage log. */
|
|
38
32
|
readonly signals: Signals;
|
|
39
|
-
/** Manage customers, their members,
|
|
33
|
+
/** Manage customers, their members, and balances. */
|
|
40
34
|
readonly customers: Customers;
|
|
41
|
-
/**
|
|
35
|
+
/** List billing plans. */
|
|
42
36
|
readonly plans: Plans;
|
|
43
37
|
/** Subscribe customers to plans (purchases). */
|
|
44
38
|
readonly purchases: Purchases;
|
|
@@ -46,20 +40,8 @@ export class ClockNext {
|
|
|
46
40
|
readonly invoices: Invoices;
|
|
47
41
|
/** Read payments (paid invoices). */
|
|
48
42
|
readonly payments: Payments;
|
|
49
|
-
/** Manage the credit-type catalog. */
|
|
50
|
-
readonly credits: Credits;
|
|
51
|
-
/** Manage the composite catalog — bundles billed as one thing. */
|
|
52
|
-
readonly composites: Composites;
|
|
53
|
-
/** Manage the outcome-type catalog. */
|
|
54
|
-
readonly outcomes: Outcomes;
|
|
55
|
-
/** Manage the unit-type catalog. */
|
|
56
|
-
readonly units: Units;
|
|
57
|
-
/** Configure threshold webhooks. */
|
|
58
|
-
readonly webhooks: Webhooks;
|
|
59
43
|
/** Mint customer-portal embed tokens. */
|
|
60
44
|
readonly portal: Portal;
|
|
61
|
-
/** Identify the workspace (sandbox/live) + list its models. `/me`, `/models`. */
|
|
62
|
-
readonly workspace: Workspace;
|
|
63
45
|
|
|
64
46
|
private readonly cfg: ResolvedConfig;
|
|
65
47
|
private readonly flusher: Flusher;
|
|
@@ -81,13 +63,7 @@ export class ClockNext {
|
|
|
81
63
|
this.purchases = new Purchases(transport);
|
|
82
64
|
this.invoices = new Invoices(transport);
|
|
83
65
|
this.payments = new Payments(transport);
|
|
84
|
-
this.credits = new Credits(transport);
|
|
85
|
-
this.composites = new Composites(transport);
|
|
86
|
-
this.outcomes = new Outcomes(transport);
|
|
87
|
-
this.units = new Units(transport);
|
|
88
|
-
this.webhooks = new Webhooks(transport);
|
|
89
66
|
this.portal = new Portal(transport);
|
|
90
|
-
this.workspace = new Workspace(transport);
|
|
91
67
|
}
|
|
92
68
|
|
|
93
69
|
/** Number of signals currently buffered (async mode). */
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The customer half of a request body: `customerId` and/or `externalId`,
|
|
3
|
+
* each only when set. Both are forwarded as given — the server applies the
|
|
4
|
+
* precedence (`customerId` wins), so the SDK never second-guesses it.
|
|
5
|
+
*/
|
|
6
|
+
export function customerRefToWire(ref: {
|
|
7
|
+
customerId?: string;
|
|
8
|
+
externalId?: string;
|
|
9
|
+
}): { customerId?: string; externalId?: string } {
|
|
10
|
+
return {
|
|
11
|
+
...(ref.customerId != null ? { customerId: ref.customerId } : {}),
|
|
12
|
+
...(ref.externalId != null ? { externalId: ref.externalId } : {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -154,7 +154,11 @@ export function translateFieldPaths(message: string): string {
|
|
|
154
154
|
* toward it still classifies, never as the sole test.
|
|
155
155
|
*/
|
|
156
156
|
const ALLOWANCE_MESSAGE =
|
|
157
|
-
/\binsufficient\b|\bno allowance left\b|\bno slots left\b|\boutcomes remaining\b|\btop up the (?:allowance|balance)\b/i;
|
|
157
|
+
/\binsufficient\b|\bno allowance left\b|\bno slots left\b|\boutcomes remaining\b|\btop up the (?:allowance|balance)\b|\bbelow zero\b/i;
|
|
158
|
+
|
|
159
|
+
/** The adjust API's 422 for an idempotency key reused with a DIFFERENT
|
|
160
|
+
* request. A conflict, not a plan problem — and never worth retrying. */
|
|
161
|
+
const IDEMPOTENCY_KEY_REUSED = /\bidempotency key was already used\b/i;
|
|
158
162
|
|
|
159
163
|
export function isAllowanceFailure(message: string, code?: string): boolean {
|
|
160
164
|
if (code) return code === "ALLOWANCE_EXHAUSTED";
|
|
@@ -205,6 +209,9 @@ export function errorFromResponse(
|
|
|
205
209
|
});
|
|
206
210
|
}
|
|
207
211
|
if (status === 422) {
|
|
212
|
+
if (IDEMPOTENCY_KEY_REUSED.test(raw)) {
|
|
213
|
+
return new ConflictError(raw, { ...opts, retryable: false });
|
|
214
|
+
}
|
|
208
215
|
return isAllowanceFailure(raw, code)
|
|
209
216
|
? new AllowanceError(raw, opts)
|
|
210
217
|
: new PlanError(raw, opts);
|
package/src/filters.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -47,7 +47,6 @@ export type {
|
|
|
47
47
|
OutcomeCompletionInput,
|
|
48
48
|
OutcomeCompletionResult,
|
|
49
49
|
TrackResult,
|
|
50
|
-
UsageList,
|
|
51
50
|
SerializedUsageLog,
|
|
52
51
|
UsageBalance,
|
|
53
52
|
SerializedRuleApplication,
|
|
@@ -56,13 +55,15 @@ export type {
|
|
|
56
55
|
UnitTrackResult,
|
|
57
56
|
CompositeCompletionInput,
|
|
58
57
|
CompositeCompletionResult,
|
|
59
|
-
UnitUsageRow,
|
|
60
|
-
UnitUsageList,
|
|
61
58
|
SerializedUnitUsage,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
UsageLogPeriod,
|
|
60
|
+
UsageLogListParams,
|
|
61
|
+
UsageLogAppliedRule,
|
|
62
|
+
UsageLogOutcomeAttribution,
|
|
63
|
+
UsageLogEntry,
|
|
64
|
+
UsageLogPage,
|
|
65
65
|
// customers
|
|
66
|
+
CustomerRef,
|
|
66
67
|
ApiCustomer,
|
|
67
68
|
CustomerProfileInput,
|
|
68
69
|
CreateCustomerInput,
|
|
@@ -79,30 +80,19 @@ export type {
|
|
|
79
80
|
RemovedMember,
|
|
80
81
|
AddMemberInput,
|
|
81
82
|
UpdateMemberInput,
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
WalletEntitlementKind,
|
|
87
|
-
WalletList,
|
|
88
|
-
WalletEntryInput,
|
|
83
|
+
// balance adjustments
|
|
84
|
+
WalletAdjustInput,
|
|
85
|
+
AdjustResult,
|
|
86
|
+
WalletPool,
|
|
89
87
|
CreditAdjustInput,
|
|
90
88
|
OutcomeAdjustInput,
|
|
91
89
|
UnitAdjustInput,
|
|
92
90
|
CompositeAdjustInput,
|
|
91
|
+
RecurringGrantInput,
|
|
92
|
+
RecurringGrantResult,
|
|
93
93
|
// plans
|
|
94
94
|
Plan,
|
|
95
|
-
PlanDetail,
|
|
96
95
|
PlanComponent,
|
|
97
|
-
PlanComponentInput,
|
|
98
|
-
WalletComponentInput,
|
|
99
|
-
FlatComponentInput,
|
|
100
|
-
CreditComponentInput,
|
|
101
|
-
OutcomeComponentInput,
|
|
102
|
-
UnitComponentInput,
|
|
103
|
-
CompositeComponentInput,
|
|
104
|
-
CreatePlanInput,
|
|
105
|
-
UpdatePlanInput,
|
|
106
96
|
BillingCycle,
|
|
107
97
|
PlanType,
|
|
108
98
|
PlanKind,
|
|
@@ -126,42 +116,6 @@ export type {
|
|
|
126
116
|
// payments
|
|
127
117
|
PaymentRow,
|
|
128
118
|
PaymentDetail,
|
|
129
|
-
// cost analytics (credits / outcomes)
|
|
130
|
-
CostPoint,
|
|
131
|
-
CostStats,
|
|
132
|
-
CreditAnalytics,
|
|
133
|
-
OutcomeAnalytics,
|
|
134
|
-
// credits catalog
|
|
135
|
-
Credit,
|
|
136
|
-
CreditDetail,
|
|
137
|
-
CreateCreditInput,
|
|
138
|
-
UpdateCreditInput,
|
|
139
|
-
ModelBundleEntry,
|
|
140
|
-
// outcomes catalog
|
|
141
|
-
Outcome,
|
|
142
|
-
OutcomeDetail,
|
|
143
|
-
OutcomeStepInput,
|
|
144
|
-
CreateOutcomeInput,
|
|
145
|
-
UpdateOutcomeInput,
|
|
146
|
-
// composites catalog
|
|
147
|
-
Composite,
|
|
148
|
-
CompositeCatalogueRef,
|
|
149
|
-
CreateCompositeInput,
|
|
150
|
-
// units catalog
|
|
151
|
-
Unit,
|
|
152
|
-
UnitDetail,
|
|
153
|
-
UnitCustomerRow,
|
|
154
|
-
UnitTier,
|
|
155
|
-
UnitTierInput,
|
|
156
|
-
UnitPricingType,
|
|
157
|
-
CreateUnitInput,
|
|
158
|
-
FlatUnitInput,
|
|
159
|
-
TieredUnitInput,
|
|
160
|
-
UpdateUnitInput,
|
|
161
|
-
// webhooks
|
|
162
|
-
Webhook,
|
|
163
|
-
UpsertWebhookInput,
|
|
164
|
-
ThresholdKind,
|
|
165
119
|
// portal
|
|
166
120
|
PortalTokenInput,
|
|
167
121
|
PortalToken,
|