@lizard-build/sdk 0.1.66 → 0.1.68

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.mts CHANGED
@@ -1401,6 +1401,7 @@ interface MetricPoint {
1401
1401
  }
1402
1402
  interface ServiceMetrics {
1403
1403
  cpu: MetricPoint[];
1404
+ /** Working set: what the service holds, without the file cache the kernel frees on demand. */
1404
1405
  memory: MetricPoint[];
1405
1406
  networkRx: MetricPoint[];
1406
1407
  networkTx: MetricPoint[];
@@ -1485,6 +1486,27 @@ interface ResalePricing {
1485
1486
  enabled: boolean;
1486
1487
  multipliers: ResaleMultipliers;
1487
1488
  }
1489
+ /** What a workspace may run at once (null: no limit). See {@link WorkspacesAPI.setLimits}. */
1490
+ interface WorkspaceLimits {
1491
+ /** Sandboxes running (or resuming) at once; paused ones do not count. */
1492
+ maxRunningSandboxes: number | null;
1493
+ /** vCPU its apps and databases may be using right now (measured). */
1494
+ maxCpuVcpus: number | null;
1495
+ /** Memory (MB) its apps and databases may be using right now (measured). */
1496
+ maxMemoryMb: number | null;
1497
+ }
1498
+ interface WorkspaceUsage {
1499
+ runningSandboxes: number;
1500
+ /** Measured, all regions, its apps and databases. */
1501
+ cpuVcpus: number;
1502
+ memoryMb: number;
1503
+ /** Unix ms of the oldest reading in the sum; null when nothing was measured. */
1504
+ measuredAt: number | null;
1505
+ }
1506
+ interface WorkspaceLimitsInfo {
1507
+ limits: WorkspaceLimits;
1508
+ usage: WorkspaceUsage;
1509
+ }
1488
1510
  interface CreateWorkspaceOpts {
1489
1511
  name: string;
1490
1512
  }
@@ -1550,6 +1572,27 @@ declare class WorkspacesAPI {
1550
1572
  setResalePricing(id: string, multipliers: Partial<ResaleMultipliers>): Promise<ResalePricing>;
1551
1573
  /** Turn resale prices off: scoped keys see Lizard's prices again (owner only). */
1552
1574
  clearResalePricing(id: string): Promise<ResalePricing>;
1575
+ /**
1576
+ * The workspace's limits and what it uses now. Anyone in the workspace may read them,
1577
+ * including a key scoped to it (your customer sees how close they are).
1578
+ */
1579
+ getLimits(id: string): Promise<WorkspaceLimitsInfo>;
1580
+ /**
1581
+ * Limit what a workspace may run at once (owner only, key with no scopes). A field left out
1582
+ * stays as it is; `null` removes that limit.
1583
+ *
1584
+ * - `maxRunningSandboxes`: a create, fork or resume past it fails with HTTP 429
1585
+ * `WORKSPACE_SANDBOX_LIMIT`.
1586
+ * - `maxCpuVcpus` / `maxMemoryMb`: what its apps and databases USE (measured every ~10 s,
1587
+ * not their configured limits). While at or over a cap, deploys, redeploys, restarts,
1588
+ * scale-ups, new databases and resumes there fail with HTTP 429 `WORKSPACE_USAGE_LIMIT`;
1589
+ * services already running keep running.
1590
+ *
1591
+ * ```ts
1592
+ * await lizard.workspaces.setLimits(ws.id, { maxRunningSandboxes: 5, maxCpuVcpus: 2, maxMemoryMb: 4096 })
1593
+ * ```
1594
+ */
1595
+ setLimits(id: string, limits: Partial<WorkspaceLimits>): Promise<WorkspaceLimitsInfo>;
1553
1596
  /**
1554
1597
  * Delete a workspace.
1555
1598
  *
@@ -2209,6 +2252,38 @@ declare class PaymentRequiredError extends LizardError {
2209
2252
  /** The one page to open next for this {@link paymentStatus}. */
2210
2253
  get url(): string | undefined;
2211
2254
  }
2255
+ /**
2256
+ * A limit was reached (HTTP 429). {@link LizardError.code} says which:
2257
+ * - `SANDBOX_LIMIT_REACHED` / `SANDBOX_RATE_LIMITED`: the account's sandbox limits (running at
2258
+ * once, starts per minute/hour/day); {@link retryAfterS} says when to try again.
2259
+ * - `WORKSPACE_SANDBOX_LIMIT`: the workspace's own cap on running sandboxes
2260
+ * (`workspaces.setLimits`).
2261
+ * - `WORKSPACE_USAGE_LIMIT`: the workspace's apps and databases use as much CPU or memory as its
2262
+ * cap; {@link usage} and {@link limits} carry both.
2263
+ * Still a {@link LizardError}, so existing `catch` blocks keep working.
2264
+ */
2265
+ declare class LimitExceededError extends LizardError {
2266
+ /** The limit that was reached (sandbox counts). */
2267
+ limit?: number;
2268
+ /** How many were running when it was refused. */
2269
+ running?: number;
2270
+ /** Seconds until a rate limit lets the next start through. */
2271
+ retryAfterS?: number;
2272
+ /** `WORKSPACE_USAGE_LIMIT`: the workspace's current use. */
2273
+ usage?: {
2274
+ runningSandboxes: number;
2275
+ cpuVcpus: number;
2276
+ memoryMb: number;
2277
+ measuredAt: number | null;
2278
+ };
2279
+ /** `WORKSPACE_USAGE_LIMIT`: the workspace's limits. */
2280
+ limits?: {
2281
+ maxRunningSandboxes: number | null;
2282
+ maxCpuVcpus: number | null;
2283
+ maxMemoryMb: number | null;
2284
+ };
2285
+ constructor(message?: string);
2286
+ }
2212
2287
 
2213
2288
  /** A single output item produced during code execution. */
2214
2289
  type OutputItem = {
@@ -2384,4 +2459,4 @@ declare class LizardCLI {
2384
2459
  }): Promise<CLIResult>;
2385
2460
  }
