@limitry/sdk 1.0.0-rc.6 → 1.0.0-rc.8

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/CHANGELOG.md CHANGED
@@ -2,6 +2,104 @@
2
2
 
3
3
  What changed in the Limitry TypeScript SDK (`@limitry/sdk`). Generated from the source on each release; newest first.
4
4
 
5
+ ## 1.0.0-rc.8 (2026-10-21)
6
+
7
+ ### Added
8
+
9
+ - Limits have `counting`: `fast` answers the instant it decides, and
10
+ `guaranteed` stores every count safely before answering, so the limit
11
+ never goes over, even if a server fails. A `total` balance defaults to
12
+ `guaranteed`, every other window to `fast`. Set it when creating or
13
+ updating a limit (`counting`, `--counting`), or in `limitry.json`.
14
+
15
+ ### Changed
16
+
17
+ - - Creating a limit needs only who it is for, the amount and the window:
18
+ `limits.create({ subject: { kind: "user" }, amount: 100, window: "month" })`
19
+ (`limitry limits create --subject '{"kind":"user"}' --amount 100 --window month`).
20
+ `action` defaults to every action (`*`), `unit` to `units`, and `name`
21
+ to the sentence the limit reads as, such as "100 units per user per
22
+ month". If a limit already has that name, the API answers `409`: give
23
+ this one a `name`. `limitry.json` entries still need a `name`.
24
+ - A limit's input names who it is for as `subject: { kind, id }` (was
25
+ `subjectKind` and `subjectId`), the same shape the limit itself has.
26
+ - What a limit counts is fixed once it is created: its subject, action,
27
+ unit, window, `every`, `start` and `rolling`. Changing one answers
28
+ `400 invalid_request`: create a new limit and archive the old one (its
29
+ history stays). Name, amount, fail mode and enabled still change any
30
+ time. `limitry sync` refuses such a change until you rename the entry.
31
+ - A limit says when a check last reached it (`lastCheckedAt`), so you can
32
+ see a limit no check names.
33
+ - One name for each idea, everywhere: the API, both SDKs, the CLI, the MCP
34
+ tools, `limitry.json` and webhooks. Update your code when you upgrade:
35
+
36
+ - `hold()` is `reserve()`: it takes `cost` (was `estimate`), and the block
37
+ gets a `Reservation` (was `Held`; Python `Reservation` and
38
+ `AsyncReservation`), with the same `cost()` and `extend()`.
39
+ - A refusal throws `LimitReached` (was `LimitExceeded`), with `limitId`
40
+ (Python `limit_id`) and `reason` `limit_reached` or
41
+ `too_many_reservations`. When Limitry can't be reached and a limit fails
42
+ closed, you now get a separate `Unavailable` error. "Can't be reached"
43
+ also covers a `402 plan_limit_reached` and a `429` from Limitry's flood
44
+ guard, so each limit's fail mode decides instead of your code getting an
45
+ error.
46
+ - A check's answer lists its limits in `limits` (was `remaining`): read
47
+ `decision.limits[0].remaining`. Every answer that names a limit says
48
+ `limitId`: `reason.limitId`, `limits[].limitId`, `usage.standing`'s
49
+ `limits[].limitId`, and webhook payloads.
50
+ - The refusal code is `limit_reached` (was `limit_exceeded`), and the
51
+ webhook event is `limit.reached` (was `limit.exceeded`): subscribe your
52
+ endpoints to the new name.
53
+ - Usage says `refused` (was `denied`); `usage.subjects` no longer has
54
+ `over` (it is `refused > 0`).
55
+ - Credits: `limits.credits.create()` and `limits.credits.list()` at
56
+ `/v1/limits/{limitId}/credits` (were `limits.grants.*` at `…/grants`),
57
+ ids start `crd_` (were `grt_`), and the approval an agent asks for is
58
+ `limit.credit` (was `limit.grant`).
59
+ - A period that starts on the subject's billing date is
60
+ `start: "billing_date"` (was `"anchor"`), and `subjects.update()` takes
61
+ `billingDate` (was `anchor`); the subject says `billingDate` too.
62
+ - `usage.standing()` and `usage.query()` take one `subject`, written
63
+ `kind:id` (`user:usr_123`), instead of separate kind and id fields
64
+ (`limitry usage standing --subject user:usr_123`).
65
+ - A limit's id starts `lmt_` (was `lim_`); keys still start `lim_test_`
66
+ and `lim_live_`.
67
+ - `limitry sync --preview` (was `--dry-run`), and the API's `preview`
68
+ (was `dryRun`), in what you send and what comes back.
69
+
70
+ ### Removed
71
+
72
+ - Limits no longer have `counting` (Fast or Guaranteed), and the CLI no
73
+ longer has `--counting`: every count is now saved before Limitry answers,
74
+ for every limit. Remove `counting` from your code and from
75
+ `limitry.json`; Limitry ignores it.
76
+
77
+ ## 1.0.0-rc.7 (2026-10-19)
78
+
79
+ ### Added
80
+
81
+ - A refused check's `reason` has a `message`: the refusal in one sentence,
82
+ such as "Refused by AI budget: 3 cents left, resets
83
+ 2026-11-01T00:00:00.000Z. Try again in 3600 s." `LimitExceeded` and
84
+ `limitry check` show it as the API writes it, so every client says the
85
+ same. Branch on `allowed` and `reason.code`, never on the message.
86
+
87
+ ### Fixed
88
+
89
+ - - `held.cost()` refuses a cost the API can't commit (not a whole number
90
+ from 0 to 1,000,000,000): TypeScript throws `RangeError`, Python raises
91
+ `ValueError`, in your code. Before, the commit failed silently after
92
+ the work and its usage was never counted.
93
+ - TypeScript's `held.extend()` throws the API's error, such as for an
94
+ expired hold, as Python's already did. Both send the `ttlSeconds` you
95
+ give as it is, so `0` is refused rather than read as the default.
96
+ - Python checks, commits and releases now retry exactly as TypeScript's
97
+ do: a network error, `408`, `429` or `5xx`, at most twice, all within
98
+ the check's `timeout` (1.5 s) or 5 s for a settle. `standing()` retries
99
+ too, and reports an error answer that isn't JSON.
100
+ - `limitry check` and `limitry sync` refuse `--workspace` with an API key,
101
+ as every other command does, instead of ignoring it.
102
+
5
103
  ## 1.0.0-rc.6 (2026-10-19)
