@clocknext/sdk 0.18.0 → 0.19.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 +39 -1
- package/dist/index.cjs +45 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -12
- package/dist/index.d.ts +118 -12
- package/dist/index.js +45 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/resources/customers.ts +54 -0
- package/src/resources/signals.ts +3 -0
- package/src/types.ts +105 -11
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -23,6 +23,9 @@ import type {
|
|
|
23
23
|
UnitBalance,
|
|
24
24
|
UpdateMemberInput,
|
|
25
25
|
WalletAdjustInput,
|
|
26
|
+
WalletLedgerPage,
|
|
27
|
+
WalletLedgerParams,
|
|
28
|
+
WalletTransaction,
|
|
26
29
|
} from "../types.js";
|
|
27
30
|
|
|
28
31
|
/**
|
|
@@ -147,6 +150,57 @@ export class Customers {
|
|
|
147
150
|
});
|
|
148
151
|
}
|
|
149
152
|
|
|
153
|
+
/**
|
|
154
|
+
* One page of the customer's wallet ledger — every movement of wallet
|
|
155
|
+
* money, newest first — plus both wallet balances. Cursor-paginated: pass
|
|
156
|
+
* back `nextCursor` as `cursor`. `GET /api/v1/customers/:id/wallet`.
|
|
157
|
+
*/
|
|
158
|
+
wallet(id: string, params: WalletLedgerParams = {}): Promise<WalletLedgerPage> {
|
|
159
|
+
return this.walletPage(`/api/v1/customers/${encodeURIComponent(id)}/wallet`, params);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** {@link wallet}, addressing the customer by its `externalId`.
|
|
163
|
+
* `GET /api/v1/customers/ext/:externalId/wallet`. */
|
|
164
|
+
walletByExternalId(
|
|
165
|
+
externalId: string,
|
|
166
|
+
params: WalletLedgerParams = {},
|
|
167
|
+
): Promise<WalletLedgerPage> {
|
|
168
|
+
return this.walletPage(
|
|
169
|
+
`/api/v1/customers/ext/${encodeURIComponent(externalId)}/wallet`,
|
|
170
|
+
params,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Async iterator over the customer's WHOLE wallet ledger, newest first,
|
|
176
|
+
* following the cursor. `params.cursor` is ignored.
|
|
177
|
+
* `for await (const t of cnk.customers.iterateWallet(id)) { … }`
|
|
178
|
+
*/
|
|
179
|
+
async *iterateWallet(
|
|
180
|
+
id: string,
|
|
181
|
+
params: Omit<WalletLedgerParams, "cursor"> = {},
|
|
182
|
+
): AsyncGenerator<WalletTransaction> {
|
|
183
|
+
let cursor: string | undefined;
|
|
184
|
+
do {
|
|
185
|
+
const page = await this.wallet(id, { ...params, cursor });
|
|
186
|
+
for (const t of page.transactions) yield t;
|
|
187
|
+
cursor = page.nextCursor ?? undefined;
|
|
188
|
+
} while (cursor);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private walletPage(path: string, params: WalletLedgerParams): Promise<WalletLedgerPage> {
|
|
192
|
+
return this.transport.request<WalletLedgerPage>({
|
|
193
|
+
method: "GET",
|
|
194
|
+
path,
|
|
195
|
+
query: {
|
|
196
|
+
limit: params.limit,
|
|
197
|
+
cursor: params.cursor,
|
|
198
|
+
from: params.from,
|
|
199
|
+
to: params.to,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
150
204
|
/** {@link balances}, addressing the customer by its `externalId`.
|
|
151
205
|
* `GET /api/v1/customers/ext/:externalId/balances`. */
|
|
152
206
|
balancesByExternalId(externalId: string): Promise<CustomerBalances> {
|
package/src/resources/signals.ts
CHANGED
|
@@ -286,6 +286,7 @@ export class Signals {
|
|
|
286
286
|
...customerRefToWire(input),
|
|
287
287
|
runId: input.runId,
|
|
288
288
|
...(input.member ? { member: input.member } : {}),
|
|
289
|
+
...(input.custom ? { custom: input.custom } : {}),
|
|
289
290
|
idempotencyKey,
|
|
290
291
|
},
|
|
291
292
|
retry: true,
|
|
@@ -328,6 +329,7 @@ export class Signals {
|
|
|
328
329
|
...(input.composite
|
|
329
330
|
? { composite: { [input.composite.ref]: input.composite.value } }
|
|
330
331
|
: {}),
|
|
332
|
+
...(input.custom ? { custom: input.custom } : {}),
|
|
331
333
|
// Assigned HERE, before the send, so the SAME key rides every
|
|
332
334
|
// transport-level retry below. Without it a single 500 followed by a
|
|
333
335
|
// success is TWO un-keyed reports, and the server dedups on the key —
|
|
@@ -391,6 +393,7 @@ export class Signals {
|
|
|
391
393
|
body: {
|
|
392
394
|
...customerRefToWire(input),
|
|
393
395
|
composite: { [input.composite.ref]: input.composite.value },
|
|
396
|
+
...(input.custom ? { custom: input.custom } : {}),
|
|
394
397
|
// Auto-assigned like the others. A retry here could not double-BILL
|
|
395
398
|
// even without it — closing a closed occurrence is a server-side
|
|
396
399
|
// no-op — but that safety comes from occurrence-level dedup, not from
|
package/src/types.ts
CHANGED
|
@@ -189,6 +189,8 @@ export type OutcomeCompletionInput = CustomerRef & {
|
|
|
189
189
|
runId: string;
|
|
190
190
|
/** Optional member (email) this completion is attributed to. */
|
|
191
191
|
member?: string;
|
|
192
|
+
/** Free-form metadata, stored as-is with this completion. Never priced. */
|
|
193
|
+
custom?: Record<string, unknown>;
|
|
192
194
|
/** Idempotency key, auto-generated if omitted. Sending this completion twice
|
|
193
195
|
* for the same run is already a safe no-op server-side, so this only
|
|
194
196
|
* collapses a retry into one attempt rather than protecting against a
|
|
@@ -429,8 +431,9 @@ export interface UsageLogOutcomeAttribution {
|
|
|
429
431
|
export interface UsageLogEntry {
|
|
430
432
|
id: string;
|
|
431
433
|
createdAt: string;
|
|
432
|
-
/** Which meter this row is.
|
|
433
|
-
|
|
434
|
+
/** Which meter this row is. `"outcome"` is one step of a run;
|
|
435
|
+
* `"outcome_completion"` is the finished run itself (one per run). */
|
|
436
|
+
type: "credit" | "outcome" | "outcome_completion" | "unit" | "wallet" | "composite";
|
|
434
437
|
status: SignalStatus;
|
|
435
438
|
typeName: string | null;
|
|
436
439
|
member: string | null;
|
|
@@ -455,8 +458,22 @@ export interface UsageLogEntry {
|
|
|
455
458
|
/** Populated only when `type === "composite"`. `amount` is a formatted USD
|
|
456
459
|
* price — the composite's flat price, read live, not stored per row. */
|
|
457
460
|
composite: { amount: string } | null;
|
|
458
|
-
/**
|
|
459
|
-
*
|
|
461
|
+
/** Populated only when `type === "outcome_completion"`. `amount` is the
|
|
462
|
+
* price frozen when the run completed (your plan price, else the catalogue
|
|
463
|
+
* price). */
|
|
464
|
+
outcomeCompletion: {
|
|
465
|
+
runId: string | null;
|
|
466
|
+
amount: string;
|
|
467
|
+
runSignals: number;
|
|
468
|
+
} | null;
|
|
469
|
+
/** The composite that covers this row's billing, by name — the row's price
|
|
470
|
+
* is then included in that composite's own charge, not billed on top. Set
|
|
471
|
+
* on credit / outcome / unit / outcome_completion rows tagged into a
|
|
472
|
+
* composite on the customer's plan; `null` otherwise. */
|
|
473
|
+
coveredByComposite: string | null;
|
|
474
|
+
/** The `custom` object sent, as sent — on the signal itself, or on the
|
|
475
|
+
* `completeComposite()` / `completeOutcome()` call that closed a composite /
|
|
476
|
+
* outcome_completion row. `null` when none was sent. */
|
|
460
477
|
custom: Record<string, unknown> | null;
|
|
461
478
|
}
|
|
462
479
|
|
|
@@ -491,8 +508,6 @@ export interface ApiCustomer {
|
|
|
491
508
|
taxId: string | null;
|
|
492
509
|
currencyCode: string;
|
|
493
510
|
creditAllowance: number;
|
|
494
|
-
recurringTransactionEmail: boolean;
|
|
495
|
-
autoRecurring: boolean;
|
|
496
511
|
createdAt: string;
|
|
497
512
|
updatedAt: string;
|
|
498
513
|
}
|
|
@@ -523,10 +538,6 @@ export interface CustomerProfileInput {
|
|
|
523
538
|
taxId?: string | null;
|
|
524
539
|
/** ISO 4217 (3 letters); must be enabled for the org. */
|
|
525
540
|
currencyCode?: string;
|
|
526
|
-
/** Send the invoice, payment receipt and card-payment-failed emails for recurring invoices. Defaults to `true` on create. */
|
|
527
|
-
recurringTransactionEmail?: boolean;
|
|
528
|
-
/** Issue every recurring invoice as `AUTO_CLOSED` (applied as if paid, never payable). Defaults to `false` on create. */
|
|
529
|
-
autoRecurring?: boolean;
|
|
530
541
|
}
|
|
531
542
|
|
|
532
543
|
/** `name` and `email` are required on create; every other field is optional. */
|
|
@@ -619,6 +630,83 @@ export interface CustomerBalances {
|
|
|
619
630
|
composites: CompositeBalance[];
|
|
620
631
|
}
|
|
621
632
|
|
|
633
|
+
/** What caused a wallet ledger row (`WalletTransaction.source`). */
|
|
634
|
+
export type WalletTransactionSource =
|
|
635
|
+
/** Wallet money from a new plan purchase. */
|
|
636
|
+
| "SUBSCRIPTION"
|
|
637
|
+
/** Wallet money from a plan renewal, or unused money removed at renewal. */
|
|
638
|
+
| "RENEWAL"
|
|
639
|
+
/** Changed in the ClockNext dashboard. */
|
|
640
|
+
| "MANUAL"
|
|
641
|
+
/** Changed with `customers.adjustWallet()`. */
|
|
642
|
+
| "API"
|
|
643
|
+
/** Top-up paid by the customer in the customer portal. */
|
|
644
|
+
| "CUSTOMER_PORTAL"
|
|
645
|
+
/** Charged by a signal; `usageLogId` links the signal. */
|
|
646
|
+
| "USAGE_LOG"
|
|
647
|
+
/** Usage cleared by a paid pay-as-you-go invoice. */
|
|
648
|
+
| "INVOICE_SETTLEMENT"
|
|
649
|
+
/** Settlement undone by a voided invoice. */
|
|
650
|
+
| "INVOICE_VOID";
|
|
651
|
+
|
|
652
|
+
/** One row of a customer's wallet ledger (`customers.wallet()`). */
|
|
653
|
+
export interface WalletTransaction {
|
|
654
|
+
id: string;
|
|
655
|
+
/** ISO 8601. */
|
|
656
|
+
createdAt: string;
|
|
657
|
+
/** `CREDIT` adds money, `DEBIT` takes it out. */
|
|
658
|
+
type: "CREDIT" | "DEBIT";
|
|
659
|
+
/** Which balance moved: the ordinary wallet or the Reserved Wallet. */
|
|
660
|
+
pool: "main" | "reserved";
|
|
661
|
+
source: WalletTransactionSource;
|
|
662
|
+
/** Always positive — `type` gives the direction. In `currencyCode`. */
|
|
663
|
+
amount: number;
|
|
664
|
+
/** The same amount in USD. */
|
|
665
|
+
amountUsd: number;
|
|
666
|
+
currencyCode: string;
|
|
667
|
+
/** 1 USD = this many units of `currencyCode`, at write time. */
|
|
668
|
+
currencyRateUsd: number;
|
|
669
|
+
/** Only text a person wrote: your own note on an `API` row, the admin's
|
|
670
|
+
* note on a `MANUAL` row. `null` on every row the system writes itself —
|
|
671
|
+
* `source` says what those are. */
|
|
672
|
+
notes: string | null;
|
|
673
|
+
/** On a usage charge for an entitlement: which kind. `null` otherwise. */
|
|
674
|
+
entitlementType: "CREDIT" | "OUTCOME" | "UNIT" | "COMPOSITE" | null;
|
|
675
|
+
/** Id of that credit / outcome / unit / composite. */
|
|
676
|
+
entitlementId: string | null;
|
|
677
|
+
/** Its name when the row was written. */
|
|
678
|
+
entitlementName: string | null;
|
|
679
|
+
/** On a `USAGE_LOG` row: the id of the matching row in
|
|
680
|
+
* `signals.usageLog()`. */
|
|
681
|
+
usageLogId: string | null;
|
|
682
|
+
/** On a `SUBSCRIPTION` / `RENEWAL` grant: the purchase it came from. */
|
|
683
|
+
purchaseId: string | null;
|
|
684
|
+
purchaseNumber: string | null;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** One page of a customer's wallet ledger, newest first. */
|
|
688
|
+
export interface WalletLedgerPage {
|
|
689
|
+
/** Ordinary wallet balance, USD. May be negative. */
|
|
690
|
+
balanceUsd: number;
|
|
691
|
+
/** Reserved Wallet balance, USD; `null` when the workspace hasn't enabled
|
|
692
|
+
* it. */
|
|
693
|
+
reservedBalanceUsd: number | null;
|
|
694
|
+
transactions: WalletTransaction[];
|
|
695
|
+
/** Pass back as `cursor` for the next page; `null` on the last page. */
|
|
696
|
+
nextCursor: string | null;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export interface WalletLedgerParams {
|
|
700
|
+
/** Default 50, max 200. */
|
|
701
|
+
limit?: number;
|
|
702
|
+
/** A previous page's `nextCursor`. Omit for the first page. */
|
|
703
|
+
cursor?: string;
|
|
704
|
+
/** First day to include, `YYYY-MM-DD` (UTC). The whole day is included. */
|
|
705
|
+
from?: string;
|
|
706
|
+
/** Last day to include, `YYYY-MM-DD` (UTC). The whole day is included. */
|
|
707
|
+
to?: string;
|
|
708
|
+
}
|
|
709
|
+
|
|
622
710
|
/** The customer's active plan (the `plan` field of `customers.plan()`);
|
|
623
711
|
* `null` when the customer is unsubscribed. */
|
|
624
712
|
export interface CustomerPlanDetails {
|
|
@@ -1120,7 +1208,8 @@ export interface PurchaseDetail {
|
|
|
1120
1208
|
// Invoices & Payments
|
|
1121
1209
|
// ---------------------------------------------------------------------------
|
|
1122
1210
|
|
|
1123
|
-
/** `AUTO_CLOSED` — a recurring invoice
|
|
1211
|
+
/** `AUTO_CLOSED` — a recurring invoice of an organisation with "Auto close
|
|
1212
|
+
* invoices on recurring" on (dashboard: Settings → Organisation → Billing):
|
|
1124
1213
|
* applied as if paid, but never payable. */
|
|
1125
1214
|
export type InvoiceStatus = "OPEN" | "PAID" | "VOID" | "AUTO_CLOSED";
|
|
1126
1215
|
|
|
@@ -1529,6 +1618,8 @@ export type UnitInput = CustomerRef & {
|
|
|
1529
1618
|
quantity?: number;
|
|
1530
1619
|
/** Optional composite this unit report belongs to. See {@link CompositeTag}. */
|
|
1531
1620
|
composite?: CompositeTag;
|
|
1621
|
+
/** Free-form metadata, stored as-is with this unit report. Never priced. */
|
|
1622
|
+
custom?: Record<string, unknown>;
|
|
1532
1623
|
/**
|
|
1533
1624
|
* Idempotency key for safe retries — a repeat carrying the same key returns
|
|
1534
1625
|
* the original result instead of drawing the balance down twice.
|
|
@@ -1580,6 +1671,9 @@ export type CompositeCompletionInput = CustomerRef & {
|
|
|
1580
1671
|
/** Which occurrence to close: the composite's `refId` and the correlation
|
|
1581
1672
|
* value the signals were tagged with. */
|
|
1582
1673
|
composite: CompositeTag;
|
|
1674
|
+
/** Free-form metadata, stored as-is on the occurrence this call closes.
|
|
1675
|
+
* Never priced. */
|
|
1676
|
+
custom?: Record<string, unknown>;
|
|
1583
1677
|
/** Idempotency key, auto-generated if omitted. Closing twice is already a
|
|
1584
1678
|
* safe no-op, so this only collapses retries into one recorded attempt
|
|
1585
1679
|
* rather than protecting against a double charge. */
|