2386
2461
 
2387
- export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CheckoutSession, type ClickOpts, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, Desktop, type DesktopInfo, type DesktopStartOpts, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type ExposedPort, type FileInfo, type ForkResult, type FsEvent, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, type MouseButton, NotFoundError, PaymentRequiredError, type Plan, PlatformClient, type ProcessInfo, type ProcessOpts, type ProcessResult, type ProcessSignal, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type PromoRedemption, type RawMetrics, type Region, RegionsAPI, type ResaleMultipliers, type ResalePricing, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type ScrollDirection, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotScope, type SnapshotWaitOpts, type StartCheckoutOpts, type StartProNowResult, StorageAPI, type StreamEvent, type Subscription, type SubscriptionStatus, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
2462
+ export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CheckoutSession, type ClickOpts, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, Desktop, type DesktopInfo, type DesktopStartOpts, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type ExposedPort, type FileInfo, type ForkResult, type FsEvent, type FsOpts, GitHubAPI, LimitExceededError, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, type MouseButton, NotFoundError, PaymentRequiredError, type Plan, PlatformClient, type ProcessInfo, type ProcessOpts, type ProcessResult, type ProcessSignal, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type PromoRedemption, type RawMetrics, type Region, RegionsAPI, type ResaleMultipliers, type ResalePricing, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type ScrollDirection, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotScope, type SnapshotWaitOpts, type StartCheckoutOpts, type StartProNowResult, StorageAPI, type StreamEvent, type Subscription, type SubscriptionStatus, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, type WorkspaceLimits, type WorkspaceLimitsInfo, type WorkspaceUsage, WorkspacesAPI, resolveProjectId };
package/dist/index.d.ts CHANGED
@@ -1401,6 +1401,7 @@ interface MetricPoint {
1401
1401
  }
1402
1402
  interface ServiceMetrics {
1403
1403
  cpu: MetricPoint[];
1404
+ /** Working set: what the service holds, without the file cache the kernel frees on demand. */
1404
1405
  memory: MetricPoint[];
1405
1406
  networkRx: MetricPoint[];
1406
1407
  networkTx: MetricPoint[];
@@ -1485,6 +1486,27 @@ interface ResalePricing {
1485
1486
  enabled: boolean;
1486
1487
  multipliers: ResaleMultipliers;
1487
1488
  }
1489
+ /** What a workspace may run at once (null: no limit). See {@link WorkspacesAPI.setLimits}. */
1490
+ interface WorkspaceLimits {
1491
+ /** Sandboxes running (or resuming) at once; paused ones do not count. */
1492
+ maxRunningSandboxes: number | null;
1493
+ /** vCPU its apps and databases may be using right now (measured). */
1494
+ maxCpuVcpus: number | null;
1495
+ /** Memory (MB) its apps and databases may be using right now (measured). */
1496
+ maxMemoryMb: number | null;
1497
+ }
1498
+ interface WorkspaceUsage {
1499
+ runningSandboxes: number;
1500
+ /** Measured, all regions, its apps and databases. */
1501
+ cpuVcpus: number;
1502
+ memoryMb: number;
1503
+ /** Unix ms of the oldest reading in the sum; null when nothing was measured. */
1504
+ measuredAt: number | null;
1505
+ }
1506
+ interface WorkspaceLimitsInfo {
1507
+ limits: WorkspaceLimits;
1508
+ usage: WorkspaceUsage;
1509
+ }
1488
1510
  interface CreateWorkspaceOpts {
1489
1511
  name: string;
1490
1512
  }
@@ -1550,6 +1572,27 @@ declare class WorkspacesAPI {
1550
1572
  setResalePricing(id: string, multipliers: Partial<ResaleMultipliers>): Promise<ResalePricing>;
1551
1573
  /** Turn resale prices off: scoped keys see Lizard's prices again (owner only). */
1552
1574
  clearResalePricing(id: string): Promise<ResalePricing>;
1575
+ /**
1576
+ * The workspace's limits and what it uses now. Anyone in the workspace may read them,
1577
+ * including a key scoped to it (your customer sees how close they are).
1578
+ */
1579
+ getLimits(id: string): Promise<WorkspaceLimitsInfo>;
1580
+ /**
1581
+ * Limit what a workspace may run at once (owner only, key with no scopes). A field left out
1582
+ * stays as it is; `null` removes that limit.
1583
+ *
1584
+ * - `maxRunningSandboxes`: a create, fork or resume past it fails with HTTP 429
1585
+ * `WORKSPACE_SANDBOX_LIMIT`.
1586
+ * - `maxCpuVcpus` / `maxMemoryMb`: what its apps and databases USE (measured every ~10 s,
1587
+ * not their configured limits). While at or over a cap, deploys, redeploys, restarts,
1588
+ * scale-ups, new databases and resumes there fail with HTTP 429 `WORKSPACE_USAGE_LIMIT`;
1589
+ * services already running keep running.
1590
+ *
1591
+ * ```ts
1592
+ * await lizard.workspaces.setLimits(ws.id, { maxRunningSandboxes: 5, maxCpuVcpus: 2, maxMemoryMb: 4096 })
1593
+ * ```
1594
+ */
1595
+ setLimits(id: string, limits: Partial<WorkspaceLimits>): Promise<WorkspaceLimitsInfo>;
1553
1596
  /**
1554
1597
  * Delete a workspace.
1555
1598
  *
@@ -2209,6 +2252,38 @@ declare class PaymentRequiredError extends LizardError {
2209
2252
  /** The one page to open next for this {@link paymentStatus}. */
2210
2253
  get url(): string | undefined;
2211
2254
  }
2255
+ /**
2256
+ * A limit was reached (HTTP 429). {@link LizardError.code} says which:
2257
+ * - `SANDBOX_LIMIT_REACHED` / `SANDBOX_RATE_LIMITED`: the account's sandbox limits (running at
2258
+ * once, starts per minute/hour/day); {@link retryAfterS} says when to try again.
2259
+ * - `WORKSPACE_SANDBOX_LIMIT`: the workspace's own cap on running sandboxes
2260
+ * (`workspaces.setLimits`).
2261
+ * - `WORKSPACE_USAGE_LIMIT`: the workspace's apps and databases use as much CPU or memory as its
2262
+ * cap; {@link usage} and {@link limits} carry both.
2263
+ * Still a {@link LizardError}, so existing `catch` blocks keep working.
2264
+ */
2265
+ declare class LimitExceededError extends LizardError {
2266
+ /** The limit that was reached (sandbox counts). */
2267
+ limit?: number;
2268
+ /** How many were running when it was refused. */
2269
+ running?: number;
2270
+ /** Seconds until a rate limit lets the next start through. */
2271
+ retryAfterS?: number;
2272
+ /** `WORKSPACE_USAGE_LIMIT`: the workspace's current use. */
2273
+ usage?: {
2274
+ runningSandboxes: number;
2275
+ cpuVcpus: number;
2276
+ memoryMb: number;
2277
+ measuredAt: number | null;
2278
+ };
2279
+ /** `WORKSPACE_USAGE_LIMIT`: the workspace's limits. */
2280
+ limits?: {
2281
+ maxRunningSandboxes: number | null;
2282
+ maxCpuVcpus: number | null;
2283
+ maxMemoryMb: number | null;
2284
+ };
2285
+ constructor(message?: string);
2286
+ }
2212
2287
 
2213
2288
  /** A single output item produced during code execution. */
2214
2289
  type OutputItem = {
@@ -2384,4 +2459,4 @@ declare class LizardCLI {
2384
2459
  }): Promise<CLIResult>;
2385
2460
  }
2386
2461
 
2387
- export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CheckoutSession, type ClickOpts, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, Desktop, type DesktopInfo, type DesktopStartOpts, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type ExposedPort, type FileInfo, type ForkResult, type FsEvent, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, type MouseButton, NotFoundError, PaymentRequiredError, type Plan, PlatformClient, type ProcessInfo, type ProcessOpts, type ProcessResult, type ProcessSignal, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type PromoRedemption, type RawMetrics, type Region, RegionsAPI, type ResaleMultipliers, type ResalePricing, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type ScrollDirection, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotScope, type SnapshotWaitOpts, type StartCheckoutOpts, type StartProNowResult, StorageAPI, type StreamEvent, type Subscription, type SubscriptionStatus, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
2462
+ export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CheckoutSession, type ClickOpts, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, Desktop, type DesktopInfo, type DesktopStartOpts, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type ExposedPort, type FileInfo, type ForkResult, type FsEvent, type FsOpts, GitHubAPI, LimitExceededError, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, type MouseButton, NotFoundError, PaymentRequiredError, type Plan, PlatformClient, type ProcessInfo, type ProcessOpts, type ProcessResult, type ProcessSignal, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type PromoRedemption, type RawMetrics, type Region, RegionsAPI, type ResaleMultipliers, type ResalePricing, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type ScrollDirection, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotScope, type SnapshotWaitOpts, type StartCheckoutOpts, type StartProNowResult, StorageAPI, type StreamEvent, type Subscription, type SubscriptionStatus, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, type WorkspaceLimits, type WorkspaceLimitsInfo, type WorkspaceUsage, WorkspacesAPI, resolveProjectId };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ __export(index_exports, {
31
31
  Desktop: () => Desktop,
32
32
  DomainsAPI: () => DomainsAPI,
33
33
  GitHubAPI: () => GitHubAPI,
34
+ LimitExceededError: () => LimitExceededError,
34
35
  Lizard: () => Lizard,
35
36
  LizardCLI: () => LizardCLI,
36
37
  LizardError: () => LizardError,
@@ -126,6 +127,12 @@ var PaymentRequiredError = class extends LizardError {
126
127
  return this.billingUrl ?? this.subscribeUrl ?? this.topupUrl;
127
128
  }
128
129
  };
130
+ var LimitExceededError = class extends LizardError {
131
+ constructor(message = "Limit reached") {
132
+ super(message);
133
+ this.name = "LimitExceededError";
134
+ }
135
+ };
129
136
  var PREPAID_STATUSES = /* @__PURE__ */ new Set(["grace", "frozen", "card_required", "credits_required"]);
130
137
  var ERROR_CODE = /^[A-Z][A-Z0-9_]*$/;
131
138
  async function handleApiError(res) {
@@ -153,7 +160,17 @@ async function handleApiError(res) {
153
160
  else if (res.status === 404) err = new NotFoundError(message);
154
161
  else if (res.status === 409) err = new ConflictError(message);
155
162
  else if (res.status === 408 || res.status === 504) err = new TimeoutError(message);
156
- else err = new LizardError(`API error ${res.status}: ${message}`);
163
+ else if (res.status === 429) {
164
+ const limited = new LimitExceededError(message);
165
+ const n = (key) => typeof body[key] === "number" ? body[key] : void 0;
166
+ limited.limit = n("limit");
167
+ limited.running = n("running");
168
+ const retry = n("retryAfterS") ?? (Number(res.headers?.get?.("retry-after")) || void 0);
169
+ limited.retryAfterS = retry;
170
+ if (body.usage && typeof body.usage === "object") limited.usage = body.usage;
171
+ if (body.limits && typeof body.limits === "object") limited.limits = body.limits;
172
+ err = limited;
173
+ } else err = new LizardError(`API error ${res.status}: ${message}`);
157
174
  err.status = res.status;
158
175
  err.code = code;
159
176
  throw err;
@@ -1752,6 +1769,31 @@ var WorkspacesAPI = class {
1752
1769
  clearResalePricing(id) {
1753
1770
  return this.client.put(`/api/workspaces/${id}/resale-pricing`, {});
1754
1771
  }
1772
+ /**
1773
+ * The workspace's limits and what it uses now. Anyone in the workspace may read them,
1774
+ * including a key scoped to it (your customer sees how close they are).
1775
+ */
1776
+ getLimits(id) {
1777
+ return this.client.get(`/api/workspaces/${id}/limits`);
1778
+ }
1779
+ /**
1780
+ * Limit what a workspace may run at once (owner only, key with no scopes). A field left out
1781
+ * stays as it is; `null` removes that limit.
1782
+ *
1783
+ * - `maxRunningSandboxes`: a create, fork or resume past it fails with HTTP 429
1784
+ * `WORKSPACE_SANDBOX_LIMIT`.
1785
+ * - `maxCpuVcpus` / `maxMemoryMb`: what its apps and databases USE (measured every ~10 s,
1786
+ * not their configured limits). While at or over a cap, deploys, redeploys, restarts,
1787
+ * scale-ups, new databases and resumes there fail with HTTP 429 `WORKSPACE_USAGE_LIMIT`;
1788
+ * services already running keep running.
1789
+ *
1790
+ * ```ts
1791
+ * await lizard.workspaces.setLimits(ws.id, { maxRunningSandboxes: 5, maxCpuVcpus: 2, maxMemoryMb: 4096 })
1792
+ * ```
1793
+ */
1794
+ setLimits(id, limits) {
1795
+ return this.client.put(`/api/workspaces/${id}/limits`, limits);
1796
+ }
1755
1797
  /**
1756
1798
  * Delete a workspace.
1757
1799
  *
@@ -2664,6 +2706,7 @@ var LizardCLI = class {
2664
2706
  Desktop,
2665
2707
  DomainsAPI,
2666
2708
  GitHubAPI,
2709
+ LimitExceededError,
2667
2710
  Lizard,
2668
2711
  LizardCLI,
2669
2712
  LizardError,
package/dist/index.mjs CHANGED
@@ -73,6 +73,12 @@ var PaymentRequiredError = class extends LizardError {
73
73
  return this.billingUrl ?? this.subscribeUrl ?? this.topupUrl;
74
74
  }
75
75
  };
76
+ var LimitExceededError = class extends LizardError {
77
+ constructor(message = "Limit reached") {
78
+ super(message);
79
+ this.name = "LimitExceededError";
80
+ }
81
+ };
76
82
  var PREPAID_STATUSES = /* @__PURE__ */ new Set(["grace", "frozen", "card_required", "credits_required"]);
77
83
  var ERROR_CODE = /^[A-Z][A-Z0-9_]*$/;
78
84
  async function handleApiError(res) {
@@ -100,7 +106,17 @@ async function handleApiError(res) {
100
106
  else if (res.status === 404) err = new NotFoundError(message);
101
107
  else if (res.status === 409) err = new ConflictError(message);
102
108
  else if (res.status === 408 || res.status === 504) err = new TimeoutError(message);
103
- else err = new LizardError(`API error ${res.status}: ${message}`);
109
+ else if (res.status === 429) {
110
+ const limited = new LimitExceededError(message);
111
+ const n = (key) => typeof body[key] === "number" ? body[key] : void 0;
112
+ limited.limit = n("limit");
113
+ limited.running = n("running");
114
+ const retry = n("retryAfterS") ?? (Number(res.headers?.get?.("retry-after")) || void 0);
115
+ limited.retryAfterS = retry;
116
+ if (body.usage && typeof body.usage === "object") limited.usage = body.usage;
117
+ if (body.limits && typeof body.limits === "object") limited.limits = body.limits;
118
+ err = limited;
119
+ } else err = new LizardError(`API error ${res.status}: ${message}`);
104
120
  err.status = res.status;
105
121
  err.code = code;
106
122
  throw err;
@@ -1699,6 +1715,31 @@ var WorkspacesAPI = class {
1699
1715
  clearResalePricing(id) {
1700
1716
  return this.client.put(`/api/workspaces/${id}/resale-pricing`, {});
1701
1717
  }
1718
+ /**
1719
+ * The workspace's limits and what it uses now. Anyone in the workspace may read them,
1720
+ * including a key scoped to it (your customer sees how close they are).
1721
+ */
1722
+ getLimits(id) {
1723
+ return this.client.get(`/api/workspaces/${id}/limits`);
1724
+ }
1725
+ /**
1726
+ * Limit what a workspace may run at once (owner only, key with no scopes). A field left out
1727
+ * stays as it is; `null` removes that limit.
1728
+ *
1729
+ * - `maxRunningSandboxes`: a create, fork or resume past it fails with HTTP 429
1730
+ * `WORKSPACE_SANDBOX_LIMIT`.
1731
+ * - `maxCpuVcpus` / `maxMemoryMb`: what its apps and databases USE (measured every ~10 s,
1732
+ * not their configured limits). While at or over a cap, deploys, redeploys, restarts,
1733
+ * scale-ups, new databases and resumes there fail with HTTP 429 `WORKSPACE_USAGE_LIMIT`;
1734
+ * services already running keep running.
1735
+ *
1736
+ * ```ts
1737
+ * await lizard.workspaces.setLimits(ws.id, { maxRunningSandboxes: 5, maxCpuVcpus: 2, maxMemoryMb: 4096 })
1738
+ * ```
1739
+ */
1740
+ setLimits(id, limits) {
1741
+ return this.client.put(`/api/workspaces/${id}/limits`, limits);
1742
+ }
1702
1743
  /**
1703
1744
  * Delete a workspace.
1704
1745
  *
@@ -2610,6 +2651,7 @@ export {
2610
2651
  Desktop,
2611
2652
  DomainsAPI,
2612
2653
  GitHubAPI,
2654
+ LimitExceededError,
2613
2655
  Lizard,
2614
2656
  LizardCLI,
2615
2657
  LizardError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lizard-build/sdk",
3
- "version": "0.1.66",
3
+ "version": "0.1.68",
4
4
  "description": "TypeScript SDK for Lizard: Firecracker microVM sandboxes, code execution and cloud apps.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",