@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/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
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";
|
|
4
6
|
import { Customers } from "./resources/customers.js";
|
|
5
7
|
import { Invoices } from "./resources/invoices.js";
|
|
8
|
+
import { Outcomes } from "./resources/outcomes.js";
|
|
6
9
|
import { Payments } from "./resources/payments.js";
|
|
7
10
|
import { Plans } from "./resources/plans.js";
|
|
8
11
|
import { Portal } from "./resources/portal.js";
|
|
9
12
|
import { Purchases } from "./resources/purchases.js";
|
|
10
13
|
import { Signals } from "./resources/signals.js";
|
|
14
|
+
import { Units } from "./resources/units.js";
|
|
11
15
|
import type { ClockNextConfig, ResolvedConfig } from "./types.js";
|
|
12
16
|
|
|
13
17
|
/**
|
|
@@ -32,8 +36,16 @@ export class ClockNext {
|
|
|
32
36
|
readonly signals: Signals;
|
|
33
37
|
/** Manage customers, their members, and balances. */
|
|
34
38
|
readonly customers: Customers;
|
|
35
|
-
/**
|
|
39
|
+
/** Billing plans: list, get, create, update, archive, unarchive. */
|
|
36
40
|
readonly plans: Plans;
|
|
41
|
+
/** Credits: list, get, create, update, archive, unarchive (no delete). */
|
|
42
|
+
readonly credits: Credits;
|
|
43
|
+
/** Outcomes: list, get, create, update, archive, unarchive (no delete). */
|
|
44
|
+
readonly outcomes: Outcomes;
|
|
45
|
+
/** Units: list, get, create, update, archive, unarchive (no delete). */
|
|
46
|
+
readonly units: Units;
|
|
47
|
+
/** Composites: list, get, create, update, archive, unarchive (no delete). */
|
|
48
|
+
readonly composites: Composites;
|
|
37
49
|
/** Subscribe customers to plans (purchases). */
|
|
38
50
|
readonly purchases: Purchases;
|
|
39
51
|
/** Read invoices and mint hosted pay links. */
|
|
@@ -60,6 +72,10 @@ export class ClockNext {
|
|
|
60
72
|
this.signals = new Signals(transport, this.flusher, this.cfg);
|
|
61
73
|
this.customers = new Customers(transport);
|
|
62
74
|
this.plans = new Plans(transport);
|
|
75
|
+
this.credits = new Credits(transport);
|
|
76
|
+
this.outcomes = new Outcomes(transport);
|
|
77
|
+
this.units = new Units(transport);
|
|
78
|
+
this.composites = new Composites(transport);
|
|
63
79
|
this.purchases = new Purchases(transport);
|
|
64
80
|
this.invoices = new Invoices(transport);
|
|
65
81
|
this.payments = new Payments(transport);
|
package/src/errors.ts
CHANGED
|
@@ -107,7 +107,7 @@ export class NetworkError extends ClockNextError {
|
|
|
107
107
|
*
|
|
108
108
|
* The server validates the WIRE body and names the offending path in its 400
|
|
109
109
|
* (`usage.inputTokens: Expected number…`). But the SDK groups those fields
|
|
110
|
-
* differently — `tokens: { input, output, cache }` — so the path it reports
|
|
110
|
+
* differently — `tokens: { input, output, cache, cacheWrite }` — so the path it reports
|
|
111
111
|
* names something that does not exist anywhere in this SDK's API. A caller
|
|
112
112
|
* (human or LLM) then searches their own code for `usage.inputTokens`, finds
|
|
113
113
|
* nothing, and has no next move.
|
|
@@ -120,6 +120,7 @@ const FIELD_PATHS: ReadonlyArray<readonly [RegExp, string]> = [
|
|
|
120
120
|
[/\busage\.inputTokens\b/g, "tokens.input"],
|
|
121
121
|
[/\busage\.outputTokens\b/g, "tokens.output"],
|
|
122
122
|
[/\busage\.cacheTokens\b/g, "tokens.cache"],
|
|
123
|
+
[/\busage\.cacheWriteTokens\b/g, "tokens.cacheWrite"],
|
|
123
124
|
[/\busage\.model\b/g, "model"],
|
|
124
125
|
// A missing/invalid `usage` block as a whole: the caller's equivalent is
|
|
125
126
|
// `tokens` (plus `model`, which the SDK hoists to the top level).
|
package/src/index.ts
CHANGED
|
@@ -72,6 +72,7 @@ export type {
|
|
|
72
72
|
CreditBalance,
|
|
73
73
|
OutcomeBalance,
|
|
74
74
|
UnitBalance,
|
|
75
|
+
CompositeBalance,
|
|
75
76
|
CustomerPlan,
|
|
76
77
|
CustomerPlanDetails,
|
|
77
78
|
// members
|
|
@@ -92,6 +93,31 @@ export type {
|
|
|
92
93
|
RecurringGrantResult,
|
|
93
94
|
// plans
|
|
94
95
|
Plan,
|
|
96
|
+
PlanEntitlement,
|
|
97
|
+
PlanEntitlementInput,
|
|
98
|
+
CreatePlanInput,
|
|
99
|
+
UpdatePlanInput,
|
|
100
|
+
// catalogue: credits, outcomes, units, composites
|
|
101
|
+
ModelBundleLine,
|
|
102
|
+
ModelBundleLineInput,
|
|
103
|
+
Credit,
|
|
104
|
+
CreateCreditInput,
|
|
105
|
+
UpdateCreditInput,
|
|
106
|
+
Outcome,
|
|
107
|
+
OutcomeStep,
|
|
108
|
+
OutcomeWithSteps,
|
|
109
|
+
OutcomeStepInput,
|
|
110
|
+
CreateOutcomeInput,
|
|
111
|
+
UpdateOutcomeInput,
|
|
112
|
+
UnitPricingType,
|
|
113
|
+
UnitTier,
|
|
114
|
+
Unit,
|
|
115
|
+
CreateUnitInput,
|
|
116
|
+
UpdateUnitInput,
|
|
117
|
+
CompositeItem,
|
|
118
|
+
Composite,
|
|
119
|
+
CreateCompositeInput,
|
|
120
|
+
UpdateCompositeInput,
|
|
95
121
|
PlanComponent,
|
|
96
122
|
BillingCycle,
|
|
97
123
|
PlanType,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
|
+
import type { Transport } from "../http.js";
|
|
3
|
+
import type { Composite, CreateCompositeInput, UpdateCompositeInput } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `composites` resource — several credits / outcomes / units grouped under
|
|
7
|
+
* one tag (`refId`) and billed as ONE thing per completed occurrence.
|
|
8
|
+
* `/api/v1/composites`.
|
|
9
|
+
*
|
|
10
|
+
* Creating a composite charges nobody: it only bills once a plan sells it as
|
|
11
|
+
* a `PRICING_METRIC` entitlement (`plans.create()` with its `compositeId`).
|
|
12
|
+
*
|
|
13
|
+
* There is no `delete()` — the API never deletes catalogue items. Retire a
|
|
14
|
+
* composite with `archive()` (new signals stop resolving to it; its history is
|
|
15
|
+
* kept); `unarchive()` brings it back.
|
|
16
|
+
*/
|
|
17
|
+
export class Composites {
|
|
18
|
+
constructor(private readonly transport: Transport) {}
|
|
19
|
+
|
|
20
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
21
|
+
* only archived ones; omit it for both. */
|
|
22
|
+
async list(params: { active?: boolean } = {}): Promise<Composite[]> {
|
|
23
|
+
const res = await this.transport.request<{ composites: Composite[] }>({
|
|
24
|
+
method: "GET",
|
|
25
|
+
path: "/api/v1/composites",
|
|
26
|
+
query: { active: activeQuery(params.active) },
|
|
27
|
+
});
|
|
28
|
+
return filterByActive(res.composites, params.active);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** One composite's configuration. */
|
|
32
|
+
async get(id: string): Promise<Composite> {
|
|
33
|
+
const res = await this.transport.request<{ composite: Composite }>({
|
|
34
|
+
method: "GET",
|
|
35
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}`,
|
|
36
|
+
});
|
|
37
|
+
return res.composite;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
41
|
+
* create a second row. */
|
|
42
|
+
async create(input: CreateCompositeInput): Promise<Composite> {
|
|
43
|
+
const res = await this.transport.request<{ created: true; composite: Composite }>({
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/api/v1/composites",
|
|
46
|
+
body: input,
|
|
47
|
+
});
|
|
48
|
+
return res.composite;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** PARTIAL update: only the fields you send change. `entitlements`, when
|
|
52
|
+
* sent, is the complete new set. Renaming `refId` cuts live traffic over at
|
|
53
|
+
* once — ship the new tag to your callers first. */
|
|
54
|
+
async update(id: string, input: UpdateCompositeInput): Promise<Composite> {
|
|
55
|
+
const res = await this.transport.request<{ updated: true; composite: Composite }>({
|
|
56
|
+
method: "PATCH",
|
|
57
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}`,
|
|
58
|
+
body: input,
|
|
59
|
+
});
|
|
60
|
+
return res.composite;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
64
|
+
async archive(id: string): Promise<Composite> {
|
|
65
|
+
const res = await this.transport.request<{ archived: true; composite: Composite }>({
|
|
66
|
+
method: "POST",
|
|
67
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}/archive`,
|
|
68
|
+
retry: true,
|
|
69
|
+
});
|
|
70
|
+
return res.composite;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
74
|
+
async unarchive(id: string): Promise<Composite> {
|
|
75
|
+
const res = await this.transport.request<{ unarchived: true; composite: Composite }>({
|
|
76
|
+
method: "POST",
|
|
77
|
+
path: `/api/v1/composites/${encodeURIComponent(id)}/unarchive`,
|
|
78
|
+
retry: true,
|
|
79
|
+
});
|
|
80
|
+
return res.composite;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
|
+
import type { Transport } from "../http.js";
|
|
3
|
+
import type { CreateCreditInput, Credit, UpdateCreditInput } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `credits` resource — the token-metered credits your product draws down
|
|
7
|
+
* by `agentKey`. `/api/v1/credits`.
|
|
8
|
+
*
|
|
9
|
+
* Pricing is never typed in: `create()` takes a `modelBundle` (one line per
|
|
10
|
+
* model, each with `averageTokensPerLLMCall` and its input / output / cache /
|
|
11
|
+
* cacheWrite split) and the server works out `basePrice` and
|
|
12
|
+
* `pricePerCredit` from the models' live prices.
|
|
13
|
+
*
|
|
14
|
+
* There is no `delete()` — the API never deletes catalogue items. Retire a
|
|
15
|
+
* credit with `archive()`; `unarchive()` brings it back unchanged.
|
|
16
|
+
*/
|
|
17
|
+
export class Credits {
|
|
18
|
+
constructor(private readonly transport: Transport) {}
|
|
19
|
+
|
|
20
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
21
|
+
* only archived ones; omit it for both. */
|
|
22
|
+
async list(params: { active?: boolean } = {}): Promise<Credit[]> {
|
|
23
|
+
const res = await this.transport.request<{ credits: Credit[] }>({
|
|
24
|
+
method: "GET",
|
|
25
|
+
path: "/api/v1/credits",
|
|
26
|
+
query: { active: activeQuery(params.active) },
|
|
27
|
+
});
|
|
28
|
+
return filterByActive(res.credits, params.active);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** One credit's configuration. */
|
|
32
|
+
async get(id: string): Promise<Credit> {
|
|
33
|
+
const res = await this.transport.request<{ credit: Credit }>({
|
|
34
|
+
method: "GET",
|
|
35
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
36
|
+
});
|
|
37
|
+
return res.credit;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
41
|
+
* create a second row. */
|
|
42
|
+
async create(input: CreateCreditInput): Promise<Credit> {
|
|
43
|
+
const res = await this.transport.request<{ created: true; credit: Credit }>({
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/api/v1/credits",
|
|
46
|
+
body: input,
|
|
47
|
+
});
|
|
48
|
+
return res.credit;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** PARTIAL update: only the fields you send change. Send `modelBundle` to
|
|
52
|
+
* re-price; leave it out to keep the stored base price. */
|
|
53
|
+
async update(id: string, input: UpdateCreditInput): Promise<Credit> {
|
|
54
|
+
const res = await this.transport.request<{ updated: true; credit: Credit }>({
|
|
55
|
+
method: "PATCH",
|
|
56
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}`,
|
|
57
|
+
body: input,
|
|
58
|
+
});
|
|
59
|
+
return res.credit;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
63
|
+
async archive(id: string): Promise<Credit> {
|
|
64
|
+
const res = await this.transport.request<{ archived: true; credit: Credit }>({
|
|
65
|
+
method: "POST",
|
|
66
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}/archive`,
|
|
67
|
+
retry: true,
|
|
68
|
+
});
|
|
69
|
+
return res.credit;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
73
|
+
async unarchive(id: string): Promise<Credit> {
|
|
74
|
+
const res = await this.transport.request<{ unarchived: true; credit: Credit }>({
|
|
75
|
+
method: "POST",
|
|
76
|
+
path: `/api/v1/credits/${encodeURIComponent(id)}/unarchive`,
|
|
77
|
+
retry: true,
|
|
78
|
+
});
|
|
79
|
+
return res.credit;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -310,7 +310,7 @@ export class Customers {
|
|
|
310
310
|
* Top up (positive `delta`) or draw down (negative `delta`) a customer's
|
|
311
311
|
* wallet, in USD — allowed whatever the customer's plan. `remaining` is the
|
|
312
312
|
* resulting USD balance. No `agentKey` — a customer has exactly one wallet.
|
|
313
|
-
* Pass `pool: "
|
|
313
|
+
* Pass `pool: "reserved"` to move the Reserved Wallet instead (then
|
|
314
314
|
* `remaining` is its balance). `POST …/:id/wallet/adjust`.
|
|
315
315
|
*/
|
|
316
316
|
adjustWallet(id: string, input: WalletAdjustInput): Promise<AdjustResult> {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
|
+
import type { Transport } from "../http.js";
|
|
3
|
+
import type { CreateOutcomeInput, Outcome, OutcomeWithSteps, UpdateOutcomeInput } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `outcomes` resource — multi-step deliverables billed per completed
|
|
7
|
+
* outcome. `/api/v1/outcomes`.
|
|
8
|
+
*
|
|
9
|
+
* `list()` and every write return the outcome without its steps; `get()`
|
|
10
|
+
* returns it with every step in full (ids included). Each new step is priced
|
|
11
|
+
* from its own `modelBundle`, on the server.
|
|
12
|
+
*
|
|
13
|
+
* There is no `delete()` — the API never deletes catalogue items. Retire an
|
|
14
|
+
* outcome with `archive()`; `unarchive()` brings it back unchanged.
|
|
15
|
+
*/
|
|
16
|
+
export class Outcomes {
|
|
17
|
+
constructor(private readonly transport: Transport) {}
|
|
18
|
+
|
|
19
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
20
|
+
* only archived ones; omit it for both. */
|
|
21
|
+
async list(params: { active?: boolean } = {}): Promise<Outcome[]> {
|
|
22
|
+
const res = await this.transport.request<{ outcomes: Outcome[] }>({
|
|
23
|
+
method: "GET",
|
|
24
|
+
path: "/api/v1/outcomes",
|
|
25
|
+
query: { active: activeQuery(params.active) },
|
|
26
|
+
});
|
|
27
|
+
return filterByActive(res.outcomes, params.active);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** One outcome's configuration, with every step in full. */
|
|
31
|
+
async get(id: string): Promise<OutcomeWithSteps> {
|
|
32
|
+
const res = await this.transport.request<{ outcome: OutcomeWithSteps }>({
|
|
33
|
+
method: "GET",
|
|
34
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
35
|
+
});
|
|
36
|
+
return res.outcome;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
40
|
+
* create a second row. */
|
|
41
|
+
async create(input: CreateOutcomeInput): Promise<Outcome> {
|
|
42
|
+
const res = await this.transport.request<{ created: true; outcome: Outcome }>({
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: "/api/v1/outcomes",
|
|
45
|
+
body: input,
|
|
46
|
+
});
|
|
47
|
+
return res.outcome;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** PARTIAL update: only the fields you send change. Leave `steps` out to
|
|
51
|
+
* leave the steps alone; send it and it is the complete list — pass each
|
|
52
|
+
* existing step's `id` (or its same `agentKey`) to keep it. */
|
|
53
|
+
async update(id: string, input: UpdateOutcomeInput): Promise<Outcome> {
|
|
54
|
+
const res = await this.transport.request<{ updated: true; outcome: Outcome }>({
|
|
55
|
+
method: "PATCH",
|
|
56
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}`,
|
|
57
|
+
body: input,
|
|
58
|
+
});
|
|
59
|
+
return res.outcome;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
63
|
+
async archive(id: string): Promise<Outcome> {
|
|
64
|
+
const res = await this.transport.request<{ archived: true; outcome: Outcome }>({
|
|
65
|
+
method: "POST",
|
|
66
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}/archive`,
|
|
67
|
+
retry: true,
|
|
68
|
+
});
|
|
69
|
+
return res.outcome;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
73
|
+
async unarchive(id: string): Promise<Outcome> {
|
|
74
|
+
const res = await this.transport.request<{ unarchived: true; outcome: Outcome }>({
|
|
75
|
+
method: "POST",
|
|
76
|
+
path: `/api/v1/outcomes/${encodeURIComponent(id)}/unarchive`,
|
|
77
|
+
retry: true,
|
|
78
|
+
});
|
|
79
|
+
return res.outcome;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/resources/plans.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
2
|
import type { Transport } from "../http.js";
|
|
3
|
-
import type { Plan } from "../types.js";
|
|
3
|
+
import type { CreatePlanInput, Plan, UpdatePlanInput } from "../types.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The `plans` resource —
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `plans` resource — the billing plans customers subscribe to. Each plan
|
|
7
|
+
* is a set of `entitlements` (wallet / credit / outcome / unit / composite /
|
|
8
|
+
* flat lines) billed on a cycle. `/api/v1/plans`.
|
|
9
|
+
*
|
|
10
|
+
* A plan's currency is the workspace's primary currency; it can't be chosen.
|
|
11
|
+
* There is no `delete()` — the API never deletes plans, so customers already
|
|
12
|
+
* on one keep what they bought. Retire a plan with `archive()`; `unarchive()`
|
|
13
|
+
* makes it purchasable again.
|
|
9
14
|
*/
|
|
10
15
|
export class Plans {
|
|
11
16
|
constructor(private readonly transport: Transport) {}
|
|
@@ -21,4 +26,57 @@ export class Plans {
|
|
|
21
26
|
});
|
|
22
27
|
return filterByActive(res.plans, params.active);
|
|
23
28
|
}
|
|
29
|
+
|
|
30
|
+
/** One plan's configuration. */
|
|
31
|
+
async get(id: string): Promise<Plan> {
|
|
32
|
+
const res = await this.transport.request<{ plan: Plan }>({
|
|
33
|
+
method: "GET",
|
|
34
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
35
|
+
});
|
|
36
|
+
return res.plan;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Create a plan. It starts active. Not retried on failure — a retry could
|
|
40
|
+
* create a second plan. */
|
|
41
|
+
async create(input: CreatePlanInput): Promise<Plan> {
|
|
42
|
+
const res = await this.transport.request<{ created: true; plan: Plan }>({
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: "/api/v1/plans",
|
|
45
|
+
body: input,
|
|
46
|
+
});
|
|
47
|
+
return res.plan;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** PARTIAL update: only the fields you send change. `entitlements`, when
|
|
51
|
+
* sent, is the complete new list — the list `get()` returned can be sent
|
|
52
|
+
* back as it is. Changes apply to new purchases only. */
|
|
53
|
+
async update(id: string, input: UpdatePlanInput): Promise<Plan> {
|
|
54
|
+
const res = await this.transport.request<{ updated: true; plan: Plan }>({
|
|
55
|
+
method: "PATCH",
|
|
56
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
57
|
+
body: input,
|
|
58
|
+
});
|
|
59
|
+
return res.plan;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Retire a plan (`isActive` → false): it can't be bought any more; customers
|
|
63
|
+
* already on it are unaffected. Safe to retry. */
|
|
64
|
+
async archive(id: string): Promise<Plan> {
|
|
65
|
+
const res = await this.transport.request<{ archived: true; plan: Plan }>({
|
|
66
|
+
method: "POST",
|
|
67
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}/archive`,
|
|
68
|
+
retry: true,
|
|
69
|
+
});
|
|
70
|
+
return res.plan;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Make an archived plan purchasable again (`isActive` → true). Safe to retry. */
|
|
74
|
+
async unarchive(id: string): Promise<Plan> {
|
|
75
|
+
const res = await this.transport.request<{ unarchived: true; plan: Plan }>({
|
|
76
|
+
method: "POST",
|
|
77
|
+
path: `/api/v1/plans/${encodeURIComponent(id)}/unarchive`,
|
|
78
|
+
retry: true,
|
|
79
|
+
});
|
|
80
|
+
return res.plan;
|
|
81
|
+
}
|
|
24
82
|
}
|
package/src/resources/signals.ts
CHANGED
|
@@ -69,12 +69,14 @@ export function signalToWire(signal: Signal): Record<string, unknown> {
|
|
|
69
69
|
const body: Record<string, unknown> = {
|
|
70
70
|
...customerRefToWire(signal),
|
|
71
71
|
// `usage` is required on all three model-priced kinds. input/output are
|
|
72
|
-
// always sent; `cacheTokens` only when provided (the
|
|
72
|
+
// always sent; `cacheTokens` / `cacheWriteTokens` only when provided (the
|
|
73
|
+
// server defaults each to 0).
|
|
73
74
|
usage: {
|
|
74
75
|
model: signal.model,
|
|
75
76
|
inputTokens: t.input,
|
|
76
77
|
outputTokens: t.output,
|
|
77
78
|
...(t.cache != null ? { cacheTokens: t.cache } : {}),
|
|
79
|
+
...(t.cacheWrite != null ? { cacheWriteTokens: t.cacheWrite } : {}),
|
|
78
80
|
},
|
|
79
81
|
};
|
|
80
82
|
if (signal.member) body.member = signal.member;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
|
+
import type { Transport } from "../http.js";
|
|
3
|
+
import type { CreateUnitInput, Unit, UpdateUnitInput } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `units` resource — fixed-price, non-LLM events (uploads, seats, API
|
|
7
|
+
* calls), priced FLAT, SLAB or VOLUME. `/api/v1/units`.
|
|
8
|
+
*
|
|
9
|
+
* There is no `delete()` — the API never deletes catalogue items. Retire a
|
|
10
|
+
* unit with `archive()`; `unarchive()` brings it back unchanged.
|
|
11
|
+
*/
|
|
12
|
+
export class Units {
|
|
13
|
+
constructor(private readonly transport: Transport) {}
|
|
14
|
+
|
|
15
|
+
/** List them. `{ active: true }` returns only active ones, `{ active: false }`
|
|
16
|
+
* only archived ones; omit it for both. */
|
|
17
|
+
async list(params: { active?: boolean } = {}): Promise<Unit[]> {
|
|
18
|
+
const res = await this.transport.request<{ units: Unit[] }>({
|
|
19
|
+
method: "GET",
|
|
20
|
+
path: "/api/v1/units",
|
|
21
|
+
query: { active: activeQuery(params.active) },
|
|
22
|
+
});
|
|
23
|
+
return filterByActive(res.units, params.active);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** One unit's configuration. */
|
|
27
|
+
async get(id: string): Promise<Unit> {
|
|
28
|
+
const res = await this.transport.request<{ unit: Unit }>({
|
|
29
|
+
method: "GET",
|
|
30
|
+
path: `/api/v1/units/${encodeURIComponent(id)}`,
|
|
31
|
+
});
|
|
32
|
+
return res.unit;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Create one. It starts active. Not retried on failure — a retry could
|
|
36
|
+
* create a second row. */
|
|
37
|
+
async create(input: CreateUnitInput): Promise<Unit> {
|
|
38
|
+
const res = await this.transport.request<{ created: true; unit: Unit }>({
|
|
39
|
+
method: "POST",
|
|
40
|
+
path: "/api/v1/units",
|
|
41
|
+
body: input,
|
|
42
|
+
});
|
|
43
|
+
return res.unit;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** PARTIAL update: only the fields you send change. `tiers`, when sent, is
|
|
47
|
+
* the complete new tier list. */
|
|
48
|
+
async update(id: string, input: UpdateUnitInput): Promise<Unit> {
|
|
49
|
+
const res = await this.transport.request<{ updated: true; unit: Unit }>({
|
|
50
|
+
method: "PATCH",
|
|
51
|
+
path: `/api/v1/units/${encodeURIComponent(id)}`,
|
|
52
|
+
body: input,
|
|
53
|
+
});
|
|
54
|
+
return res.unit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Retire it (`isActive` → false). Nothing is deleted. Safe to retry. */
|
|
58
|
+
async archive(id: string): Promise<Unit> {
|
|
59
|
+
const res = await this.transport.request<{ archived: true; unit: Unit }>({
|
|
60
|
+
method: "POST",
|
|
61
|
+
path: `/api/v1/units/${encodeURIComponent(id)}/archive`,
|
|
62
|
+
retry: true,
|
|
63
|
+
});
|
|
64
|
+
return res.unit;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Bring an archived one back (`isActive` → true). Safe to retry. */
|
|
68
|
+
async unarchive(id: string): Promise<Unit> {
|
|
69
|
+
const res = await this.transport.request<{ unarchived: true; unit: Unit }>({
|
|
70
|
+
method: "POST",
|
|
71
|
+
path: `/api/v1/units/${encodeURIComponent(id)}/unarchive`,
|
|
72
|
+
retry: true,
|
|
73
|
+
});
|
|
74
|
+
return res.unit;
|
|
75
|
+
}
|
|
76
|
+
}
|