@clocknext/sdk 0.6.0 → 0.8.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/dist/index.d.cts CHANGED
@@ -18,6 +18,21 @@ interface Tokens {
18
18
  output: number;
19
19
  cache?: number;
20
20
  }
21
+ /**
22
+ * Tags a signal with a pricing metric for reporting. `ref` is the metric's
23
+ * `refId` (defined in Settings → Pricing metrics) and `value` is your own
24
+ * correlation id — a session, a call, a tenant — which the metric rolls up one
25
+ * row per distinct value. Reporting only: a metric never affects billing, a bad
26
+ * tag never fails the signal, and a `ref` naming no live metric is simply
27
+ * ignored. Applies to credit and outcome signals (ignored on wallet).
28
+ */
29
+ interface MetricTag {
30
+ /** The metric's `refId`. Case-insensitive; must not collide with a reserved
31
+ * ingest field (e.g. `model`, `member`, `agentKey`, `runId`, `custom`). */
32
+ ref: string;
33
+ /** Your correlation value for this metric, stored verbatim. */
34
+ value: string | number;
35
+ }
21
36
  /** The organisation + key behind a request — `cnk.workspace.me()`. */
22
37
  interface WorkspaceIdentity {
23
38
  organization: {
@@ -75,16 +90,36 @@ interface CreditSignal extends SignalBase {
75
90
  type: "credit";
76
91
  /** The Credit's stable agent key (assigned when the credit was created). */
77
92
  agentKey: string;
93
+ /** Optional pricing-metric tag for reporting. */
94
+ metric?: MetricTag;
78
95
  }
79
96
  /** Debits the customer's wallet in USD at the model's cost. */
80
97
  interface WalletSignal extends SignalBase {
81
98
  type: "wallet";
82
99
  }
83
- /** Advances one step of a multi-call outcome workflow, by the step's `agentKey`. */
100
+ /**
101
+ * Records one step of a multi-call outcome run. The `agentKey` identifies the
102
+ * step (and the outcome); `runId` groups every signal of a single run, so a step
103
+ * may repeat freely. The run bills once, when the caller marks it `complete`.
104
+ */
84
105
  interface OutcomeSignal extends SignalBase {
85
106
  type: "outcome";
86
107
  /** The OutcomeStep's stable agent key — identifies the outcome AND the step. */
87
108
  agentKey: string;
109
+ /**
110
+ * Correlates every signal of one workflow run. Required. A step may fire more
111
+ * than once within a run (a "verify" loop firing 3× is three signals, one
112
+ * outcome). Opaque to ClockNext — any string you can correlate; unique per org.
113
+ */
114
+ runId: string;
115
+ /**
116
+ * Set `true` on the LAST step signal to declare the run finished — completion
117
+ * is never inferred from step coverage. Sending it twice is a safe no-op and
118
+ * can't bill again.
119
+ */
120
+ complete?: boolean;
121
+ /** Optional pricing-metric tag for reporting. */
122
+ metric?: MetricTag;
88
123
  }
89
124
  type Signal = CreditSignal | WalletSignal | OutcomeSignal;
90
125
  /** Helper input shapes for the per-type convenience methods. */
@@ -98,9 +133,21 @@ interface SerializedRuleApplication {
98
133
  }
99
134
  interface SerializedOutcomeAttribution {
100
135
  name: string;
136
+ /** The step of the outcome this signal performed. */
101
137
  step: string;
138
+ /** The caller's run id — every signal of one run shares it. `null` on logs
139
+ * recorded before the run-based flow. */
140
+ runId: string | null;
141
+ /** True when this signal ended the run (`complete: true`). */
142
+ closedRun: boolean;
143
+ /** True once the run's completion was counted against the allowance. Diverges
144
+ * from `closedRun` only when a run closes with no allowance left — it waits,
145
+ * then flips true once a top-up settles it. */
102
146
  completed: boolean;
103
- progressSteps: string[];
147
+ /** How many signals the run holds after this one. */
148
+ signalCount: number;
149
+ /** The outcome's catalogue step count — not a progress target, since steps
150
+ * may repeat within a run. */
104
151
  totalSteps: number;
105
152
  }
106
153
  /** The customer's remaining balance for the dimension a signal metered, AFTER
@@ -138,12 +185,38 @@ interface SerializedUsageLog {
138
185
  balance: UsageBalance | null;
139
186
  createdAt: string;
140
187
  }
141
- /** Result of a single signal send (sync mode, or `{ wait: true }`). */
188
+ /**
189
+ * Result of a single signal send (sync mode, or `{ wait: true }`).
190
+ *
191
+ * `queued: true` has TWO causes, and they are not the same thing:
192
+ * 1. **Client-side buffering** (async mode, no `wait`) — the signal is in this
193
+ * process's buffer and has not been sent. No `messageId`.
194
+ * 2. **Server-side durable hand-off** — the request WAS sent and the server
195
+ * answered `202 Accepted`, having enqueued it for a worker to price. Carries
196
+ * a `messageId`. `usageLog` is null: the log does not exist yet.
197
+ *
198
+ * In case 2 the signal is accepted but **not yet billed**, and it has only been
199
+ * shallowly validated. A bad `agentKey`, a customer with no matching plan, or an
200
+ * exhausted allowance is detected by the worker LATER and never surfaces here —
201
+ * the signal is simply dropped. A `202` therefore means "accepted", never
202
+ * "recorded". To confirm a signal actually landed, read it back with
203
+ * `signals.list({ customerId })`.
204
+ *
205
+ * When the server has no queue configured it prices inline instead and returns
206
+ * `queued: false` with a populated `usageLog`, validating synchronously.
207
+ */
142
208
  interface TrackResult {
143
- /** True when the signal was buffered (async mode) and not yet sent. */
209
+ /** True when the signal has not been priced yet — either buffered locally
210
+ * (async mode) or accepted for asynchronous processing by the server. */
144
211
  queued: boolean;
145
- /** The computed usage log — present only once the signal has been sent. */
212
+ /** The computed usage log. Non-null ONLY when the server priced the signal
213
+ * inline (`queued: false`); null on a `202` hand-off and absent while the
214
+ * signal sits in the client-side buffer. */
146
215
  usageLog?: SerializedUsageLog | null;
216
+ /** The server's durable-queue message id, present only on a `202` hand-off
217
+ * (server-side queueing). Absent for client-side buffering and for inline
218
+ * pricing. */
219
+ messageId?: string;
147
220
  }
148
221
  interface UsageList {
149
222
  customer: {
@@ -232,7 +305,9 @@ interface OutcomeBalance {
232
305
  granted: number;
233
306
  remaining: number;
234
307
  /** Each step's `agentKey` is what `signals.outcome()` and the outcome adjust
235
- * API use to address this outcome (outcomes have no key of their own). */
308
+ * API use to address this outcome at runtime. The outcome also has its own
309
+ * separate key ({@link Outcome.agentKey}), but neither of those APIs accepts
310
+ * it — it identifies the outcome in the catalogue, not in a signal. */
236
311
  steps: {
237
312
  id: string;
238
313
  name: string;
@@ -687,10 +762,12 @@ interface CreditAdjustInput {
687
762
  notes?: string;
688
763
  }
689
764
  /** Grant/claw an outcome balance. `delta` is a non-zero whole number; floored at
690
- * 0. The outcome is addressed by a STEP's `agentKey` (outcomes have no key of
691
- * their own). */
765
+ * 0. The outcome is addressed here by a STEP's `agentKey`, which resolves to its
766
+ * parent outcome — NOT by the outcome's own `agentKey` ({@link Outcome.agentKey}),
767
+ * which this endpoint does not accept. */
692
768
  interface OutcomeAdjustInput {
693
- /** An outcome step's stable agent key — identifies the parent outcome. */
769
+ /** An outcome STEP's stable agent key — identifies the parent outcome. Passing
770
+ * the outcome's own `agentKey` here fails with `422`. */
694
771
  agentKey: string;
695
772
  delta: number;
696
773
  notes?: string;
@@ -799,6 +876,17 @@ interface OutcomeStepInput {
799
876
  interface Outcome {
800
877
  id: string;
801
878
  name: string;
879
+ /**
880
+ * The OUTCOME's own stable agent key — its durable identity, mirroring
881
+ * {@link Credit.agentKey}. Lowercased `[a-z0-9._-]`, max 80 chars, unique per
882
+ * organisation. A rename never changes it.
883
+ *
884
+ * Distinct from each step's `agentKey` in `steps`, and in a SEPARATE
885
+ * namespace: usage is always reported against a STEP's key
886
+ * (`signals.outcome({ agentKey })`), never this one. This key identifies the
887
+ * outcome itself when creating or updating it.
888
+ */
889
+ agentKey: string;
802
890
  description: string | null;
803
891
  isActive: boolean;
804
892
  marginPercent: number;
@@ -827,6 +915,15 @@ interface OutcomeDetail extends Outcome {
827
915
  }
828
916
  interface CreateOutcomeInput {
829
917
  name: string;
918
+ /**
919
+ * The OUTCOME's own stable agent key — REQUIRED. Lowercased `[a-z0-9._-]`,
920
+ * max 80 chars, unique per organisation (the server lowercases and trims it).
921
+ *
922
+ * Separate namespace from `steps[].agentKey`: this names the outcome, a step
923
+ * key names a step and is what `signals.outcome()` reports against. Omitting
924
+ * it is rejected with a `ValidationError` (400).
925
+ */
926
+ agentKey: string;
830
927
  basePrice: number;
831
928
  marginPercent: number;
832
929
  pricePerOutcome: number;
@@ -1233,8 +1330,14 @@ declare class Invoices {
1233
1330
 
1234
1331
  /**
1235
1332
  * The `outcomes` resource — manage the org's outcome *types* (the catalog). An
1236
- * outcome is a multi-step workflow; each step has a stable `agentKey` you pass
1237
- * to `signals.outcome()`. `/api/v1/outcomes`.
1333
+ * outcome is a multi-step workflow. `/api/v1/outcomes`.
1334
+ *
1335
+ * Two distinct kinds of agent key, in separate namespaces, each unique per
1336
+ * organisation — do not conflate them:
1337
+ * - the OUTCOME's own `agentKey`, REQUIRED on `create()` and `update()`, which
1338
+ * names the outcome itself in the catalogue;
1339
+ * - each STEP's `agentKey`, which is what you pass to `signals.outcome()` to
1340
+ * report usage and to the outcome-adjust API.
1238
1341
  */
1239
1342
  declare class Outcomes {
1240
1343
  private readonly transport;
@@ -1384,15 +1487,31 @@ declare function signalToWire(signal: Signal): Record<string, unknown>;
1384
1487
  /**
1385
1488
  * The `signals` resource: record usage signals and read them back.
1386
1489
  *
1387
- * In async mode (default), `track()` buffers the signal and returns immediately
1388
- * with `{ queued: true }`. Pass `{ wait: true }` (or construct the client in
1389
- * `sync` mode) to await the send and receive the computed `usageLog`.
1490
+ * In async mode (default), `track()` buffers the signal locally and returns
1491
+ * immediately with `{ queued: true }`. Pass `{ wait: true }` (or construct the
1492
+ * client in `sync` mode) to await the request.
1493
+ *
1494
+ * Awaiting the request does NOT guarantee a priced result. Where the server has
1495
+ * a durable queue configured it answers `202` and prices the signal in a worker,
1496
+ * so `track()` resolves `{ queued: true, messageId, usageLog: null }` — accepted,
1497
+ * not yet billed, and validated only later (a bad `agentKey` is dropped there,
1498
+ * silently). Only when the server prices inline do you get
1499
+ * `{ queued: false, usageLog }`. Branch on `queued`; never assume `usageLog`.
1500
+ * `verify()` is the way to validate and price a signal synchronously, and
1501
+ * `list()` is how you confirm one actually landed.
1390
1502
  */
1391
1503
  declare class Signals {
1392
1504
  private readonly transport;
1393
1505
  private readonly flusher;
1394
1506
  private readonly cfg;
1395
1507
  constructor(transport: Transport, flusher: Flusher, cfg: ResolvedConfig);
1508
+ /**
1509
+ * Record one usage signal. `POST /api/v1/usage`.
1510
+ *
1511
+ * Returns as soon as the signal is buffered (async mode) or the request has
1512
+ * been answered (`{ wait: true }` / sync mode). See {@link TrackResult}: a
1513
+ * resolved promise means "accepted", which is not the same as "billed".
1514
+ */
1396
1515
  track(signal: Signal, opts?: {
1397
1516
  wait?: boolean;
1398
1517
  }): Promise<TrackResult>;
@@ -1592,4 +1711,4 @@ declare class NetworkError extends ClockNextError {
1592
1711
  constructor(message: string);
1593
1712
  }
1594
1713
 
1595
- export { type AddMemberInput, AllowanceError, type ApiCustomer, AuthError, type BillingCycle, type BillingMode, ClockNext, type ClockNextConfig, ClockNextError, type ComponentType, ConflictError, type CostPoint, type CostStats, type CreateCreditInput, type CreateCustomerInput, type CreateOutcomeInput, type CreatePlanInput, type CreatePurchaseInput, type CreateUnitInput, type Credit, type CreditAdjustInput, type CreditAnalytics, type CreditBalance, type CreditComponentInput, type CreditDetail, type CreditInput, type CreditSignal, type CustomerBalances, type CustomerList, type CustomerPlan, type CustomerPlanDetails, type CustomerProfileInput, type DropReason, type FetchLike, type FlatComponentInput, type FlatUnitInput, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListRow, type InvoiceParty, type InvoicePlanSnapshot, type InvoiceStatus, type Logger, type Member, type MemberRole, type Model, type ModelBundleEntry, NetworkError, NotFoundError, type Outcome, type OutcomeAdjustInput, type OutcomeAnalytics, type OutcomeBalance, type OutcomeComponentInput, type OutcomeDetail, type OutcomeInput, type OutcomeSignal, type OutcomeStepInput, type PayLink, type PaymentDetail, type PaymentRow, type Plan, type PlanComponent, type PlanComponentInput, type PlanDetail, PlanError, type PlanKind, type PlanRef, type PlanType, type PortalToken, type PortalTokenInput, type Purchase, type PurchaseDetail, type PurchaseStatus, RateLimitError, type SerializedOutcomeAttribution, type SerializedRuleApplication, type SerializedUnitUsage, type SerializedUsageLog, ServerError, type Signal, type SignalStatus, type SignalType, type ThresholdKind, type TieredUnitInput, type Tokens, type TrackResult, type Unit, type UnitAdjustInput, type UnitBalance, type UnitComponentInput, type UnitCustomerRow, type UnitDetail, type UnitInput, type UnitPricingType, type UnitTier, type UnitTierInput, type UnitUsageList, type UnitUsageRow, type UpdateCreditInput, type UpdateMemberInput, type UpdateOutcomeInput, type UpdatePlanInput, type UpdateUnitInput, type UpsertWebhookInput, type UsageBalance, type UsageList, ValidationError, type WalletComponentInput, type WalletEntryInput, type WalletInput, type WalletList, type WalletSignal, type WalletTransaction, type WalletTransactionType, type Webhook, type WorkspaceIdentity, signalToWire };
1714
+ export { type AddMemberInput, AllowanceError, type ApiCustomer, AuthError, type BillingCycle, type BillingMode, ClockNext, type ClockNextConfig, ClockNextError, type ComponentType, ConflictError, type CostPoint, type CostStats, type CreateCreditInput, type CreateCustomerInput, type CreateOutcomeInput, type CreatePlanInput, type CreatePurchaseInput, type CreateUnitInput, type Credit, type CreditAdjustInput, type CreditAnalytics, type CreditBalance, type CreditComponentInput, type CreditDetail, type CreditInput, type CreditSignal, type CustomerBalances, type CustomerList, type CustomerPlan, type CustomerPlanDetails, type CustomerProfileInput, type DropReason, type FetchLike, type FlatComponentInput, type FlatUnitInput, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListRow, type InvoiceParty, type InvoicePlanSnapshot, type InvoiceStatus, type Logger, type Member, type MemberRole, type MetricTag, type Model, type ModelBundleEntry, NetworkError, NotFoundError, type Outcome, type OutcomeAdjustInput, type OutcomeAnalytics, type OutcomeBalance, type OutcomeComponentInput, type OutcomeDetail, type OutcomeInput, type OutcomeSignal, type OutcomeStepInput, type PayLink, type PaymentDetail, type PaymentRow, type Plan, type PlanComponent, type PlanComponentInput, type PlanDetail, PlanError, type PlanKind, type PlanRef, type PlanType, type PortalToken, type PortalTokenInput, type Purchase, type PurchaseDetail, type PurchaseStatus, RateLimitError, type SerializedOutcomeAttribution, type SerializedRuleApplication, type SerializedUnitUsage, type SerializedUsageLog, ServerError, type Signal, type SignalStatus, type SignalType, type ThresholdKind, type TieredUnitInput, type Tokens, type TrackResult, type Unit, type UnitAdjustInput, type UnitBalance, type UnitComponentInput, type UnitCustomerRow, type UnitDetail, type UnitInput, type UnitPricingType, type UnitTier, type UnitTierInput, type UnitUsageList, type UnitUsageRow, type UpdateCreditInput, type UpdateMemberInput, type UpdateOutcomeInput, type UpdatePlanInput, type UpdateUnitInput, type UpsertWebhookInput, type UsageBalance, type UsageList, ValidationError, type WalletComponentInput, type WalletEntryInput, type WalletInput, type WalletList, type WalletSignal, type WalletTransaction, type WalletTransactionType, type Webhook, type WorkspaceIdentity, signalToWire };
package/dist/index.d.ts CHANGED
@@ -18,6 +18,21 @@ interface Tokens {
18
18
  output: number;
19
19
  cache?: number;
20
20
  }
21
+ /**
22
+ * Tags a signal with a pricing metric for reporting. `ref` is the metric's
23
+ * `refId` (defined in Settings → Pricing metrics) and `value` is your own
24
+ * correlation id — a session, a call, a tenant — which the metric rolls up one
25
+ * row per distinct value. Reporting only: a metric never affects billing, a bad
26
+ * tag never fails the signal, and a `ref` naming no live metric is simply
27
+ * ignored. Applies to credit and outcome signals (ignored on wallet).
28
+ */
29
+ interface MetricTag {
30
+ /** The metric's `refId`. Case-insensitive; must not collide with a reserved
31
+ * ingest field (e.g. `model`, `member`, `agentKey`, `runId`, `custom`). */
32
+ ref: string;
33
+ /** Your correlation value for this metric, stored verbatim. */
34
+ value: string | number;
35
+ }
21
36
  /** The organisation + key behind a request — `cnk.workspace.me()`. */
22
37
  interface WorkspaceIdentity {
23
38
  organization: {
@@ -75,16 +90,36 @@ interface CreditSignal extends SignalBase {
75
90
  type: "credit";
76
91
  /** The Credit's stable agent key (assigned when the credit was created). */
77
92
  agentKey: string;
93
+ /** Optional pricing-metric tag for reporting. */
94
+ metric?: MetricTag;
78
95
  }
79
96
  /** Debits the customer's wallet in USD at the model's cost. */
80
97
  interface WalletSignal extends SignalBase {
81
98
  type: "wallet";
82
99
  }
83
- /** Advances one step of a multi-call outcome workflow, by the step's `agentKey`. */
100
+ /**
101
+ * Records one step of a multi-call outcome run. The `agentKey` identifies the
102
+ * step (and the outcome); `runId` groups every signal of a single run, so a step
103
+ * may repeat freely. The run bills once, when the caller marks it `complete`.
104
+ */
84
105
  interface OutcomeSignal extends SignalBase {
85
106
  type: "outcome";
86
107
  /** The OutcomeStep's stable agent key — identifies the outcome AND the step. */
87
108
  agentKey: string;
109
+ /**
110
+ * Correlates every signal of one workflow run. Required. A step may fire more
111
+ * than once within a run (a "verify" loop firing 3× is three signals, one
112
+ * outcome). Opaque to ClockNext — any string you can correlate; unique per org.
113
+ */
114
+ runId: string;
115
+ /**
116
+ * Set `true` on the LAST step signal to declare the run finished — completion
117
+ * is never inferred from step coverage. Sending it twice is a safe no-op and
118
+ * can't bill again.
119
+ */
120
+ complete?: boolean;
121
+ /** Optional pricing-metric tag for reporting. */
122
+ metric?: MetricTag;
88
123
  }
89
124
  type Signal = CreditSignal | WalletSignal | OutcomeSignal;
90
125
  /** Helper input shapes for the per-type convenience methods. */
@@ -98,9 +133,21 @@ interface SerializedRuleApplication {
98
133
  }
99
134
  interface SerializedOutcomeAttribution {
100
135
  name: string;
136
+ /** The step of the outcome this signal performed. */
101
137
  step: string;
138
+ /** The caller's run id — every signal of one run shares it. `null` on logs
139
+ * recorded before the run-based flow. */
140
+ runId: string | null;
141
+ /** True when this signal ended the run (`complete: true`). */
142
+ closedRun: boolean;
143
+ /** True once the run's completion was counted against the allowance. Diverges
144
+ * from `closedRun` only when a run closes with no allowance left — it waits,
145
+ * then flips true once a top-up settles it. */
102
146
  completed: boolean;
103
- progressSteps: string[];
147
+ /** How many signals the run holds after this one. */
148
+ signalCount: number;
149
+ /** The outcome's catalogue step count — not a progress target, since steps
150
+ * may repeat within a run. */
104
151
  totalSteps: number;
105
152
  }
106
153
  /** The customer's remaining balance for the dimension a signal metered, AFTER
@@ -138,12 +185,38 @@ interface SerializedUsageLog {
138
185
  balance: UsageBalance | null;
139
186
  createdAt: string;
140
187
  }
141
- /** Result of a single signal send (sync mode, or `{ wait: true }`). */
188
+ /**
189
+ * Result of a single signal send (sync mode, or `{ wait: true }`).
190
+ *
191
+ * `queued: true` has TWO causes, and they are not the same thing:
192
+ * 1. **Client-side buffering** (async mode, no `wait`) — the signal is in this
193
+ * process's buffer and has not been sent. No `messageId`.
194
+ * 2. **Server-side durable hand-off** — the request WAS sent and the server
195
+ * answered `202 Accepted`, having enqueued it for a worker to price. Carries
196
+ * a `messageId`. `usageLog` is null: the log does not exist yet.
197
+ *
198
+ * In case 2 the signal is accepted but **not yet billed**, and it has only been
199
+ * shallowly validated. A bad `agentKey`, a customer with no matching plan, or an
200
+ * exhausted allowance is detected by the worker LATER and never surfaces here —
201
+ * the signal is simply dropped. A `202` therefore means "accepted", never
202
+ * "recorded". To confirm a signal actually landed, read it back with
203
+ * `signals.list({ customerId })`.
204
+ *
205
+ * When the server has no queue configured it prices inline instead and returns
206
+ * `queued: false` with a populated `usageLog`, validating synchronously.
207
+ */
142
208
  interface TrackResult {
143
- /** True when the signal was buffered (async mode) and not yet sent. */
209
+ /** True when the signal has not been priced yet — either buffered locally
210
+ * (async mode) or accepted for asynchronous processing by the server. */
144
211
  queued: boolean;
145
- /** The computed usage log — present only once the signal has been sent. */
212
+ /** The computed usage log. Non-null ONLY when the server priced the signal
213
+ * inline (`queued: false`); null on a `202` hand-off and absent while the
214
+ * signal sits in the client-side buffer. */
146
215
  usageLog?: SerializedUsageLog | null;
216
+ /** The server's durable-queue message id, present only on a `202` hand-off
217
+ * (server-side queueing). Absent for client-side buffering and for inline
218
+ * pricing. */
219
+ messageId?: string;
147
220
  }
148
221
  interface UsageList {
149
222
  customer: {
@@ -232,7 +305,9 @@ interface OutcomeBalance {
232
305
  granted: number;
233
306
  remaining: number;
234
307
  /** Each step's `agentKey` is what `signals.outcome()` and the outcome adjust
235
- * API use to address this outcome (outcomes have no key of their own). */
308
+ * API use to address this outcome at runtime. The outcome also has its own
309
+ * separate key ({@link Outcome.agentKey}), but neither of those APIs accepts
310
+ * it — it identifies the outcome in the catalogue, not in a signal. */
236
311
  steps: {
237
312
  id: string;
238
313
  name: string;
@@ -687,10 +762,12 @@ interface CreditAdjustInput {
687
762
  notes?: string;
688
763
  }
689
764
  /** Grant/claw an outcome balance. `delta` is a non-zero whole number; floored at
690
- * 0. The outcome is addressed by a STEP's `agentKey` (outcomes have no key of
691
- * their own). */
765
+ * 0. The outcome is addressed here by a STEP's `agentKey`, which resolves to its
766
+ * parent outcome — NOT by the outcome's own `agentKey` ({@link Outcome.agentKey}),
767
+ * which this endpoint does not accept. */
692
768
  interface OutcomeAdjustInput {
693
- /** An outcome step's stable agent key — identifies the parent outcome. */
769
+ /** An outcome STEP's stable agent key — identifies the parent outcome. Passing
770
+ * the outcome's own `agentKey` here fails with `422`. */
694
771
  agentKey: string;
695
772
  delta: number;
696
773
  notes?: string;
@@ -799,6 +876,17 @@ interface OutcomeStepInput {
799
876
  interface Outcome {
800
877
  id: string;
801
878
  name: string;
879
+ /**
880
+ * The OUTCOME's own stable agent key — its durable identity, mirroring
881
+ * {@link Credit.agentKey}. Lowercased `[a-z0-9._-]`, max 80 chars, unique per
882
+ * organisation. A rename never changes it.
883
+ *
884
+ * Distinct from each step's `agentKey` in `steps`, and in a SEPARATE
885
+ * namespace: usage is always reported against a STEP's key
886
+ * (`signals.outcome({ agentKey })`), never this one. This key identifies the
887
+ * outcome itself when creating or updating it.
888
+ */
889
+ agentKey: string;
802
890
  description: string | null;
803
891
  isActive: boolean;
804
892
  marginPercent: number;
@@ -827,6 +915,15 @@ interface OutcomeDetail extends Outcome {
827
915
  }
828
916
  interface CreateOutcomeInput {
829
917
  name: string;
918
+ /**
919
+ * The OUTCOME's own stable agent key — REQUIRED. Lowercased `[a-z0-9._-]`,
920
+ * max 80 chars, unique per organisation (the server lowercases and trims it).
921
+ *
922
+ * Separate namespace from `steps[].agentKey`: this names the outcome, a step
923
+ * key names a step and is what `signals.outcome()` reports against. Omitting
924
+ * it is rejected with a `ValidationError` (400).
925
+ */
926
+ agentKey: string;
830
927
  basePrice: number;
831
928
  marginPercent: number;
832
929
  pricePerOutcome: number;
@@ -1233,8 +1330,14 @@ declare class Invoices {
1233
1330
 
1234
1331
  /**
1235
1332
  * The `outcomes` resource — manage the org's outcome *types* (the catalog). An
1236
- * outcome is a multi-step workflow; each step has a stable `agentKey` you pass
1237
- * to `signals.outcome()`. `/api/v1/outcomes`.
1333
+ * outcome is a multi-step workflow. `/api/v1/outcomes`.
1334
+ *
1335
+ * Two distinct kinds of agent key, in separate namespaces, each unique per
1336
+ * organisation — do not conflate them:
1337
+ * - the OUTCOME's own `agentKey`, REQUIRED on `create()` and `update()`, which
1338
+ * names the outcome itself in the catalogue;
1339
+ * - each STEP's `agentKey`, which is what you pass to `signals.outcome()` to
1340
+ * report usage and to the outcome-adjust API.
1238
1341
  */
1239
1342
  declare class Outcomes {
1240
1343
  private readonly transport;
@@ -1384,15 +1487,31 @@ declare function signalToWire(signal: Signal): Record<string, unknown>;
1384
1487
  /**
1385
1488
  * The `signals` resource: record usage signals and read them back.
1386
1489
  *
1387
- * In async mode (default), `track()` buffers the signal and returns immediately
1388
- * with `{ queued: true }`. Pass `{ wait: true }` (or construct the client in
1389
- * `sync` mode) to await the send and receive the computed `usageLog`.
1490
+ * In async mode (default), `track()` buffers the signal locally and returns
1491
+ * immediately with `{ queued: true }`. Pass `{ wait: true }` (or construct the
1492
+ * client in `sync` mode) to await the request.
1493
+ *
1494
+ * Awaiting the request does NOT guarantee a priced result. Where the server has
1495
+ * a durable queue configured it answers `202` and prices the signal in a worker,
1496
+ * so `track()` resolves `{ queued: true, messageId, usageLog: null }` — accepted,
1497
+ * not yet billed, and validated only later (a bad `agentKey` is dropped there,
1498
+ * silently). Only when the server prices inline do you get
1499
+ * `{ queued: false, usageLog }`. Branch on `queued`; never assume `usageLog`.
1500
+ * `verify()` is the way to validate and price a signal synchronously, and
1501
+ * `list()` is how you confirm one actually landed.
1390
1502
  */
1391
1503
  declare class Signals {
1392
1504
  private readonly transport;
1393
1505
  private readonly flusher;
1394
1506
  private readonly cfg;
1395
1507
  constructor(transport: Transport, flusher: Flusher, cfg: ResolvedConfig);
1508
+ /**
1509
+ * Record one usage signal. `POST /api/v1/usage`.
1510
+ *
1511
+ * Returns as soon as the signal is buffered (async mode) or the request has
1512
+ * been answered (`{ wait: true }` / sync mode). See {@link TrackResult}: a
1513
+ * resolved promise means "accepted", which is not the same as "billed".
1514
+ */
1396
1515
  track(signal: Signal, opts?: {
1397
1516
  wait?: boolean;
1398
1517
  }): Promise<TrackResult>;
@@ -1592,4 +1711,4 @@ declare class NetworkError extends ClockNextError {
1592
1711
  constructor(message: string);
1593
1712
  }
1594
1713
 
1595
- export { type AddMemberInput, AllowanceError, type ApiCustomer, AuthError, type BillingCycle, type BillingMode, ClockNext, type ClockNextConfig, ClockNextError, type ComponentType, ConflictError, type CostPoint, type CostStats, type CreateCreditInput, type CreateCustomerInput, type CreateOutcomeInput, type CreatePlanInput, type CreatePurchaseInput, type CreateUnitInput, type Credit, type CreditAdjustInput, type CreditAnalytics, type CreditBalance, type CreditComponentInput, type CreditDetail, type CreditInput, type CreditSignal, type CustomerBalances, type CustomerList, type CustomerPlan, type CustomerPlanDetails, type CustomerProfileInput, type DropReason, type FetchLike, type FlatComponentInput, type FlatUnitInput, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListRow, type InvoiceParty, type InvoicePlanSnapshot, type InvoiceStatus, type Logger, type Member, type MemberRole, type Model, type ModelBundleEntry, NetworkError, NotFoundError, type Outcome, type OutcomeAdjustInput, type OutcomeAnalytics, type OutcomeBalance, type OutcomeComponentInput, type OutcomeDetail, type OutcomeInput, type OutcomeSignal, type OutcomeStepInput, type PayLink, type PaymentDetail, type PaymentRow, type Plan, type PlanComponent, type PlanComponentInput, type PlanDetail, PlanError, type PlanKind, type PlanRef, type PlanType, type PortalToken, type PortalTokenInput, type Purchase, type PurchaseDetail, type PurchaseStatus, RateLimitError, type SerializedOutcomeAttribution, type SerializedRuleApplication, type SerializedUnitUsage, type SerializedUsageLog, ServerError, type Signal, type SignalStatus, type SignalType, type ThresholdKind, type TieredUnitInput, type Tokens, type TrackResult, type Unit, type UnitAdjustInput, type UnitBalance, type UnitComponentInput, type UnitCustomerRow, type UnitDetail, type UnitInput, type UnitPricingType, type UnitTier, type UnitTierInput, type UnitUsageList, type UnitUsageRow, type UpdateCreditInput, type UpdateMemberInput, type UpdateOutcomeInput, type UpdatePlanInput, type UpdateUnitInput, type UpsertWebhookInput, type UsageBalance, type UsageList, ValidationError, type WalletComponentInput, type WalletEntryInput, type WalletInput, type WalletList, type WalletSignal, type WalletTransaction, type WalletTransactionType, type Webhook, type WorkspaceIdentity, signalToWire };
1714
+ export { type AddMemberInput, AllowanceError, type ApiCustomer, AuthError, type BillingCycle, type BillingMode, ClockNext, type ClockNextConfig, ClockNextError, type ComponentType, ConflictError, type CostPoint, type CostStats, type CreateCreditInput, type CreateCustomerInput, type CreateOutcomeInput, type CreatePlanInput, type CreatePurchaseInput, type CreateUnitInput, type Credit, type CreditAdjustInput, type CreditAnalytics, type CreditBalance, type CreditComponentInput, type CreditDetail, type CreditInput, type CreditSignal, type CustomerBalances, type CustomerList, type CustomerPlan, type CustomerPlanDetails, type CustomerProfileInput, type DropReason, type FetchLike, type FlatComponentInput, type FlatUnitInput, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListRow, type InvoiceParty, type InvoicePlanSnapshot, type InvoiceStatus, type Logger, type Member, type MemberRole, type MetricTag, type Model, type ModelBundleEntry, NetworkError, NotFoundError, type Outcome, type OutcomeAdjustInput, type OutcomeAnalytics, type OutcomeBalance, type OutcomeComponentInput, type OutcomeDetail, type OutcomeInput, type OutcomeSignal, type OutcomeStepInput, type PayLink, type PaymentDetail, type PaymentRow, type Plan, type PlanComponent, type PlanComponentInput, type PlanDetail, PlanError, type PlanKind, type PlanRef, type PlanType, type PortalToken, type PortalTokenInput, type Purchase, type PurchaseDetail, type PurchaseStatus, RateLimitError, type SerializedOutcomeAttribution, type SerializedRuleApplication, type SerializedUnitUsage, type SerializedUsageLog, ServerError, type Signal, type SignalStatus, type SignalType, type ThresholdKind, type TieredUnitInput, type Tokens, type TrackResult, type Unit, type UnitAdjustInput, type UnitBalance, type UnitComponentInput, type UnitCustomerRow, type UnitDetail, type UnitInput, type UnitPricingType, type UnitTier, type UnitTierInput, type UnitUsageList, type UnitUsageRow, type UpdateCreditInput, type UpdateMemberInput, type UpdateOutcomeInput, type UpdatePlanInput, type UpdateUnitInput, type UpsertWebhookInput, type UsageBalance, type UsageList, ValidationError, type WalletComponentInput, type WalletEntryInput, type WalletInput, type WalletList, type WalletSignal, type WalletTransaction, type WalletTransactionType, type Webhook, type WorkspaceIdentity, signalToWire };
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.6.0" ;
230
+ var SDK_VERSION = "0.8.0" ;
231
231
  var Transport = class {
232
232
  constructor(cfg) {
233
233
  this.cfg = cfg;
@@ -868,6 +868,13 @@ function signalToWire(signal) {
868
868
  if (signal.type === "credit" || signal.type === "outcome") {
869
869
  body.agentKey = signal.agentKey;
870
870
  }
871
+ if (signal.type === "outcome") {
872
+ body.runId = signal.runId;
873
+ if (signal.complete != null) body.complete = signal.complete;
874
+ }
875
+ if (signal.type !== "wallet" && signal.metric) {
876
+ body[signal.metric.ref] = signal.metric.value;
877
+ }
871
878
  if (signal.idempotencyKey) body.idempotencyKey = signal.idempotencyKey;
872
879
  return body;
873
880
  }
@@ -880,6 +887,13 @@ var Signals = class {
880
887
  transport;
881
888
  flusher;
882
889
  cfg;
890
+ /**
891
+ * Record one usage signal. `POST /api/v1/usage`.
892
+ *
893
+ * Returns as soon as the signal is buffered (async mode) or the request has
894
+ * been answered (`{ wait: true }` / sync mode). See {@link TrackResult}: a
895
+ * resolved promise means "accepted", which is not the same as "billed".
896
+ */
883
897
  async track(signal, opts = {}) {
884
898
  const body = signalToWire(signal);
885
899
  if (body.idempotencyKey == null) body.idempotencyKey = newKey();
@@ -896,8 +910,9 @@ var Signals = class {
896
910
  retry: true
897
911
  });
898
912
  return {
899
- queued: false,
900
- usageLog: res.usageLog ?? null
913
+ queued: res.queued === true,
914
+ usageLog: res.usageLog ?? null,
915
+ ...res.messageId != null ? { messageId: res.messageId } : {}
901
916
  };
902
917
  }
903
918
  /**