6
104
 
7
105
  ### Changed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @limitry/sdk
2
2
 
3
- The Limitry TypeScript SDK puts a limit around costly work in one call: `guard` checks before your code runs, and `hold` reserves an estimate, then charges what the work actually cost. Every API operation is a typed method too.
3
+ The Limitry TypeScript SDK puts a limit around costly work in one call: `guard` checks before your code runs, and `reserve` reserves what the work will probably cost, then charges what it actually cost. Every API operation is a typed method too.
4
4
 
5
5
  Limitry is the limits, credits and budgets layer for your software: give each of your users, teams, tenants, API keys or agents an allowance, and before any costly action one call tells your code whether it may happen.
6
6
 
@@ -19,7 +19,7 @@ key (`lim_test_…`) while you build.
19
19
  it counts one AI call against a limit such as 100 a day:
20
20
 
21
21
  ```ts
22
- import { createClient, LimitExceeded } from "@limitry/sdk";
22
+ import { createClient, LimitReached } from "@limitry/sdk";
23
23
 
24
24
  const limitry = createClient(); // reads LIMITRY_API_KEY
25
25
 
@@ -29,7 +29,7 @@ try {
29
29
  () => callModel(prompt),
30
30
  );
31
31
  } catch (error) {
32
- if (error instanceof LimitExceeded) {
32
+ if (error instanceof LimitReached) {
33
33
  console.log(`Try again in ${error.retryAfterSeconds} seconds`);
34
34
  }
35
35
  }
@@ -38,26 +38,28 @@ try {
38
38
  ## Charge what it actually cost
39
39
 
40
40
  When you only know the cost afterwards, such as an AI reply priced by
41
- the token, `hold` reserves an estimate (5 cents here), runs your code
42
- and charges what it used. If your code throws, the hold is released:
41
+ the token, `reserve` reserves what it will probably cost (5 cents here),
42
+ runs your code and charges what it used. If your code throws, the
43
+ reservation is released:
43
44
 
44
45
  ```ts
