@lizard-build/sdk 0.1.35 → 0.1.36

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.ts CHANGED
@@ -271,6 +271,11 @@ interface SandboxInfo {
271
271
  template: string;
272
272
  startedAt: string;
273
273
  endAt: string;
274
+ /** Region the sandbox runs in — the volume's region when one is attached. */
275
+ region?: string;
276
+ status?: string;
277
+ cpus?: number;
278
+ memoryMb?: number;
274
279
  metadata?: Record<string, string>;
275
280
  }
276
281
  interface SandboxOpts extends ConnectionOpts {
@@ -287,6 +292,17 @@ interface SandboxOpts extends ConnectionOpts {
287
292
  metadata?: Record<string, string>;
288
293
  envs?: Record<string, string>;
289
294
  timeoutMs?: number;
295
+ /**
296
+ * Region to run the sandbox in, e.g. `'us-east-1'`.
297
+ *
298
+ * Leave it unset when attaching a volume: a volume is node-local, so the server
299
+ * places the sandbox in the volume's own region. Setting it to a region the volume
300
+ * is not in is rejected with a 400 rather than silently moved — that combination
301
+ * cannot be satisfied.
302
+ *
303
+ * Defaults to the platform's default sandbox region.
304
+ */
305
+ region?: string;
290
306
  /** Attach a persistent volume by id, mounted at `/data`. */
291
307
  volumeId?: string;
292
308
  /**
@@ -295,6 +311,27 @@ interface SandboxOpts extends ConnectionOpts {
295
311
  * Requires the sandbox's project to be given as an exact `projectId`.
296
312
  */
297
313
  volumeName?: string;
314
+ /**
315
+ * A `liz_` API key to write into the sandbox, so `lizard` works inside it. The CLI is
316
+ * preinstalled in every template; this is what authenticates it.
317
+ *
318
+ * The key must belong to the caller — the server verifies that and silently skips the
319
+ * injection otherwise.
320
+ *
321
+ * SECURITY: anything running in the sandbox can read this key, and sandboxes run
322
+ * untrusted code. Pass a WORKSPACE-SCOPED key rather than a full-access one. Scopes are
323
+ * enforced end to end, so a scoped key that escapes is bounded to that one workspace.
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * const sandbox = await Sandbox.create('codex', {
328
+ * projectId: 'proj_123',
329
+ * lizardToken: process.env.LIZARD_WORKSPACE_KEY, // scoped to one workspace
330
+ * })
331
+ * await sandbox.process.exec('lizard volume list')
332
+ * ```
333
+ */
334
+ lizardToken?: string;
298
335
  }
299
336
  /**
300
337
  * Low-level HTTP client for the Lizard sandbox API.
@@ -317,13 +354,15 @@ declare class SandboxClient {
317
354
  }
318
355
 
319
356
  /**
320
- * A Lizard sandbox — an isolated Firecracker microVM that boots in milliseconds.
357
+ * A Lizard sandbox — an isolated Linux environment that starts in under a second.
358
+ *
359
+ * Each sandbox is a full Linux environment with its own filesystem, network, and
360
+ * process namespace, restored from a pre-warmed template snapshot.
321
361
  *
322
- * Each sandbox is a full Linux environment with its own filesystem, network,
323
- * and process namespace. Sandboxes are spun up from templates and can be
324
- * paused — vCPUs frozen, memory and running processes kept — then resumed
325
- * instantly, perfect for stateful AI agent sessions or ephemeral code
326
- * execution.
362
+ * Sandboxes are **ephemeral**: killing one, or letting it hit its timeout, discards
363
+ * everything written inside it. State that has to outlive a sandbox belongs on a
364
+ * {@link Volume}, which is a separate disk you mount at `/data` and re-attach to a
365
+ * later sandbox.
327
366
  *
328
367
  * @example Basic usage:
329
368
  * ```ts
@@ -336,16 +375,18 @@ declare class SandboxClient {
336
375
  * await sandbox.kill()
337
376
  * ```
338
377
  *
339
- * @example Pause and resume a long-running session:
378
+ * @example Carry work across sandboxes with a volume:
340
379
  * ```ts
341
- * const sandbox = await Sandbox.create('code-interpreter-v1', { project: 'my-project' })
342
- * await sandbox.process.exec('pip install numpy')
343
- * const id = sandbox.sandboxId
344
- * await sandbox.pause()
380
+ * const vol = await Volume.getOrCreate(projectId, 'agent-scratch', { sizeGb: 10 })
345
381
  *
346
- * // Later — resume exactly where it left off:
347
- * const resumed = await Sandbox.connect(id)
348
- * await resumed.process.exec('python -c "import numpy; print(numpy.__version__)"')
382
+ * const first = await Sandbox.create('codex', { projectId, volumeName: 'agent-scratch' })
383
+ * await first.process.exec('echo "notes" > /data/notes.txt')
384
+ * await first.kill()
385
+ *
386
+ * // A different sandbox, the same disk. No region to thread through: the sandbox
387
+ * // is placed wherever the volume already lives.
388
+ * const second = await Sandbox.create('codex', { projectId, volumeName: 'agent-scratch' })
389
+ * console.log(await second.fs.read('/data/notes.txt')) // "notes"
349
390
  * ```
350
391
  */
351
392
  declare class Sandbox extends SandboxClient {
@@ -406,8 +447,14 @@ declare class Sandbox extends SandboxClient {
406
447
  /**
407
448
  * Connect to an existing sandbox by its ID.
408
449
  *
409
- * If the sandbox is currently paused, it will be automatically resumed
410
- * before this call returns.
450
+ * Verifies the sandbox exists and is reachable, then returns a handle to it.
451
+ * Throws `NotFoundError` if it has been killed or has expired.
452
+ *
453
+ * This used to call `resume` first, on the assumption that a sandbox you are
454
+ * reconnecting to might be paused. Sandboxes are pods now and pause/resume is a
455
+ * `501` on every one of them, so that call turned every `connect()` into an
456
+ * error against a perfectly healthy sandbox. Connecting does not need to change
457
+ * a sandbox's state, so it no longer tries to.
411
458
  *
412
459
  * @example
413
460
  * ```ts
@@ -431,35 +478,21 @@ declare class Sandbox extends SandboxClient {
431
478
  */
432
479
  kill(opts?: ConnectionOpts): Promise<boolean>;
433
480
  /**
434
- * Pause the sandbox microVM by freezing its vCPUs.
481
+ * Pause the sandbox by freezing it in place.
435
482
  *
436
- * Memory, filesystem, and running processes are held in the host's RAM —
437
- * nothing is written to disk, so a paused sandbox does not survive a host
438
- * failure. Resume with `sandbox.resume()` or `Sandbox.connect(id)`.
439
- *
440
- * Pausing does not buy you time past the original deadline. Resuming pushes the
441
- * expiry forward by however long the sandbox was paused — so a pause/resume cycle
442
- * costs no runtime — but that adjustment only happens on `resume()`. A sandbox left
443
- * paused past its original `expiresAt` is deleted there, within a minute, and
444
- * `resume()` then returns `false`.
445
- *
446
- * In other words: pause and come back *before* the original deadline and you lose
447
- * nothing; leave it paused across the deadline and it is gone. Pass `timeoutMs: 0`
448
- * at create time to opt out of expiry entirely, which is the only way to park a
449
- * sandbox indefinitely.
450
- *
451
- * @returns `true` if paused successfully.
483
+ * @deprecated Not implemented for the current runtime — always throws
484
+ * `LizardError` with HTTP 501. Sandboxes run as pods, and the equivalent is a CRIU
485
+ * checkpoint of the pod, which is not built. To park work across a gap, put it on a
486
+ * {@link Volume} and create a fresh sandbox on that volume later; the volume is the
487
+ * part that is meant to outlive a sandbox.
452
488
  */
453
489
  pause(opts?: ConnectionOpts): Promise<boolean>;
454
490
  /**
455
- * Resume a paused sandbox by unfreezing its vCPUs.
456
- *
457
- * The expiry is pushed forward by the time spent paused, so the timeout measures
458
- * running time rather than wall-clock — provided the original deadline had not
459
- * already passed while paused. See {@link pause}.
491
+ * Resume a paused sandbox.
460
492
  *
461
- * @returns `true` if resumed successfully, `false` if the sandbox no longer exists
462
- * (including because it expired while paused).
493
+ * @deprecated Not implemented for the current runtime — always throws
494
+ * `LizardError` with HTTP 501. See {@link pause}. `Sandbox.connect()` no longer
495
+ * calls this, so reconnecting to a running sandbox works without it.
463
496
  */
464
497
  resume(opts?: ConnectionOpts): Promise<boolean>;
465
498
  /**
@@ -851,6 +884,304 @@ declare class MetricsAPI {
851
884
  all(id: string, range?: MetricRange): Promise<ServiceMetrics>;
852
885
  }
853
886
 
887
+ interface Workspace {
888
+ id: string;
889
+ name: string;
890
+ slug: string;
891
+ /** `owner` | `admin` | `member` — the calling account's role in this workspace. */
892
+ role?: string;
893
+ /** True for the account's own workspace, which cannot be deleted. */
894
+ isPersonal?: boolean;
895
+ projectCount?: number;
896
+ plan?: string;
897
+ createdAt?: number | string;
898
+ }
899
+ interface CreateWorkspaceOpts {
900
+ name: string;
901
+ }
902
+ /**
903
+ * Workspaces — the top of the ownership tree: a workspace holds projects, a project
904
+ * holds services, sandboxes and volumes.
905
+ *
906
+ * This is the missing first step of per-user provisioning. Handing each of your users
907
+ * their own workspace, plus an API key scoped to it, is what keeps them isolated from
908
+ * one another while all of it bills to your account:
909
+ *
910
+ * ```ts
911
+ * const ws = await lizard.workspaces.create({ name: `user-${userId}` })
912
+ * const prj = await lizard.projects.create({ workspaceId: ws.id, name: 'default' })
913
+ * const key = await lizard.apiKeys.create({ name: `user-${userId}`, workspaces: [ws.id] })
914
+ * // hand key.key to that user — it reaches nothing outside ws
915
+ * ```
916
+ *
917
+ * @see {@link ApiKeysAPI} for the scoping half of that flow.
918
+ */
919
+ declare class WorkspacesAPI {
920
+ private readonly client;
921
+ constructor(client: PlatformClient);
922
+ /**
923
+ * List workspaces the calling credential can see.
924
+ *
925
+ * A scoped API key sees only what it is scoped to: a workspace-scoped key returns
926
+ * that one workspace, and a project-scoped key returns the workspace containing its
927
+ * project. A full key returns every workspace the account belongs to.
928
+ */
929
+ list(): Promise<Workspace[]>;
930
+ /** Create a workspace. The caller becomes its owner. */
931
+ create(opts: CreateWorkspaceOpts): Promise<Workspace>;
932
+ /**
933
+ * Delete a workspace.
934
+ *
935
+ * Empty-only by default — the server refuses while any project or sandbox remains,
936
+ * so this cannot quietly destroy a user's work. Pass `{ force: true }` to delete a
937
+ * workspace and everything in it; that is irreversible.
938
+ */
939
+ delete(id: string, opts?: {
940
+ force?: boolean;
941
+ }): Promise<void>;
942
+ /**
943
+ * Find a workspace by name, slug, or id, or `null` if there is no such workspace.
944
+ * Matching is exact; id wins, then slug, then name.
945
+ */
946
+ find(nameOrSlugOrId: string): Promise<Workspace | null>;
947
+ }
948
+
949
+ interface ApiKeyScope {
950
+ type: 'workspace' | 'project';
951
+ id: string;
952
+ /** Present on read; the server resolves the scoped resource's name for display. */
953
+ name?: string;
954
+ }
955
+ interface ApiKey {
956
+ id: string;
957
+ name: string;
958
+ /** A masked fragment, e.g. `liz_abc…xyz`. The full key is only ever returned once. */
959
+ keyPreview?: string;
960
+ scopes: ApiKeyScope[];
961
+ createdAt?: number | string | null;
962
+ lastUsedAt?: number | string | null;
963
+ }
964
+ interface CreatedApiKey extends ApiKey {
965
+ /**
966
+ * The full `liz_` secret. **Returned exactly once, by this create call** — it is
967
+ * stored hashed and no later request can read it back. Hand it to its owner or
968
+ * persist it here, or it is gone.
969
+ */
970
+ key: string;
971
+ }
972
+ interface CreateApiKeyOpts {
973
+ name: string;
974
+ /** Workspace ids this key may reach. */
975
+ workspaces?: string[];
976
+ /** Project ids this key may reach. */
977
+ projects?: string[];
978
+ /** Raw scope list, if you would rather build it yourself than use the two above. */
979
+ scopes?: ApiKeyScope[];
980
+ }
981
+ /**
982
+ * API keys, including the scoped keys that make per-user isolation possible.
983
+ *
984
+ * **A key with no scope has full access** to every workspace and project the creating
985
+ * account can reach. Pass `workspaces` or `projects` to bound it. Scopes are enforced
986
+ * server-side on every route, so a scoped key that leaks — out of a sandbox, a log, a
987
+ * user's machine — reaches only what it was scoped to.
988
+ *
989
+ * A scoped key cannot mint a broader key: that check is server-side and exact, so
990
+ * handing a user a workspace-scoped key is not a step away from full access.
991
+ *
992
+ * @example Give each of your users their own isolated workspace
993
+ * ```ts
994
+ * const ws = await lizard.workspaces.create({ name: `user-${userId}` })
995
+ * const prj = await lizard.projects.create({ workspaceId: ws.id, name: 'default' })
996
+ * const key = await lizard.apiKeys.create({ name: `user-${userId}`, workspaces: [ws.id] })
997
+ *
998
+ * // key.key is visible only here. Store it now.
999
+ * await db.users.update(userId, { lizardKey: key.key })
1000
+ * ```
1001
+ *
1002
+ * @example Let a sandbox use the CLI as that user, and nothing more
1003
+ * ```ts
1004
+ * const sandbox = await Sandbox.create('codex', {
1005
+ * projectId: prj.id,
1006
+ * lizardToken: key.key, // scoped — safe to expose to code in the sandbox
1007
+ * })
1008
+ * await sandbox.process.exec('lizard volume list')
1009
+ * ```
1010
+ */
1011
+ declare class ApiKeysAPI {
1012
+ private readonly client;
1013
+ constructor(client: PlatformClient);
1014
+ /** List the account's API keys. Previews only — full keys are never returned here. */
1015
+ list(): Promise<ApiKey[]>;
1016
+ /**
1017
+ * Create an API key.
1018
+ *
1019
+ * The response is the only place the full key appears. Omitting every scope creates
1020
+ * a full-access key; the server rejects an attempt to create one from a key that is
1021
+ * itself scoped.
1022
+ */
1023
+ create(opts: CreateApiKeyOpts): Promise<CreatedApiKey>;
1024
+ /** Revoke a key by id. It stops working immediately, everywhere. */
1025
+ delete(id: string): Promise<void>;
1026
+ }
1027
+
1028
+ interface Region {
1029
+ id: string;
1030
+ name?: string;
1031
+ label?: string;
1032
+ country?: string;
1033
+ city?: string;
1034
+ /** False for a region that exists but is not accepting new workloads. */
1035
+ available?: boolean;
1036
+ isDefault?: boolean;
1037
+ }
1038
+ /**
1039
+ * The regions workloads can be placed in.
1040
+ *
1041
+ * Region ids are what `Sandbox.create({ region })` and `Volume.create({ region })`
1042
+ * take, so this is how you discover a valid value rather than hardcoding one.
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * const regions = await lizard.regions.list()
1047
+ * console.log(regions.map(r => r.id)) // ['eu-west-lim-a', 'us-east-1', ...]
1048
+ * ```
1049
+ */
1050
+ declare class RegionsAPI {
1051
+ private readonly client;
1052
+ constructor(client: PlatformClient);
1053
+ /** List every region, including ones not currently accepting workloads. */
1054
+ list(): Promise<Region[]>;
1055
+ }
1056
+
1057
+ interface Balance {
1058
+ plan: string;
1059
+ status: 'active' | 'grace' | 'frozen' | string;
1060
+ /** Current balance in cents. Negative means the account is in debt. */
1061
+ balanceCents: number;
1062
+ overdraftLimitCents: number | null;
1063
+ availableCents: number | null;
1064
+ /** Current burn rate in cents per hour, across every running workload. */
1065
+ hourlyRateCents: number;
1066
+ /** Hours of runway left at the current rate, or `null` when nothing is running. */
1067
+ runwayHours: number | null;
1068
+ expiringCents: number;
1069
+ expiringAt: number | null;
1070
+ neverFreeze?: boolean;
1071
+ invoicedMonthly?: boolean;
1072
+ email?: string | null;
1073
+ }
1074
+ interface Transaction {
1075
+ id: string;
1076
+ kind: string;
1077
+ amountCents: number;
1078
+ balanceAfterCents?: number;
1079
+ description?: string;
1080
+ createdAt: number;
1081
+ }
1082
+ interface TransactionPage {
1083
+ items: Transaction[];
1084
+ nextCursor: string | null;
1085
+ }
1086
+ interface ListTransactionsOpts {
1087
+ /** 1-100, default 20. */
1088
+ limit?: number;
1089
+ /** `nextCursor` from a previous page. */
1090
+ cursor?: string;
1091
+ /** Include the daily usage-deduction rows, which are otherwise omitted as noise. */
1092
+ includeUsage?: boolean;
1093
+ }
1094
+ /**
1095
+ * Account balance and usage.
1096
+ *
1097
+ * Billing is **account-scoped, not workspace-scoped**: every workspace you create for
1098
+ * a user bills to the account that owns the key. That is what makes per-user
1099
+ * workspaces a safe pattern — your users get isolation, you keep one bill — and also
1100
+ * what makes {@link Balance.runwayHours} worth watching before you provision more.
1101
+ */
1102
+ declare class BillingAPI {
1103
+ private readonly client;
1104
+ constructor(client: PlatformClient);
1105
+ /** Current balance, status, burn rate, and runway. */
1106
+ balance(): Promise<Balance>;
1107
+ /** A page of balance transactions, newest first. */
1108
+ transactions(opts?: ListTransactionsOpts): Promise<TransactionPage>;
1109
+ /** Cost summary for the current billing period, broken down by resource. */
1110
+ summary(): Promise<unknown>;
1111
+ /** Live (not-yet-invoiced) usage accumulating right now. */
1112
+ live(): Promise<unknown>;
1113
+ }
1114
+
1115
+ interface VolumeInfo {
1116
+ id: string;
1117
+ projectId: string;
1118
+ name: string;
1119
+ sizeGb: number;
1120
+ sizeMb?: number;
1121
+ /** Region the volume's node lives in. A sandbox mounting it runs here too. */
1122
+ region?: string;
1123
+ status: string;
1124
+ attachedTo?: string | null;
1125
+ createdAt: number;
1126
+ }
1127
+ interface CreateVolumeOpts extends ConnectionOpts {
1128
+ sizeGb?: number;
1129
+ /**
1130
+ * Region to place the volume in, e.g. `'us-east-1'`. A volume is node-local, so
1131
+ * this also fixes where any sandbox mounting it must run — `Sandbox.create` takes
1132
+ * the volume's region automatically when you don't name one, so you normally set
1133
+ * the region here or nowhere.
1134
+ *
1135
+ * Defaults to the platform's default region.
1136
+ */
1137
+ region?: string;
1138
+ }
1139
+ /**
1140
+ * A persistent volume that outlives sandboxes.
1141
+ *
1142
+ * A volume's **name** is its key inside a project: names are unique per project, and
1143
+ * every method here accepts either a name or the generated id wherever a volume is
1144
+ * addressed. Prefer the name — it is the thing you chose and can reconstruct, while
1145
+ * the id only exists after the first create.
1146
+ *
1147
+ * Names are slugs: lowercase letters, digits and dashes, starting and ending with a
1148
+ * letter or digit, up to 64 characters.
1149
+ *
1150
+ * Mount one to a sandbox via `Sandbox.create({ volumeName: 'my-data' })`.
1151
+ */
1152
+ declare class Volume {
1153
+ /** The volume's generated id. Stable, but you rarely need it — address by name. */
1154
+ readonly volumeId: string;
1155
+ /** The volume's name: unique within its project, and usable anywhere `volumeId` is. */
1156
+ readonly name?: string;
1157
+ private readonly config;
1158
+ constructor(opts: {
1159
+ volumeId: string;
1160
+ name?: string;
1161
+ } & ConnectionOpts);
1162
+ /**
1163
+ * Create a volume. Throws `ConflictError` (409) if the project already has one with
1164
+ * this name — use {@link getOrCreate} when you want "make sure this exists" instead.
1165
+ */
1166
+ static create(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
1167
+ /**
1168
+ * Return the project's volume with this name, creating it first if it does not
1169
+ * exist yet. This is the reason a volume's name is its key: an agent that wants
1170
+ * "the scratch disk for this task" no longer has to store an id between runs.
1171
+ *
1172
+ * An existing volume is returned as-is — `sizeGb` applies only to a fresh create
1173
+ * and never resizes one that is already there.
1174
+ */
1175
+ static getOrCreate(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
1176
+ /** Look a volume up by name or by id. */
1177
+ static get(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<Volume>;
1178
+ static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
1179
+ /** Delete a volume by name or by id, without constructing one first. */
1180
+ static delete(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<void>;
1181
+ getInfo(projectId: string): Promise<VolumeInfo>;
1182
+ delete(projectId: string): Promise<void>;
1183
+ }
1184
+
854
1185
  interface LizardOpts extends ConnectionOpts {
855
1186
  /**
856
1187
  * The project every sandbox created through this client belongs to — its ID,
@@ -892,6 +1223,14 @@ declare class Lizard {
892
1223
  private readonly config;
893
1224
  private readonly projectRef;
894
1225
  private _platform;
1226
+ /** Create, list and delete workspaces — the top of the ownership tree. */
1227
+ readonly workspaces: WorkspacesAPI;
1228
+ /** Mint and revoke API keys, including keys scoped to one workspace or project. */
1229
+ readonly apiKeys: ApiKeysAPI;
1230
+ /** List the regions workloads can be placed in. */
1231
+ readonly regions: RegionsAPI;
1232
+ /** Account balance, burn rate and transactions. */
1233
+ readonly billing: BillingAPI;
895
1234
  /** Manage projects. */
896
1235
  readonly projects: ProjectsAPI;
897
1236
  /** Deploy and manage services. */
@@ -913,10 +1252,51 @@ declare class Lizard {
913
1252
  * @requires `project` to be set in the constructor.
914
1253
  */
915
1254
  create(template?: string, opts?: Omit<SandboxOpts, 'project' | 'projectId'>): Promise<Sandbox>;
916
- /** Connect to an existing sandbox by ID (resumes it if paused). */
1255
+ /** Connect to an existing sandbox by ID. Throws `NotFoundError` if it is gone. */
917
1256
  connect(sandboxId: string, opts?: ConnectionOpts): Promise<Sandbox>;
918
1257
  /** List running sandboxes for the authenticated account. */
919
1258
  list(opts?: ConnectionOpts): Promise<SandboxInfo[]>;
1259
+ /**
1260
+ * Persistent volumes in this client's project.
1261
+ *
1262
+ * The same calls as the static {@link Volume} methods, minus the `projectId`
1263
+ * argument — the client already knows it.
1264
+ *
1265
+ * @requires `project` to be set in the constructor.
1266
+ *
1267
+ * @example
1268
+ * ```ts
1269
+ * const lizard = new Lizard({ project: 'my-project' })
1270
+ * const vol = await lizard.volumes.getOrCreate('scratch', { sizeGb: 10 })
1271
+ * const sb = await lizard.create('codex', { volumeName: 'scratch' })
1272
+ * ```
1273
+ */
1274
+ readonly volumes: {
1275
+ create: (name: string, opts?: CreateVolumeOpts) => Promise<Volume>;
1276
+ getOrCreate: (name: string, opts?: CreateVolumeOpts) => Promise<Volume>;
1277
+ get: (nameOrId: string, opts?: ConnectionOpts) => Promise<Volume>;
1278
+ list: (opts?: ConnectionOpts) => Promise<VolumeInfo[]>;
1279
+ delete: (nameOrId: string, opts?: ConnectionOpts) => Promise<void>;
1280
+ };
1281
+ /**
1282
+ * The account this credential belongs to — the SDK's `lizard whoami`.
1283
+ *
1284
+ * Works for a scoped key as well as a full one: the identity is the account that
1285
+ * created the key, which is what the key's usage bills to.
1286
+ */
1287
+ whoami(): Promise<Account>;
1288
+ /** The underlying HTTP client, for endpoints this SDK does not wrap yet. */
1289
+ get platform(): PlatformClient;
1290
+ }
1291
+ /** The account behind a credential — see {@link Lizard.whoami}. */
1292
+ interface Account {
1293
+ id: string;
1294
+ username: string;
1295
+ email?: string | null;
1296
+ avatarUrl?: string | null;
1297
+ plan?: string;
1298
+ billingStatus?: string;
1299
+ balanceCents?: number;
920
1300
  }
921
1301
 
922
1302
  /**
@@ -1099,63 +1479,4 @@ declare class CodeSandbox extends Sandbox {
1099
1479
  static connect(sandboxId: string, opts?: ConnectionOpts): Promise<CodeSandbox>;
1100
1480
  }
1101
1481
 
1102
- interface VolumeInfo {
1103
- id: string;
1104
- projectId: string;
1105
- name: string;
1106
- sizeGb: number;
1107
- sizeMb?: number;
1108
- status: string;
1109
- attachedTo?: string | null;
1110
- createdAt: number;
1111
- }
1112
- interface CreateVolumeOpts extends ConnectionOpts {
1113
- sizeGb?: number;
1114
- }
1115
- /**
1116
- * A persistent volume that outlives sandboxes.
1117
- *
1118
- * A volume's **name** is its key inside a project: names are unique per project, and
1119
- * every method here accepts either a name or the generated id wherever a volume is
1120
- * addressed. Prefer the name — it is the thing you chose and can reconstruct, while
1121
- * the id only exists after the first create.
1122
- *
1123
- * Names are slugs: lowercase letters, digits and dashes, starting and ending with a
1124
- * letter or digit, up to 64 characters.
1125
- *
1126
- * Mount one to a sandbox via `Sandbox.create({ volumeName: 'my-data' })`.
1127
- */
1128
- declare class Volume {
1129
- /** The volume's generated id. Stable, but you rarely need it — address by name. */
1130
- readonly volumeId: string;
1131
- /** The volume's name: unique within its project, and usable anywhere `volumeId` is. */
1132
- readonly name?: string;
1133
- private readonly config;
1134
- constructor(opts: {
1135
- volumeId: string;
1136
- name?: string;
1137
- } & ConnectionOpts);
1138
- /**
1139
- * Create a volume. Throws `ConflictError` (409) if the project already has one with
1140
- * this name — use {@link getOrCreate} when you want "make sure this exists" instead.
1141
- */
1142
- static create(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
1143
- /**
1144
- * Return the project's volume with this name, creating it first if it does not
1145
- * exist yet. This is the reason a volume's name is its key: an agent that wants
1146
- * "the scratch disk for this task" no longer has to store an id between runs.
1147
- *
1148
- * An existing volume is returned as-is — `sizeGb` applies only to a fresh create
1149
- * and never resizes one that is already there.
1150
- */
1151
- static getOrCreate(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
1152
- /** Look a volume up by name or by id. */
1153
- static get(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<Volume>;
1154
- static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
1155
- /** Delete a volume by name or by id, without constructing one first. */
1156
- static delete(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<void>;
1157
- getInfo(projectId: string): Promise<VolumeInfo>;
1158
- delete(projectId: string): Promise<void>;
1159
- }
1160
-
1161
- export { type Addon, type AddonType, AuthenticationError, type CodeContext, CodeSandbox, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type DeployEvent, DeployHandle, type DomainInfo, Execution, ExecutionError, type FileInfo, type FsOpts, Lizard, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, NotFoundError, type ProcessOpts, type ProcessResult, type Project, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type ScaleOpts, type Secret, type Service, type ServiceMetrics, type SetSecretOpts, TimeoutError, Volume, type VolumeInfo, resolveProjectId };
1482
+ export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CodeContext, CodeSandbox, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, type DomainInfo, DomainsAPI, Execution, ExecutionError, type FileInfo, type FsOpts, type ListTransactionsOpts, Lizard, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, NotFoundError, PlatformClient, type ProcessOpts, type ProcessResult, type Project, ProjectsAPI, type Region, RegionsAPI, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type ScaleOpts, type Secret, SecretsAPI, type Service, type ServiceMetrics, ServicesAPI, type SetSecretOpts, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };