@clocknext/sdk 0.14.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 +188 -445
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +295 -818
- package/dist/index.d.ts +295 -818
- package/dist/index.js +188 -445
- 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 +7 -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 +5 -45
- package/src/types.ts +223 -612
- 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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Transport } from "../http.js";
|
|
2
|
+
import { newKey } from "../idempotency.js";
|
|
2
3
|
import type {
|
|
3
4
|
AddMemberInput,
|
|
5
|
+
AdjustResult,
|
|
4
6
|
ApiCustomer,
|
|
5
7
|
CompositeAdjustInput,
|
|
6
8
|
CreateCustomerInput,
|
|
@@ -14,19 +16,18 @@ import type {
|
|
|
14
16
|
MemberProfile,
|
|
15
17
|
OutcomeAdjustInput,
|
|
16
18
|
OutcomeBalance,
|
|
19
|
+
RecurringGrantInput,
|
|
20
|
+
RecurringGrantResult,
|
|
17
21
|
RemovedMember,
|
|
18
22
|
UnitAdjustInput,
|
|
19
23
|
UnitBalance,
|
|
20
24
|
UpdateMemberInput,
|
|
21
|
-
|
|
22
|
-
WalletEntryInput,
|
|
23
|
-
WalletList,
|
|
24
|
-
WalletTransaction,
|
|
25
|
+
WalletAdjustInput,
|
|
25
26
|
} from "../types.js";
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* The `customers` resource — full CRUD over the org's customers plus the
|
|
29
|
-
* read-only insight endpoints (
|
|
30
|
+
* read-only insight endpoints (balances / plan). Every call is scoped
|
|
30
31
|
* to the API key's organisation server-side; a customer in another org
|
|
31
32
|
* resolves as a NotFoundError.
|
|
32
33
|
*/
|
|
@@ -94,6 +95,42 @@ export class Customers {
|
|
|
94
95
|
return res.customer;
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Fetch one customer by YOUR id for them (its `externalId`), instead of
|
|
100
|
+
* ours. Same result as {@link get}. `GET /api/v1/customers/ext/:externalId`.
|
|
101
|
+
* An unknown external id is a `NotFoundError`; only active customers match.
|
|
102
|
+
*/
|
|
103
|
+
async getByExternalId(externalId: string): Promise<ApiCustomer> {
|
|
104
|
+
const res = await this.transport.request<{ customer: ApiCustomer }>({
|
|
105
|
+
method: "GET",
|
|
106
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`,
|
|
107
|
+
});
|
|
108
|
+
return res.customer;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Update a customer (partial), addressed by its `externalId`. Same body as
|
|
112
|
+
* {@link update}. `PATCH /api/v1/customers/ext/:externalId`. */
|
|
113
|
+
async updateByExternalId(
|
|
114
|
+
externalId: string,
|
|
115
|
+
input: CustomerProfileInput,
|
|
116
|
+
): Promise<ApiCustomer> {
|
|
117
|
+
const res = await this.transport.request<{ customer: ApiCustomer }>({
|
|
118
|
+
method: "PATCH",
|
|
119
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`,
|
|
120
|
+
body: input,
|
|
121
|
+
});
|
|
122
|
+
return res.customer;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** {@link delete}, addressing the customer by its `externalId`.
|
|
126
|
+
* `DELETE /api/v1/customers/ext/:externalId`. */
|
|
127
|
+
async deleteByExternalId(externalId: string): Promise<void> {
|
|
128
|
+
await this.transport.request({
|
|
129
|
+
method: "DELETE",
|
|
130
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
97
134
|
/** Delete a customer (members, invitations, usage logs cascade). */
|
|
98
135
|
async delete(id: string): Promise<void> {
|
|
99
136
|
await this.transport.request({
|
|
@@ -102,21 +139,20 @@ export class Customers {
|
|
|
102
139
|
});
|
|
103
140
|
}
|
|
104
141
|
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
142
|
+
/** Wallet / credit / outcome / unit balances. `GET …/:id/balances`. */
|
|
143
|
+
balances(id: string): Promise<CustomerBalances> {
|
|
144
|
+
return this.transport.request<CustomerBalances>({
|
|
108
145
|
method: "GET",
|
|
109
|
-
path: `/api/v1/
|
|
110
|
-
query: { customerId: id, limit: params.limit },
|
|
146
|
+
path: `/api/v1/customers/${encodeURIComponent(id)}/balances`,
|
|
111
147
|
});
|
|
112
|
-
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
113
148
|
}
|
|
114
149
|
|
|
115
|
-
/**
|
|
116
|
-
balances
|
|
150
|
+
/** {@link balances}, addressing the customer by its `externalId`.
|
|
151
|
+
* `GET /api/v1/customers/ext/:externalId/balances`. */
|
|
152
|
+
balancesByExternalId(externalId: string): Promise<CustomerBalances> {
|
|
117
153
|
return this.transport.request<CustomerBalances>({
|
|
118
154
|
method: "GET",
|
|
119
|
-
path: `/api/v1/customers/${encodeURIComponent(
|
|
155
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/balances`,
|
|
120
156
|
});
|
|
121
157
|
}
|
|
122
158
|
|
|
@@ -183,6 +219,15 @@ export class Customers {
|
|
|
183
219
|
});
|
|
184
220
|
}
|
|
185
221
|
|
|
222
|
+
/** {@link plan}, addressing the customer by its `externalId`.
|
|
223
|
+
* `GET /api/v1/customers/ext/:externalId/plan`. */
|
|
224
|
+
planByExternalId(externalId: string): Promise<CustomerPlan> {
|
|
225
|
+
return this.transport.request<CustomerPlan>({
|
|
226
|
+
method: "GET",
|
|
227
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/plan`,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
186
231
|
// --- Members -------------------------------------------------------------
|
|
187
232
|
|
|
188
233
|
/** List a customer's members. `GET …/:id/members`. */
|
|
@@ -227,95 +272,169 @@ export class Customers {
|
|
|
227
272
|
return res.member;
|
|
228
273
|
}
|
|
229
274
|
|
|
230
|
-
// ---
|
|
275
|
+
// --- Billing config -----------------------------------------------------
|
|
231
276
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
277
|
+
// Note: a customer's currency is set through `update(id, { currencyCode })`
|
|
278
|
+
// (PATCH …/:id) — there is no separate currency endpoint. Credit-type
|
|
279
|
+
// assignment has no public API.
|
|
280
|
+
|
|
281
|
+
// --- Balance adjustments -------------------------------------------------
|
|
282
|
+
|
|
283
|
+
/** Grant or claw back a credit balance. The credit must be a prepaid part of
|
|
284
|
+
* the customer's current plan. Pass `idempotencyKey` to make it safe to
|
|
285
|
+
* retry. `POST …/:id/credits/adjust`. */
|
|
286
|
+
adjustCredit(id: string, input: CreditAdjustInput): Promise<AdjustResult> {
|
|
287
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/credits/adjust`, input);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Grant or claw back an outcome balance. The outcome must be a prepaid part
|
|
291
|
+
* of the customer's current plan. `POST …/:id/outcomes/adjust`. */
|
|
292
|
+
adjustOutcome(id: string, input: OutcomeAdjustInput): Promise<AdjustResult> {
|
|
293
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/outcomes/adjust`, input);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Grant or claw back a unit balance. The unit must be a prepaid part of the
|
|
297
|
+
* customer's current plan. `POST …/:id/units/adjust`. */
|
|
298
|
+
adjustUnit(id: string, input: UnitAdjustInput): Promise<AdjustResult> {
|
|
299
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/units/adjust`, input);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Grant or claw back slots on a customer's ADVANCE composite pool for the
|
|
303
|
+
* current billing cycle. `remaining` is the resulting slot count.
|
|
304
|
+
* `POST …/:id/composites/adjust`. */
|
|
305
|
+
adjustComposite(id: string, input: CompositeAdjustInput): Promise<AdjustResult> {
|
|
306
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/composites/adjust`, input);
|
|
239
307
|
}
|
|
240
308
|
|
|
241
309
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
310
|
+
* Top up (positive `delta`) or draw down (negative `delta`) a customer's
|
|
311
|
+
* wallet, in USD — allowed whatever the customer's plan. `remaining` is the
|
|
312
|
+
* resulting USD balance. No `agentKey` — a customer has exactly one wallet.
|
|
313
|
+
* Pass `pool: "RESERVED"` to move the Reserved Wallet instead (then
|
|
314
|
+
* `remaining` is its balance). `POST …/:id/wallet/adjust`.
|
|
244
315
|
*/
|
|
245
|
-
|
|
246
|
-
id
|
|
247
|
-
input: WalletEntryInput,
|
|
248
|
-
): Promise<{ transaction: WalletTransaction; balanceUsd: number }> {
|
|
249
|
-
return this.transport.request<{
|
|
250
|
-
transaction: WalletTransaction;
|
|
251
|
-
balanceUsd: number;
|
|
252
|
-
}>({
|
|
253
|
-
method: "POST",
|
|
254
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/wallet`,
|
|
255
|
-
body: input,
|
|
256
|
-
});
|
|
316
|
+
adjustWallet(id: string, input: WalletAdjustInput): Promise<AdjustResult> {
|
|
317
|
+
return this.adjust(`/api/v1/customers/${encodeURIComponent(id)}/wallet/adjust`, input);
|
|
257
318
|
}
|
|
258
319
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
320
|
+
/** {@link adjustCredit}, addressing the customer by its `externalId` (`id`
|
|
321
|
+
* here). `POST /api/v1/customers/ext/:externalId/credits/adjust`. */
|
|
322
|
+
adjustCreditByExternalId(id: string, input: CreditAdjustInput): Promise<AdjustResult> {
|
|
323
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/credits/adjust`, input);
|
|
324
|
+
}
|
|
262
325
|
|
|
263
|
-
|
|
326
|
+
/** {@link adjustOutcome}, addressing the customer by its `externalId` (`id`
|
|
327
|
+
* here). `POST /api/v1/customers/ext/:externalId/outcomes/adjust`. */
|
|
328
|
+
adjustOutcomeByExternalId(id: string, input: OutcomeAdjustInput): Promise<AdjustResult> {
|
|
329
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/outcomes/adjust`, input);
|
|
330
|
+
}
|
|
264
331
|
|
|
265
|
-
/**
|
|
266
|
-
* `POST
|
|
267
|
-
|
|
268
|
-
id
|
|
269
|
-
input: CreditAdjustInput,
|
|
270
|
-
): Promise<{ remaining: number }> {
|
|
271
|
-
const res = await this.transport.request<{ remaining: number }>({
|
|
272
|
-
method: "POST",
|
|
273
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/credits/adjust`,
|
|
274
|
-
body: input,
|
|
275
|
-
});
|
|
276
|
-
return { remaining: res.remaining };
|
|
332
|
+
/** {@link adjustUnit}, addressing the customer by its `externalId` (`id`
|
|
333
|
+
* here). `POST /api/v1/customers/ext/:externalId/units/adjust`. */
|
|
334
|
+
adjustUnitByExternalId(id: string, input: UnitAdjustInput): Promise<AdjustResult> {
|
|
335
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/units/adjust`, input);
|
|
277
336
|
}
|
|
278
337
|
|
|
279
|
-
/**
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
input
|
|
283
|
-
): Promise<{ remaining: number }> {
|
|
284
|
-
const res = await this.transport.request<{ remaining: number }>({
|
|
285
|
-
method: "POST",
|
|
286
|
-
path: `/api/v1/customers/${encodeURIComponent(id)}/outcomes/adjust`,
|
|
287
|
-
body: input,
|
|
288
|
-
});
|
|
289
|
-
return { remaining: res.remaining };
|
|
338
|
+
/** {@link adjustComposite}, addressing the customer by its `externalId`
|
|
339
|
+
* (`id` here). `POST /api/v1/customers/ext/:externalId/composites/adjust`. */
|
|
340
|
+
adjustCompositeByExternalId(id: string, input: CompositeAdjustInput): Promise<AdjustResult> {
|
|
341
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/composites/adjust`, input);
|
|
290
342
|
}
|
|
291
343
|
|
|
292
|
-
/**
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
input
|
|
296
|
-
|
|
297
|
-
|
|
344
|
+
/** {@link adjustWallet}, addressing the customer by its `externalId` (`id`
|
|
345
|
+
* here). `POST /api/v1/customers/ext/:externalId/wallet/adjust`. */
|
|
346
|
+
adjustWalletByExternalId(id: string, input: WalletAdjustInput): Promise<AdjustResult> {
|
|
347
|
+
return this.adjust(`/api/v1/customers/ext/${encodeURIComponent(id)}/wallet/adjust`, input);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The one body behind all ten adjust calls.
|
|
352
|
+
*
|
|
353
|
+
* Every adjustment carries an idempotency key — the caller's, or one
|
|
354
|
+
* generated here ONCE per call, exactly like signals. The server
|
|
355
|
+
* deduplicates on it, so a transient failure is safe to retry: the same key
|
|
356
|
+
* rides every attempt, and a retry of one that already landed comes back as
|
|
357
|
+
* `replayed: true` instead of adjusting again. The key is also copied onto
|
|
358
|
+
* any thrown error (`error.idempotencyKey`) so the caller can replay safely.
|
|
359
|
+
*/
|
|
360
|
+
private async adjust(
|
|
361
|
+
path: string,
|
|
362
|
+
input:
|
|
363
|
+
| CreditAdjustInput
|
|
364
|
+
| OutcomeAdjustInput
|
|
365
|
+
| UnitAdjustInput
|
|
366
|
+
| CompositeAdjustInput
|
|
367
|
+
| WalletAdjustInput,
|
|
368
|
+
): Promise<AdjustResult> {
|
|
369
|
+
const idempotencyKey = input.idempotencyKey ?? newKey();
|
|
370
|
+
const res = await this.transport.request<{
|
|
371
|
+
remaining: number;
|
|
372
|
+
replayed?: boolean;
|
|
373
|
+
adjustedAt?: string;
|
|
374
|
+
customerArchived?: boolean;
|
|
375
|
+
}>({
|
|
298
376
|
method: "POST",
|
|
299
|
-
path
|
|
300
|
-
|
|
377
|
+
path,
|
|
378
|
+
idempotencyKey,
|
|
379
|
+
body: { ...input, idempotencyKey },
|
|
380
|
+
retry: true,
|
|
301
381
|
});
|
|
302
|
-
|
|
382
|
+
|
|
383
|
+
const result: AdjustResult = {
|
|
384
|
+
remaining: res.remaining,
|
|
385
|
+
replayed: res.replayed === true,
|
|
386
|
+
customerArchived: res.customerArchived === true,
|
|
387
|
+
};
|
|
388
|
+
if (result.replayed && typeof res.adjustedAt === "string") {
|
|
389
|
+
result.adjustedAt = res.adjustedAt;
|
|
390
|
+
}
|
|
391
|
+
return result;
|
|
303
392
|
}
|
|
304
393
|
|
|
394
|
+
// --- Recurring grants ----------------------------------------------------
|
|
395
|
+
|
|
305
396
|
/**
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
* `
|
|
397
|
+
* Change how much a customer is granted every billing cycle (wallet top-up,
|
|
398
|
+
* credits, outcomes, units or a composite pool). Any increase or decrease
|
|
399
|
+
* applies to their current balance immediately. `PUT …/:id/recurring-grant`.
|
|
309
400
|
*/
|
|
310
|
-
async
|
|
401
|
+
async updateRecurringGrant(
|
|
311
402
|
id: string,
|
|
312
|
-
input:
|
|
313
|
-
): Promise<
|
|
314
|
-
const res = await this.transport.request<
|
|
315
|
-
|
|
316
|
-
|
|
403
|
+
input: RecurringGrantInput,
|
|
404
|
+
): Promise<RecurringGrantResult> {
|
|
405
|
+
const res = await this.transport.request<
|
|
406
|
+
RecurringGrantResult & { updated: true }
|
|
407
|
+
>({
|
|
408
|
+
method: "PUT",
|
|
409
|
+
path: `/api/v1/customers/${encodeURIComponent(id)}/recurring-grant`,
|
|
410
|
+
body: input,
|
|
411
|
+
});
|
|
412
|
+
return toRecurringGrantResult(res);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** {@link updateRecurringGrant}, addressing the customer by its
|
|
416
|
+
* `externalId`. `PUT /api/v1/customers/ext/:externalId/recurring-grant`. */
|
|
417
|
+
async updateRecurringGrantByExternalId(
|
|
418
|
+
externalId: string,
|
|
419
|
+
input: RecurringGrantInput,
|
|
420
|
+
): Promise<RecurringGrantResult> {
|
|
421
|
+
const res = await this.transport.request<
|
|
422
|
+
RecurringGrantResult & { updated: true }
|
|
423
|
+
>({
|
|
424
|
+
method: "PUT",
|
|
425
|
+
path: `/api/v1/customers/ext/${encodeURIComponent(externalId)}/recurring-grant`,
|
|
317
426
|
body: input,
|
|
318
427
|
});
|
|
319
|
-
return
|
|
428
|
+
return toRecurringGrantResult(res);
|
|
320
429
|
}
|
|
321
430
|
}
|
|
431
|
+
|
|
432
|
+
/** Drop the response's `updated: true` marker, keeping `balanceUsd` only when
|
|
433
|
+
* the server sent it (wallet grants). */
|
|
434
|
+
function toRecurringGrantResult(res: RecurringGrantResult): RecurringGrantResult {
|
|
435
|
+
return {
|
|
436
|
+
kind: res.kind,
|
|
437
|
+
quantity: res.quantity,
|
|
438
|
+
...(res.balanceUsd !== undefined ? { balanceUsd: res.balanceUsd } : {}),
|
|
439
|
+
};
|
|
440
|
+
}
|
|
@@ -39,7 +39,7 @@ export class Invoices {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Mint a hosted pay link for an OPEN invoice. PAID/VOID invoices are rejected
|
|
42
|
+
* Mint a hosted pay link for an OPEN invoice. PAID/VOID/AUTO_CLOSED invoices are rejected
|
|
43
43
|
* with a `ConflictError`. `GET /api/v1/invoices/:id/pay-link`.
|
|
44
44
|
*/
|
|
45
45
|
payLink(id: string): Promise<PayLink> {
|
package/src/resources/plans.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { activeQuery, filterByActive } from "../filters.js";
|
|
2
2
|
import type { Transport } from "../http.js";
|
|
3
|
-
import type {
|
|
4
|
-
CreatePlanInput,
|
|
5
|
-
Plan,
|
|
6
|
-
PlanDetail,
|
|
7
|
-
UpdatePlanInput,
|
|
8
|
-
} from "../types.js";
|
|
3
|
+
import type { Plan } from "../types.js";
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
|
-
* The `plans` resource —
|
|
12
|
-
*
|
|
13
|
-
*
|
|
6
|
+
* The `plans` resource — read the billing plans customers can subscribe to.
|
|
7
|
+
* Each plan is a set of entitlement components (wallet / credit / outcome /
|
|
8
|
+
* unit / flat) billed on a cycle. `/api/v1/plans`.
|
|
14
9
|
*/
|
|
15
10
|
export class Plans {
|
|
16
11
|
constructor(private readonly transport: Transport) {}
|
|
@@ -26,51 +21,4 @@ export class Plans {
|
|
|
26
21
|
});
|
|
27
22
|
return filterByActive(res.plans, params.active);
|
|
28
23
|
}
|
|
29
|
-
|
|
30
|
-
/** Create a plan. `POST /api/v1/plans`. */
|
|
31
|
-
async create(input: CreatePlanInput): Promise<Plan> {
|
|
32
|
-
const res = await this.transport.request<{ plan: Plan }>({
|
|
33
|
-
method: "POST",
|
|
34
|
-
path: "/api/v1/plans",
|
|
35
|
-
body: input,
|
|
36
|
-
});
|
|
37
|
-
return res.plan;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Fetch one plan with aggregate subscriber/invoice stats. `GET /api/v1/plans/:id`. */
|
|
41
|
-
async get(id: string): Promise<PlanDetail> {
|
|
42
|
-
const res = await this.transport.request<{ plan: PlanDetail }>({
|
|
43
|
-
method: "GET",
|
|
44
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
45
|
-
});
|
|
46
|
-
return res.plan;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Replace a plan's definition (components + settings). `PATCH /api/v1/plans/:id`. */
|
|
50
|
-
async update(id: string, input: UpdatePlanInput): Promise<Plan> {
|
|
51
|
-
const res = await this.transport.request<{ plan: Plan }>({
|
|
52
|
-
method: "PATCH",
|
|
53
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
54
|
-
body: input,
|
|
55
|
-
});
|
|
56
|
-
return res.plan;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Activate or deactivate a plan without rewriting it. */
|
|
60
|
-
async setActive(id: string, isActive: boolean): Promise<Plan> {
|
|
61
|
-
const res = await this.transport.request<{ plan: Plan }>({
|
|
62
|
-
method: "PATCH",
|
|
63
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
64
|
-
body: { isActive },
|
|
65
|
-
});
|
|
66
|
-
return res.plan;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Delete a plan. Refused once any customer has purchased it. */
|
|
70
|
-
async delete(id: string): Promise<void> {
|
|
71
|
-
await this.transport.request({
|
|
72
|
-
method: "DELETE",
|
|
73
|
-
path: `/api/v1/plans/${encodeURIComponent(id)}`,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
24
|
}
|
package/src/resources/signals.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Transport } from "../http.js";
|
|
2
2
|
import type { Flusher } from "../flusher.js";
|
|
3
|
+
import { customerRefToWire } from "../customer-ref.js";
|
|
3
4
|
import { newKey } from "../idempotency.js";
|
|
4
5
|
import type {
|
|
5
6
|
CompositeCompletionInput,
|
|
@@ -15,8 +16,6 @@ import type {
|
|
|
15
16
|
TrackResult,
|
|
16
17
|
UnitInput,
|
|
17
18
|
UnitTrackResult,
|
|
18
|
-
UnitUsageList,
|
|
19
|
-
UsageList,
|
|
20
19
|
UsageLogListParams,
|
|
21
20
|
UsageLogPage,
|
|
22
21
|
WalletInput,
|
|
@@ -68,7 +67,7 @@ const USAGE_LOG_PATH = "/api/v1/signal/usage-log";
|
|
|
68
67
|
export function signalToWire(signal: Signal): Record<string, unknown> {
|
|
69
68
|
const t = signal.tokens;
|
|
70
69
|
const body: Record<string, unknown> = {
|
|
71
|
-
|
|
70
|
+
...customerRefToWire(signal),
|
|
72
71
|
// `usage` is required on all three model-priced kinds. input/output are
|
|
73
72
|
// always sent; `cacheTokens` only when provided (the server defaults 0).
|
|
74
73
|
usage: {
|
|
@@ -282,9 +281,8 @@ export class Signals {
|
|
|
282
281
|
path: OUTCOME_COMPLETE_PATH,
|
|
283
282
|
idempotencyKey,
|
|
284
283
|
body: {
|
|
285
|
-
|
|
284
|
+
...customerRefToWire(input),
|
|
286
285
|
runId: input.runId,
|
|
287
|
-
complete: true,
|
|
288
286
|
...(input.member ? { member: input.member } : {}),
|
|
289
287
|
idempotencyKey,
|
|
290
288
|
},
|
|
@@ -300,27 +298,6 @@ export class Signals {
|
|
|
300
298
|
};
|
|
301
299
|
}
|
|
302
300
|
|
|
303
|
-
/**
|
|
304
|
-
* Recent usage logs + totals for a customer. `GET /api/v1/usage`.
|
|
305
|
-
*
|
|
306
|
-
* Still the legacy path, deliberately. The `/api/v1/signal/*` family is
|
|
307
|
-
* POST-only — it replaced how usage is INGESTED, not how it is read — so
|
|
308
|
-
* `GET /api/v1/usage` has no successor and is not deprecated. It is also the
|
|
309
|
-
* only way to prove a signal landed, which matters more now that ingestion
|
|
310
|
-
* answers `202` for everything.
|
|
311
|
-
*/
|
|
312
|
-
async list(params: {
|
|
313
|
-
customerId: string;
|
|
314
|
-
limit?: number;
|
|
315
|
-
}): Promise<UsageList> {
|
|
316
|
-
const res = await this.transport.request<UsageList>({
|
|
317
|
-
method: "GET",
|
|
318
|
-
path: "/api/v1/usage",
|
|
319
|
-
query: { customerId: params.customerId, limit: params.limit },
|
|
320
|
-
});
|
|
321
|
-
return { customer: res.customer, totals: res.totals, logs: res.logs };
|
|
322
|
-
}
|
|
323
|
-
|
|
324
301
|
/**
|
|
325
302
|
* Record one unit-metered event (a fixed-price meter with no tokens),
|
|
326
303
|
* addressed to a catalog unit by its `agentKey`. Sent immediately — unit
|
|
@@ -342,7 +319,7 @@ export class Signals {
|
|
|
342
319
|
path: UNIT_PATH,
|
|
343
320
|
idempotencyKey,
|
|
344
321
|
body: {
|
|
345
|
-
|
|
322
|
+
...customerRefToWire(input),
|
|
346
323
|
agentKey: input.agentKey,
|
|
347
324
|
...(input.quantity != null ? { quantity: input.quantity } : {}),
|
|
348
325
|
...(input.member ? { member: input.member } : {}),
|
|
@@ -410,7 +387,7 @@ export class Signals {
|
|
|
410
387
|
path: COMPOSITE_COMPLETE_PATH,
|
|
411
388
|
idempotencyKey,
|
|
412
389
|
body: {
|
|
413
|
-
|
|
390
|
+
...customerRefToWire(input),
|
|
414
391
|
composite: { [input.composite.ref]: input.composite.value },
|
|
415
392
|
// Auto-assigned like the others. A retry here could not double-BILL
|
|
416
393
|
// even without it — closing a closed occurrence is a server-side
|
|
@@ -432,23 +409,6 @@ export class Signals {
|
|
|
432
409
|
};
|
|
433
410
|
}
|
|
434
411
|
|
|
435
|
-
/**
|
|
436
|
-
* A customer's unit balances + recent unit events. `GET /api/v1/units`.
|
|
437
|
-
*
|
|
438
|
-
* Legacy path for the same reason as {@link list}: the signal family is
|
|
439
|
-
* POST-only, so the read side has no successor and is not deprecated.
|
|
440
|
-
*/
|
|
441
|
-
unitUsage(params: {
|
|
442
|
-
customerId: string;
|
|
443
|
-
limit?: number;
|
|
444
|
-
}): Promise<UnitUsageList> {
|
|
445
|
-
return this.transport.request<UnitUsageList>({
|
|
446
|
-
method: "GET",
|
|
447
|
-
path: "/api/v1/units",
|
|
448
|
-
query: { customerId: params.customerId, limit: params.limit },
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
|
|
452
412
|
/**
|
|
453
413
|
* One customer's usage history, merged from every meter kind — credit,
|
|
454
414
|
* outcome, unit, wallet, and completed composite occurrences — into one
|