45
46
  import { createClient } from "@limitry/sdk";
46
47
 
47
48
  const limitry = createClient();
48
49
 
49
- const answer = await limitry.hold(
50
- { subject: { kind: "user", id: "usr_123" }, action: "ai-call", estimate: 5 },
51
- async (held) => {
50
+ const answer = await limitry.reserve(
51
+ { subject: { kind: "user", id: "usr_123" }, action: "ai-call", cost: 5 },
52
+ async (reservation) => {
52
53
  const response = await callModel(prompt);
53
- held.cost(priceCents(response.usage)); // your prices, in cents
54
+ reservation.cost(priceCents(response.usage)); // your prices, in cents
54
55
  return response;
55
56
  },
56
57
  );
57
58
  ```
58
59
 
59
- If Limitry can't be reached, each limit's fail mode decides: `open` lets
60
- the work run, `closed` refuses it.
60
+ A refusal throws `LimitReached`. If Limitry can't be reached, each
61
+ limit's fail mode decides: `open` lets the work run, `closed` throws
62
+ `Unavailable`.
61
63
 
62
64
  ## Everything else
63
65
 
@@ -69,9 +71,9 @@ import { createClient } from "@limitry/sdk";
69
71
 
70
72
  const limitry = createClient();
71
73
 
74
+ // "100 units per user per day for ai-call"
72
75
  await limitry.limits.create({
73
- name: "AI replies per day",
74
- subjectKind: "user",
76
+ subject: { kind: "user" },
75
77
  action: "ai-call",
76
78
  amount: 100,
77
79
  window: "day",
package/dist/index.d.ts CHANGED
@@ -76,11 +76,12 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
76
76
  create: (input: import("./resources.ts").Input<"/checks", "post">, options?: import("./resources.ts").RequestOptions) => Promise<{
77
77
  allowed: boolean;
78
78
  id: string;
79
+ limits: components["schemas"]["CheckLimit"][];
79
80
  reason: {
80
- code: "limit_exceeded" | "too_many_reservations";
81
- limit: string | null;
81
+ code: "limit_reached" | "too_many_reservations";
82
+ limitId: string | null;
83
+ message: string;
82
84
  } | null;
83
- remaining: components["schemas"]["CheckRemaining"][];
84
85
  reservation?: {
85
86
  expiresAt: string;
86
87
  id: string;
@@ -99,15 +100,33 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
99
100
  every: number;
100
101
  failMode: "open" | "closed";
101
102
  id: string;
103
+ lastCheckedAt: string | null;
102
104
  name: string;
103
105
  rolling: boolean;
104
- start: "calendar" | "anchor" | "first_use";
106
+ start: "calendar" | "billing_date" | "first_use";
105
107
  subject: components["schemas"]["LimitSubject"];
106
108
  unit: string;
107
109
  updatedAt: string;
108
110
  version: number;
109
111
  window: "minute" | "hour" | "day" | "week" | "month" | "year" | "total" | "concurrent";
110
112
  }>;
113
+ credits: {
114
+ create: (limitId: string | number, input: import("./resources.ts").Input<"/limits/{limitId}/credits", "post">, options?: import("./resources.ts").RequestOptions) => Promise<{
115
+ amount: number;
116
+ createdAt: string;
117
+ createdByUserId: string | null;
118
+ id: string;
119
+ limitId: string;
120
+ note: string;
121
+ subject: {
122
+ id: string;
123
+ kind: string;
124
+ };
125
+ }>;
126
+ list: (limitId: string | number, options?: import("./resources.ts").RequestOptions) => Promise<{
127
+ items: components["schemas"]["Credit"][];
128
+ }>;
129
+ };
111
130
  get: (limitId: string | number, options?: import("./resources.ts").RequestOptions) => Promise<{
112
131
  action: string;
113
132
  amount: number;
@@ -117,32 +136,16 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
117
136
  every: number;
118
137
  failMode: "open" | "closed";
119
138
  id: string;
139
+ lastCheckedAt: string | null;
120
140
  name: string;
121
141
  rolling: boolean;
122
- start: "calendar" | "anchor" | "first_use";
142
+ start: "calendar" | "billing_date" | "first_use";
123
143
  subject: components["schemas"]["LimitSubject"];
124
144
  unit: string;
125
145
  updatedAt: string;
126
146
  version: number;
127
147
  window: "minute" | "hour" | "day" | "week" | "month" | "year" | "total" | "concurrent";
128
148
  }>;
129
- grants: {
130
- create: (limitId: string | number, input: import("./resources.ts").Input<"/limits/{limitId}/grants", "post">, options?: import("./resources.ts").RequestOptions) => Promise<{
131
- amount: number;
132
- createdAt: string;
133
- createdByUserId: string | null;
134
- id: string;
135
- limitId: string;
136
- note: string;
137
- subject: {
138
- id: string;
139
- kind: string;
140
- };
141
- }>;
142
- list: (limitId: string | number, options?: import("./resources.ts").RequestOptions) => Promise<{
143
- items: components["schemas"]["LimitGrant"][];
144
- }>;
145
- };
146
149
  list: (input?: import("./resources.ts").Input<"/limits", "get">, options?: import("./resources.ts").RequestOptions) => Promise<{
147
150
  items: components["schemas"]["Limit"][];
148
151
  nextCursor: string | null;
@@ -156,9 +159,10 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
156
159
  every: number;
157
160
  failMode: "open" | "closed";
158
161
  id: string;
162
+ lastCheckedAt: string | null;
159
163
  name: string;
160
164
  rolling: boolean;
161
- start: "calendar" | "anchor" | "first_use";
165
+ start: "calendar" | "billing_date" | "first_use";
162
166
  subject: components["schemas"]["LimitSubject"];
163
167
  unit: string;
164
168
  updatedAt: string;
@@ -168,7 +172,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
168
172
  sync: (input: import("./resources.ts").Input<"/limits/sync", "post">, options?: import("./resources.ts").RequestOptions) => Promise<{
169
173
  archived: string[];
170
174
  created: string[];
171
- dryRun: boolean;
175
+ preview: boolean;
172
176
  unchanged: string[];
173
177
  updated: {
174
178
  changes: {
@@ -189,9 +193,10 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
189
193
  every: number;
190
194
  failMode: "open" | "closed";
191
195
  id: string;
196
+ lastCheckedAt: string | null;
192
197
  name: string;
193
198
  rolling: boolean;
194
- start: "calendar" | "anchor" | "first_use";
199
+ start: "calendar" | "billing_date" | "first_use";
195
200
  subject: components["schemas"]["LimitSubject"];
196
201
  unit: string;
197
202
  updatedAt: string;
@@ -224,7 +229,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
224
229
  };
225
230
  subjects: {
226
231
  get: (subjectKind: string | number, subjectId: string | number, options?: import("./resources.ts").RequestOptions) => Promise<{
227
- anchor: string | null;
232
+ billingDate: string | null;
228
233
  subject: components["schemas"]["SubjectRef"];
229
234
  }>;
230
235
  reset: (subjectKind: string | number, subjectId: string | number, input?: import("./resources.ts").Input<"/subjects/{subjectKind}/{subjectId}/reset", "post">, options?: import("./resources.ts").RequestOptions) => Promise<{
@@ -232,7 +237,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
232
237
  subject: components["schemas"]["SubjectRef"];
233
238
  }>;
234
239
  update: (subjectKind: string | number, subjectId: string | number, input: import("./resources.ts").Input<"/subjects/{subjectKind}/{subjectId}", "patch">, options?: import("./resources.ts").RequestOptions) => Promise<{
235
- anchor: string | null;
240
+ billingDate: string | null;
236
241
  subject: components["schemas"]["SubjectRef"];
237
242
  }>;
238
243
  };
@@ -242,7 +247,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
242
247
  limitId: string;
243
248
  points: {
244
249
  allowed: number;
245
- denied: number;
250
+ refused: number;
246
251
  start: string;
247
252
  used: number;
248
253
  }[];
@@ -252,7 +257,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
252
257
  limits: {
253
258
  action: string;
254
259
  amount: number;
255
- limit: string;
260
+ limitId: string;
256
261
  name: string;
257
262
  remaining: number;
258
263
  resetsAt: string | null;
@@ -273,8 +278,7 @@ declare function createBaseClient(options: ClientOptions): import("openapi-fetch
273
278
  }>;
274
279
  subjects: (input: import("./resources.ts").Input<"/usage/subjects", "get">, options?: import("./resources.ts").RequestOptions) => Promise<{
275
280
  items: {
276
- denied: number;
277
- over: boolean;
281
+ refused: number;
278
282
  remaining: number;
279
283
  subject: {
280
284
  id: string;
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * PRODUCT-OWNED: Limitry's SDK helpers (fork-owned seam — docs/conventions.md
3
3
  * "Fork-owned seams"): re-exported by the SDK entry and published with
4
- * it. `guard` / `hold` (docs/product/roadmap.md slice 6) sit on the client
4
+ * it. `guard` / `reserve` (docs/product/roadmap.md slice 6) sit on the client
5
5
  * (`limitry.guard(…)`, the SDK's `productMethods` seam); `createLimits(client,
6
6
  * options)` gives them with your own timeout or fail mode.
7
7
  */
8
8
  import type { BaseClient } from "../index.ts";
9
- export { createLimits, LimitExceeded, type GuardRequest, type Held, type HoldRequest, type Limits, type LimitsOptions, } from "./limits.ts";
10
- /** Limitry's methods on the client: `limitry.guard(…)`, `limitry.hold(…)`, `limitry.standing(…)`. */
9
+ export { createLimits, LimitReached, Unavailable, type GuardRequest, type Limits, type LimitsOptions, type Reservation, type ReserveRequest, } from "./limits.ts";
10
+ /** Limitry's methods on the client: `limitry.guard(…)`, `limitry.reserve(…)`, `limitry.standing(…)`. */
11
11
  export declare const productMethods: (client: BaseClient) => {
12
12
  guard: <T>(request: import("./limits.ts").GuardRequest, fn: () => Promise<T>) => Promise<T>;
13
- hold: <T>(request: import("./limits.ts").HoldRequest, fn: (held: import("./limits.ts").Held) => Promise<T>) => Promise<T>;
13
+ reserve: <T>(request: import("./limits.ts").ReserveRequest, fn: (reservation: import("./limits.ts").Reservation) => Promise<T>) => Promise<T>;
14
14
  standing: (request: {
15
15
  subject: {
16
16
  kind: string;
@@ -1,7 +1,11 @@
1
1
  import { createLimits } from "./limits.js";
2
- export { createLimits, LimitExceeded, } from "./limits.js";
3
- /** Limitry's methods on the client: `limitry.guard(…)`, `limitry.hold(…)`, `limitry.standing(…)`. */
2
+ export { createLimits, LimitReached, Unavailable, } from "./limits.js";
3
+ /** Limitry's methods on the client: `limitry.guard(…)`, `limitry.reserve(…)`, `limitry.standing(…)`. */
4
4
  export const productMethods = (client) => {
5
5
  const limits = createLimits(client);
6
- return { guard: limits.guard, hold: limits.hold, standing: limits.standing };
6
+ return {
7
+ guard: limits.guard,
8
+ reserve: limits.reserve,
9
+ standing: limits.standing,
10
+ };
7
11
  };
@@ -13,33 +13,34 @@ import type { BaseClient, Schemas } from "../index.ts";
13
13
  * );
14
14
  *
15
15
  * // Cost known afterwards (an AI reply's cents), or "at most N at
16
- * // once": hold an estimate, do the work, commit what it used —
17
- * // released on failure.
18
- * const answer = await limitry.hold(
19
- * { subject: { kind: "user", id: user.id }, action: "ai-call", estimate: 5 },
20
- * async (held) => {
16
+ * // once": reserve what it will probably cost, do the work, commit
17
+ * // what it used — released on failure.
18
+ * const answer = await limitry.reserve(
19
+ * { subject: { kind: "user", id: user.id }, action: "ai-call", cost: 5 },
20
+ * async (reservation) => {
21
21
  * const res = await callModel(prompt);
22
- * held.cost(priceCents(res.usage));
22
+ * reservation.cost(priceCents(res.usage));
23
23
  * return res;
24
24
  * },
25
25
  * );
26
26
  *
27
- * A refusal throws `LimitExceeded` (with `retryAfterSeconds`). When
28
- * Limitry cannot be reached (an error, a 5xx, or no answer within
29
- * `timeoutMs`) — or the workspace is past its plan's allowance (402
30
- * `plan_limit_reached`) — each limit's fail mode decides: the last decision's
31
- * `failMode` for this subject and action is remembered in memory, and
32
- * `closed` refuses (`LimitExceeded` with reason `unavailable`) while
33
- * `open` — the default, and the answer before any decision was seen —
34
- * lets the work run unmetered.
27
+ * A refusal throws `LimitReached` (with `limitId` and
28
+ * `retryAfterSeconds`). When Limitry cannot be reached — an error, a 5xx,
29
+ * no answer within `timeoutMs`, the workspace past its plan's allowance
30
+ * (402 `plan_limit_reached`) or the edge's flood guard (429) — each
31
+ * limit's fail mode decides: the last decision's `failMode` for this
32
+ * subject and action is remembered in memory, and `closed` throws
33
+ * `Unavailable` while `open` — the default, and the answer before any
34
+ * decision was seen — lets the work run unmetered.
35
35
  *
36
- * Retries are safe (docs/product idempotency): each guard or hold sends
37
- * one Idempotency-Key, which the client's own retries reuse, so a check
38
- * counts once however often it is sent. A hold whose check timed out may
39
- * have been granted all the same: once the work is done, `hold` sends the
40
- * check again with the same key — a replay, nothing counted twice — and
41
- * releases the hold it finds, rather than leave it taken until it expires.
42
- * Commits and releases retry too (settling twice answers the same).
36
+ * Retries are safe (docs/product idempotency): each guard or reserve
37
+ * sends one Idempotency-Key, which the client's own retries reuse, so a
38
+ * check counts once however often it is sent. A reservation whose check
39
+ * timed out may have been made all the same: once the work is done,
40
+ * `reserve` sends the check again with the same key — a replay, nothing
41
+ * counted twice — and releases the reservation it finds, rather than
42
+ * leave it taken until it expires. Commits and releases retry too
43
+ * (committing or releasing twice answers the same).
43
44
  */
44
45
  type Decision = Schemas["CheckDecision"];
45
46
  type Subject = {
@@ -60,29 +61,47 @@ export type GuardRequest = {
60
61
  /** Pools it also draws from (a team's, an org's). */
61
62
  shared?: Subject[];
62
63
  };
63
- export type HoldRequest = {
64
+ export type ReserveRequest = {
64
65
  subject: Subject;
65
66
  action: string;
66
- /** What it will probably use — held until you commit the actual cost. Default 1. */
67
- estimate?: number;
67
+ /** What it will probably use — reserved until you commit the actual cost. Default 1. */
68
+ cost?: number;
68
69
  shared?: Subject[];
69
- /** How long the hold lasts if never settled (default 300, at most 3600). */
70
+ /** How long the reservation lasts if never committed or released (default 300, at most 3600). */
70
71
  ttlSeconds?: number;
71
72
  };
72
- export type Held = {
73
- /** The cost actually used — committed when the work returns. Default: the estimate. */
73
+ export type Reservation = {
74
+ /**
75
+ * The cost actually used — committed when the work returns. Default: the
76
+ * reserved cost. A whole number from 0 to 1,000,000,000, as the API
77
+ * commits: anything else throws a RangeError here, in your code, rather
78
+ * than a commit the API refuses after the work (whose usage would go
79
+ * uncounted).
80
+ */
74
81
  cost(units: number): void;
75
- /** Keep the hold for longer work: it expires `ttlSeconds` from now. */
82
+ /**
83
+ * Keep the reservation for longer work: it expires `ttlSeconds` from now
84
+ * (default 300, 1 to 3600). Throws the API's error, such as for a
85
+ * reservation that already expired.
86
+ */
76
87
  extend(ttlSeconds?: number): Promise<void>;
77
88
  };
78
- /** Not allowed: a limit is used up — or Limitry is unreachable and a limit fails closed. */
79
- export declare class LimitExceeded extends Error {
80
- readonly reason: "limit_exceeded" | "too_many_reservations" | "unavailable";
81
- /** The limit that refused; null when unavailable or too many holds. */
82
- readonly limit: string | null;
89
+ /** Refused: a limit is reached, or the subject holds too many open reservations. */
90
+ export declare class LimitReached extends Error {
91
+ readonly reason: "limit_reached" | "too_many_reservations";
92
+ /** The limit that refused; null for too many open reservations. */
93
+ readonly limitId: string | null;
83
94
  readonly retryAfterSeconds: number | null;
84
- readonly decision: Decision | null;
85
- constructor(decision: Decision | null);
95
+ readonly decision: Decision;
96
+ constructor(decision: Decision);
97
+ }
98
+ /**
99
+ * Limitry could not be reached (an error, a 5xx, a timeout, the plan's
100
+ * allowance used up, or the flood guard's 429) and a limit on this
101
+ * subject and action fails closed. With `open`, the work runs instead.
102
+ */
103
+ export declare class Unavailable extends Error {
104
+ constructor();
86
105
  }
87
106
  export declare function createLimits(client: BaseClient, options?: LimitsOptions): {
88
107
  /**
@@ -99,12 +118,12 @@ export declare function createLimits(client: BaseClient, options?: LimitsOptions
99
118
  /** Checks `cost`, runs `fn` only if allowed, and returns its result. */
100
119
  guard<T>(request: GuardRequest, fn: () => Promise<T>): Promise<T>;
101
120
  /**
102
- * Holds `estimate`, runs `fn`, then commits the cost it reported
103
- * (`held.cost(n)`, default the estimate) — or releases the hold if
104
- * `fn` throws, and rethrows. A concurrent limit's slot is held for
105
- * exactly as long as `fn` runs.
121
+ * Reserves `cost`, runs `fn`, then commits the cost it reported
122
+ * (`reservation.cost(n)`, default the reserved cost) — or releases the
123
+ * reservation if `fn` throws, and rethrows. A concurrent limit's slot
124
+ * is taken for exactly as long as `fn` runs.
106
125
  */
107
- hold<T>(request: HoldRequest, fn: (held: Held) => Promise<T>): Promise<T>;
126
+ reserve<T>(request: ReserveRequest, fn: (reservation: Reservation) => Promise<T>): Promise<T>;
108
127
  };
109
128
  export type Limits = ReturnType<typeof createLimits>;
110
129
  export {};