@gjermundgaraba/clankerbox-sdk 0.18.2 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,20 +24,31 @@ var NotFound = class extends Schema.TaggedError()("NotFound", {
24
24
  message: Schema.String,
25
25
  ...located
26
26
  }, { httpApiStatus: 404 }) {};
27
- const ConflictKind = Schema.Literals(["exists", "busy"]);
28
- /** The name is taken (`exists`), or another action holds the resource (`busy`). */
27
+ /** The name is taken. */
29
28
  var Conflict = class extends Schema.TaggedError()("Conflict", {
30
29
  message: Schema.String,
31
- kind: ConflictKind,
32
30
  ...located
33
31
  }, { httpApiStatus: 409 }) {};
32
+ /**
33
+ * A later request on the machine replaced this one before the host got there: `by` is what that
34
+ * request asked for. The machine's own state says where it is now.
35
+ */
36
+ var Superseded = class extends Schema.TaggedError()("Superseded", {
37
+ message: Schema.String,
38
+ ...located,
39
+ by: Schema.Literals([
40
+ "running",
41
+ "stopped",
42
+ "deleted"
43
+ ])
44
+ }, { httpApiStatus: 409 }) {};
34
45
  /** No host offers `base`: the host a create names, or any in the client's list. */
35
46
  var NotOffered = class extends Schema.TaggedError()("NotOffered", {
36
47
  message: Schema.String,
37
48
  ...located,
38
49
  base: Schema.String
39
50
  }, { httpApiStatus: 412 }) {};
40
- /** `machine`'s create, fork or restore failed before it was made: it can only be deleted. */
51
+ /** `machine` isn't made yet: its create or setup still runs, so it can't be copied or captured. */
41
52
  var NotMade = class extends Schema.TaggedError()("NotMade", {
42
53
  message: Schema.String,
43
54
  ...located,
@@ -49,12 +60,6 @@ var Missing = class extends Schema.TaggedError()("Missing", {
49
60
  ...located,
50
61
  machine: Schema.String
51
62
  }, { httpApiStatus: 412 }) {};
52
- /** `checkpoint`'s capture failed, so nothing restores from it: it can only be deleted. */
53
- var NotReady = class extends Schema.TaggedError()("NotReady", {
54
- message: Schema.String,
55
- ...located,
56
- checkpoint: Schema.String
57
- }, { httpApiStatus: 412 }) {};
58
63
  /** `checkpoint` holds RAM state saved under another runtime pin than the one the host runs. */
59
64
  var PinMismatch = class extends Schema.TaggedError()("PinMismatch", {
60
65
  message: Schema.String,
@@ -75,12 +80,13 @@ var Unsizable = class extends Schema.TaggedError()("Unsizable", {
75
80
  }, { httpApiStatus: 422 }) {};
76
81
  /**
77
82
  * A guest script exited non-zero or ran past its timeout; the message says which, with its
78
- * output's tail. A failed `setup` leaves the machine unmade, a failed `preparation` made.
83
+ * output's tail, and `script` names it: a failed `setup` deletes the machine, and a failed
84
+ * `preparation` runs again on the next start.
79
85
  */
80
86
  var ScriptFailed = class extends Schema.TaggedError()("ScriptFailed", {
81
87
  message: Schema.String,
82
88
  ...located,
83
- script: Schema.Literals(["setup", "preparation"])
89
+ script: Schema.String
84
90
  }, { httpApiStatus: 422 }) {};
85
91
  /** The provider under the runtime refused the call for good, such as for its plan or API key. */
86
92
  var Refused = class extends Schema.TaggedError()("Refused", {
@@ -110,10 +116,10 @@ const hostErrors = [
110
116
  Invalid,
111
117
  NotFound,
112
118
  Conflict,
119
+ Superseded,
113
120
  NotOffered,
114
121
  NotMade,
115
122
  Missing,
116
- NotReady,
117
123
  PinMismatch,
118
124
  WrongState,
119
125
  Unsizable,
@@ -126,22 +132,24 @@ const HostError = Schema.Union(hostErrors);
126
132
  /**
127
133
  * Each carries, where known: `host` and `action`, which the client sets; `id`, the resource the
128
134
  * error is about, which a host sets on `NotFound` and `Conflict` and the client sets to the call's
129
- * subject otherwise; and `made`, the resource a create, fork, restore or capture makes, which a
130
- * failure may leave behind.
135
+ * subject otherwise; and `made`, the resource a create, fork, restore or capture makes. The host
136
+ * deletes a machine whose copy or setup fails, again at each recheck while that delete fails, and
137
+ * keeps one whose preparation fails; a call whose answer was lost, `Unavailable`, may leave
138
+ * `made` behind unmade.
131
139
  */
132
140
  const ClankerboxError = Schema.Union([...hostErrors, Unavailable]);
133
141
  /**
134
- * Whether the same call may succeed later: a busy resource or a full host may free up, and a read
135
- * that got no reply may get one.
142
+ * Whether the same call may succeed later: a full host may free up, and a read that got no reply
143
+ * may get one.
136
144
  */
137
145
  const retryable = (error) => Match.value(error).pipe(Match.tagsExhaustive({
138
146
  Invalid: () => false,
139
147
  NotFound: () => false,
140
- Conflict: ({ kind }) => kind === "busy",
148
+ Conflict: () => false,
149
+ Superseded: () => false,
141
150
  NotOffered: () => false,
142
151
  NotMade: () => false,
143
152
  Missing: () => false,
144
- NotReady: () => false,
145
153
  PinMismatch: () => false,
146
154
  WrongState: () => false,
147
155
  Unsizable: () => false,
@@ -196,31 +204,31 @@ const Runtime = Schema.Literals([
196
204
  "boat"
197
205
  ]);
198
206
  const Size = Schema.Int.check(Schema.isGreaterThan(0));
199
- /** The contract's mutations, which record themselves on a resource's `action`. */
200
- const ActionName = Schema.Literals([
201
- "createMachine",
202
- "startMachine",
203
- "stopMachine",
204
- "deleteMachine",
205
- "forkMachine",
206
- "restoreMachine",
207
- "captureCheckpoint",
208
- "deleteCheckpoint"
209
- ]);
210
- const ActionStatus = Schema.Literals([
207
+ /** What the operator asked a machine to be; the host keeps moving the machine toward it. */
208
+ const Desired = Schema.Literals([
211
209
  "running",
210
+ "stopped",
211
+ "deleted"
212
+ ]);
213
+ /**
214
+ * What the host is doing about a machine. A request waits for a rest: `settled`, at rest with what
215
+ * was asked; `failed`, after a step failed, until the next request; `lost`, one the runtime no
216
+ * longer has, which can only be deleted; and `waiting`, one the runtime can't read, which fails the
217
+ * request and is read again at the host's next recheck. `creating` copies the machine and runs its
218
+ * setup, and a machine whose create or setup fails is deleted. `starting` starts the machine, also
219
+ * when it runs already, and prepares it.
220
+ */
221
+ const Phase = Schema.Literals([
222
+ "observing",
223
+ "waiting",
224
+ "creating",
225
+ "starting",
226
+ "stopping",
227
+ "deleting",
228
+ "settled",
212
229
  "failed",
213
- "done"
230
+ "lost"
214
231
  ]);
215
- /** A resource's last action; the next action replaces it. */
216
- const ActionRecord = Schema.Union([Schema.Struct({
217
- name: ActionName,
218
- status: Schema.Literals(["running", "done"])
219
- }), Schema.Struct({
220
- name: ActionName,
221
- status: Schema.Literal("failed"),
222
- error: HostError
223
- })]);
224
232
  const SshEndpoint = Schema.Struct({
225
233
  host: Schema.String,
226
234
  port: Schema.Int.check(Schema.isBetween({
@@ -233,10 +241,30 @@ const SshLogin = Schema.Struct({
233
241
  ...SshEndpoint.fields
234
242
  });
235
243
  /**
236
- * `state` is `missing` when the runtime doesn't have the machine, and `unknown` when it couldn't
237
- * be read. Until its create, fork or restore has `made` it, a machine can only be read, stopped or
238
- * deleted. `ssh` is only on a running machine whose runtime gives it an endpoint, and `hostKey`,
239
- * `<type> <base64>`, once preparation has recorded it.
244
+ * A running machine's place on the tailnet, as the host last checked it: `joined` once
245
+ * `tailscaled` runs signed in, with the MagicDNS name Tailscale gave it, if any; `failed` with
246
+ * why; or `missing` when the guest has no `tailscaled`. Kept in the host's memory only: each start
247
+ * checks again, a joined machine is checked again every half hour or so, and a failed one sooner,
248
+ * waiting longer after each failure.
249
+ */
250
+ const TailnetStatus = Schema.Union([
251
+ Schema.Struct({
252
+ state: Schema.Literal("joined"),
253
+ name: Schema.optionalKey(Schema.String)
254
+ }),
255
+ Schema.Struct({
256
+ state: Schema.Literal("failed"),
257
+ error: Schema.String
258
+ }),
259
+ Schema.Struct({ state: Schema.Literal("missing") })
260
+ ]).annotate({ identifier: "TailnetStatus" });
261
+ /**
262
+ * `state` is what the runtime reports: `missing` when it doesn't have the machine, and `unknown`
263
+ * when it couldn't be read. `desired` is what the last request asked for, `phase` what the host is
264
+ * doing about it, and `error` why the last step failed, until the next request. `ssh` is only
265
+ * on a running machine whose runtime gives it an endpoint, and `hostKey`, `<type> <base64>`, once
266
+ * preparation has recorded it. `tailnet` is on a running machine of a host that joins its machines
267
+ * to a tailnet, once the host has checked it.
240
268
  */
241
269
  const Machine = Schema.Struct({
242
270
  id: Id,
@@ -253,14 +281,22 @@ const Machine = Schema.Struct({
253
281
  "missing",
254
282
  "unknown"
255
283
  ]),
256
- made: Schema.Boolean,
257
- action: ActionRecord,
284
+ desired: Desired,
285
+ phase: Phase,
286
+ error: Schema.optionalKey(HostError),
258
287
  ssh: Schema.optionalKey(SshLogin),
259
- hostKey: Schema.optionalKey(Schema.String)
288
+ hostKey: Schema.optionalKey(Schema.String),
289
+ tailnet: Schema.optionalKey(TailnetStatus)
260
290
  }).annotate({ identifier: "Machine" });
261
- /** The state as people read it: `running`, or `stopped (unmade)` for one never made. */
262
- const stateLabel = ({ state, made }) => made ? state : `${state} (unmade)`;
263
- /** `kind` is `ram` (RAM and disks) on smolvm, and `disk` on Tart and boat. */
291
+ /**
292
+ * The state as people read it: `running` at rest, `running (failed)` where it is but not at rest,
293
+ * and `stopped, wants running (starting)` on the way.
294
+ */
295
+ const stateLabel = ({ state, desired, phase }) => phase === "settled" ? state : state === desired ? `${state} (${phase})` : `${state}, wants ${desired} (${phase})`;
296
+ /**
297
+ * `kind` is `ram` (RAM and disks) on smolvm, and `disk` on Tart and boat. A checkpoint exists only
298
+ * once its capture is done, and never changes after.
299
+ */
264
300
  const Checkpoint = Schema.Struct({
265
301
  id: Id,
266
302
  createdAt: Schema.DateTimeUtcFromString,
@@ -270,11 +306,8 @@ const Checkpoint = Schema.Struct({
270
306
  profile: Schema.optionalKey(Schema.String),
271
307
  cpu: Size,
272
308
  ramMib: Size,
273
- diskGib: Size,
274
- action: ActionRecord
309
+ diskGib: Size
275
310
  }).annotate({ identifier: "Checkpoint" });
276
- /** A checkpoint restores once its capture is done; it never changes after. */
277
- const isReady = (checkpoint) => checkpoint.action.status === "done";
278
311
  /**
279
312
  * `runtimeVersion` is boat's API version on boat. `captureFrom` is the state a machine must be in
280
313
  * to be captured: Tart's is `stopped`.
@@ -336,6 +369,17 @@ const CreateRequest = Schema.Struct({
336
369
  id: Id,
337
370
  ...specFields
338
371
  });
372
+ /** A prebuild is the checkpoint `id` of a machine made from the spec, setup and all. */
373
+ const PrebuildRequest = Schema.Struct({
374
+ id: Id,
375
+ ...specFields,
376
+ setup: Setup
377
+ });
378
+ /** `built` is false when the host already had the checkpoint. */
379
+ const Prebuilt = Schema.Struct({
380
+ checkpoint: Checkpoint,
381
+ built: Schema.Boolean
382
+ });
339
383
  //#endregion
340
384
  //#region src/api.ts
341
385
  /** A host bounds its own reads of runtime state under it, so a list answers in time. */
@@ -359,20 +403,28 @@ const reading = [
359
403
  NotFound,
360
404
  Internal
361
405
  ];
362
- const changing = [
406
+ const removing = [
363
407
  Invalid,
364
408
  NotFound,
365
- Conflict,
366
409
  Refused,
367
410
  Internal
368
411
  ];
369
- const booting = [
370
- ...changing,
412
+ const converging = [
413
+ Invalid,
414
+ NotFound,
371
415
  NotMade,
372
416
  Missing,
373
417
  WrongState,
374
- Capacity
418
+ PinMismatch,
419
+ Unsizable,
420
+ ScriptFailed,
421
+ Refused,
422
+ Capacity,
423
+ Superseded,
424
+ Internal
375
425
  ];
426
+ const making = [...converging, Conflict];
427
+ const creating = [...making, NotOffered];
376
428
  const Http = ActionHttp.make([
377
429
  Action.make("listMachines", {
378
430
  ...read,
@@ -389,62 +441,42 @@ const Http = ActionHttp.make([
389
441
  }),
390
442
  Action.make("createMachine", {
391
443
  ...write,
392
- error: [
393
- Invalid,
394
- Conflict,
395
- NotOffered,
396
- Unsizable,
397
- ScriptFailed,
398
- Refused,
399
- Capacity,
400
- Internal
401
- ],
402
- description: "Create a machine from a base, run its setup once, and prepare it.",
444
+ error: creating,
445
+ description: "Create a machine from a base, run its setup once, and prepare it. A create or setup that fails deletes the machine, again at each recheck while that delete fails, and the error is the answer; a preparation that fails keeps it.",
403
446
  input: CreateRequest,
404
447
  success: Machine
405
448
  }),
406
449
  Action.make("startMachine", {
407
450
  ...write,
408
- error: [...booting, ScriptFailed],
409
- description: "Start a machine. On a running machine, run preparation again.",
451
+ error: converging,
452
+ description: "Ask for a machine to run, and wait until it does: start it and prepare it again, also when it runs already.",
410
453
  input: ById,
411
454
  success: Machine
412
455
  }),
413
456
  Action.make("stopMachine", {
414
457
  ...write,
415
- error: changing,
416
- description: "Stop a machine: a power-off that keeps its disk and ends its processes. A stopped machine stays stopped, and the stop is still its last action.",
458
+ error: converging,
459
+ description: "Ask for a machine to stay stopped, and wait until it is: a power-off that keeps its disk and ends its processes. A start under way is cut short; a machine still being made is made first, and its create answers Superseded.",
417
460
  input: ById,
418
461
  success: Machine
419
462
  }),
420
463
  Action.make("deleteMachine", {
421
464
  ...write,
422
- error: changing,
423
- description: "Delete a machine and everything native it owns.",
465
+ error: converging,
466
+ description: "Delete a machine and everything native it owns, whatever it is doing.",
424
467
  input: ById
425
468
  }),
426
469
  Action.make("forkMachine", {
427
470
  ...write,
428
- error: [
429
- ...booting,
430
- Unsizable,
431
- ScriptFailed
432
- ],
433
- description: "Copy a machine to a new name on the same host.",
471
+ error: making,
472
+ description: "Copy a machine to a new name on the same host. A copy that fails deletes the new machine.",
434
473
  input: FromMachine,
435
474
  success: Machine
436
475
  }),
437
476
  Action.make("restoreMachine", {
438
477
  ...write,
439
- error: [
440
- ...changing,
441
- NotReady,
442
- PinMismatch,
443
- Unsizable,
444
- ScriptFailed,
445
- Capacity
446
- ],
447
- description: "Create a machine on the checkpoint's host from that checkpoint.",
478
+ error: making,
479
+ description: "Create a machine on the checkpoint's host from that checkpoint. A restore that fails deletes the new machine.",
448
480
  input: Schema.Struct({
449
481
  checkpoint: Id,
450
482
  name: Name
@@ -466,17 +498,34 @@ const Http = ActionHttp.make([
466
498
  }),
467
499
  Action.make("captureCheckpoint", {
468
500
  ...write,
469
- error: booting,
501
+ error: [
502
+ Invalid,
503
+ NotFound,
504
+ Conflict,
505
+ NotMade,
506
+ Missing,
507
+ WrongState,
508
+ Refused,
509
+ Capacity,
510
+ Internal
511
+ ],
470
512
  description: "Capture a checkpoint of a machine. Its kind follows the runtime: ram on smolvm, which captures only a running machine, and disk on Tart and boat.",
471
513
  input: FromMachine,
472
514
  success: Checkpoint
473
515
  }),
474
516
  Action.make("deleteCheckpoint", {
475
517
  ...write,
476
- error: changing,
477
- description: "Delete a checkpoint.",
518
+ error: removing,
519
+ description: "Delete a checkpoint, once the restores that read it are done.",
478
520
  input: ById
479
521
  }),
522
+ Action.make("prebuildCheckpoint", {
523
+ ...write,
524
+ error: creating,
525
+ description: "Make checkpoint id from a machine the host builds from the spec, setup and all, and deletes after. A checkpoint id that exists is the answer, and two prebuilds of one id share one build.",
526
+ input: PrebuildRequest,
527
+ success: Prebuilt
528
+ }),
480
529
  Action.make("getHost", {
481
530
  ...read,
482
531
  error: [Invalid],
@@ -498,7 +547,7 @@ const actionsByName = Action.byName(Http.actions);
498
547
  //#endregion
499
548
  //#region src/release.ts
500
549
  /** Also the version of the clankerbox CLI released with it. */
501
- const version = "0.18.2";
550
+ const version = "0.19.0";
502
551
  /** major.minor: releases that share it speak the same API. */
503
552
  const release = (of) => of.split(".").slice(0, 2).join(".");
504
553
  /** A host refuses a request whose `release` differs from its own, or that has none. */
@@ -700,9 +749,10 @@ const make = (hosts, options) => Effect.gen(function* () {
700
749
  restoreMachine: (input) => onResource("restoreMachine", input, input.name),
701
750
  getCheckpoint: (input) => onResource("getCheckpoint", input),
702
751
  captureCheckpoint: (input) => onResource("captureCheckpoint", input, input.name),
703
- deleteCheckpoint: (input) => deleting(onResource("deleteCheckpoint", input))
752
+ deleteCheckpoint: (input) => deleting(onResource("deleteCheckpoint", input)),
753
+ prebuildCheckpoint: (input) => onResource("prebuildCheckpoint", input)
704
754
  };
705
755
  });
706
756
  const layer = (hosts, options) => Layer.effect(Client, make(hosts, options));
707
757
  //#endregion
708
- export { parseId as A, NotFound as B, Usage as C, Id as D, HostId as E, ConflictKind as F, Refused as G, NotOffered as H, HostError as I, Unsizable as J, ScriptFailed as K, Internal as L, Capacity as M, ClankerboxError as N, Name as O, Conflict as P, Invalid as R, SshLogin as S, stateLabel as T, NotReady as U, NotMade as V, PinMismatch as W, hostErrors as X, WrongState as Y, retryable as Z, Machine as _, release as a, Setup as b, Http as c, ActionName as d, ActionRecord as f, Host as g, CreateRequest as h, describeIssues as i, parseName as j, formatId as k, actionsByName as l, Checkpoint as m, layer as n, version as o, ActionStatus as p, Unavailable as q, describeFileError as r, versionHeader as s, client_exports as t, readTimeout as u, MachineSpec as v, isReady as w, SshEndpoint as x, Runtime as y, Missing as z };
758
+ export { formatId as A, NotFound as B, SshLogin as C, HostId as D, stateLabel as E, Conflict as F, ScriptFailed as G, NotOffered as H, HostError as I, Unsizable as J, Superseded as K, Internal as L, parseName as M, Capacity as N, Id as O, ClankerboxError as P, Invalid as R, SshEndpoint as S, Usage as T, PinMismatch as U, NotMade as V, Refused as W, hostErrors as X, WrongState as Y, retryable as Z, Phase as _, release as a, Runtime as b, Http as c, Checkpoint as d, CreateRequest as f, MachineSpec as g, Machine as h, describeIssues as i, parseId as j, Name as k, actionsByName as l, Host as m, layer as n, version as o, Desired as p, Unavailable as q, describeFileError as r, versionHeader as s, client_exports as t, readTimeout as u, PrebuildRequest as v, TailnetStatus as w, Setup as x, Prebuilt as y, Missing as z };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as ConflictKind, B as Refused, C as Declared, D as Capacity, E as readTimeout, F as NotFound, G as hostErrors, H as Unavailable, I as NotMade, K as retryable, L as NotOffered, M as Internal, N as Invalid, O as ClankerboxError, P as Missing, R as NotReady, S as stateLabel, T as actionsByName, U as Unsizable, V as ScriptFailed, W as WrongState, _ as Setup, b as Usage, c as ActionRecord, d as CreateRequest, f as Host, g as Runtime, h as Reading, i as Interface, j as HostError, k as Conflict, l as ActionStatus, m as MachineSpec, n as CreateOptions$1, o as client_d_exports, p as Machine, s as ActionName, u as Checkpoint, v as SshEndpoint, w as Http, x as isReady, y as SshLogin, z as PinMismatch } from "./client-8af586hb.mjs";
1
+ import { A as Conflict, B as ScriptFailed, C as stateLabel, D as readTimeout, E as actionsByName, F as NotFound, G as hostErrors, H as Unavailable, I as NotMade, K as retryable, L as NotOffered, M as Internal, N as Invalid, O as Capacity, P as Missing, R as PinMismatch, S as Usage, T as Http, U as Unsizable, V as Superseded, W as WrongState, _ as Runtime, b as SshLogin, c as CreateRequest, d as Machine, f as MachineSpec, g as Reading, h as Prebuilt, i as Interface, j as HostError, k as ClankerboxError, l as Desired, m as PrebuildRequest, n as CreateOptions$1, o as client_d_exports, p as Phase, s as Checkpoint, u as Host, v as Setup, w as Declared, x as TailnetStatus, y as SshEndpoint, z as Refused } from "./client-BodRGKAX.mjs";
2
2
  import { Effect, FileSystem, Path, PlatformError, Schema, Scope } from "effect";
3
3
  //#region src/ids.d.ts
4
4
  export declare const HostId: Schema.String;
@@ -15,7 +15,7 @@ export declare const parseName: (name: string) => Effect.Effect<string, Invalid>
15
15
  /** Checks both parts and the whole. */
16
16
  export declare const formatId: (host: string, name: string) => Effect.Effect<string, Invalid>;
17
17
  declare namespace prebuild_d_exports {
18
- export { Built, CreateOptions, Created, build, create, nameOf };
18
+ export { CreateOptions, Created, build, create, nameOf };
19
19
  }
20
20
  /**
21
21
  * A digest of the spec's label, base, sizes, setup script as sent, and the host's runtime
@@ -34,26 +34,17 @@ interface Created {
34
34
  readonly prebuild?: Checkpoint | undefined;
35
35
  }
36
36
  /**
37
- * `client.create`, restoring the spec's prebuild when the host it is placed on has one whose
38
- * capture is done, unless `fresh`. A failed restore is the reply.
37
+ * `client.create`, restoring the spec's prebuild when the host it is placed on has one, unless
38
+ * `fresh`. A failed restore is the reply.
39
39
  */
40
40
  declare const create: (client: Interface, name: string, spec: MachineSpec, options?: CreateOptions) => Effect.Effect<Created, ClankerboxError>;
41
- interface Built {
42
- readonly checkpoint: Checkpoint;
43
- readonly built: boolean;
44
- /** The builder's ID when its delete failed: it may still run, holding its RAM. */
45
- readonly leftover?: string | undefined;
46
- }
47
41
  /**
48
- * Builds the spec's prebuild on the host a create of it is placed on, with a machine of its own
49
- * that it deletes however it ends. A prebuild that is there and done is the answer, one that
50
- * failed is deleted and built again, and one still running is `Conflict{busy}`, as its capture
51
- * holds it. Of two builds of one spec at once, the second's capture is `Conflict`, and neither
52
- * touches the other's machine.
42
+ * Asks the host a create of the spec is placed on for the spec's prebuild, which it builds with a
43
+ * machine of its own unless it has it. Two builds of one spec at once share the host's one build.
53
44
  */
54
45
  declare const build: (client: Interface, spec: MachineSpec & {
55
46
  readonly setup: Setup;
56
- }, options?: CreateOptions$1) => Effect.Effect<Built, ClankerboxError>;
47
+ }, options?: CreateOptions$1) => Effect.Effect<Prebuilt, ClankerboxError>;
57
48
  //#endregion
58
49
  //#region src/release.d.ts
59
50
  /** Also the version of the clankerbox CLI released with it. */
@@ -154,4 +145,4 @@ export declare const formatMib: (mib: number) => string;
154
145
  /** As a size flag takes it: `60G`. */
155
146
  export declare const formatGib: (gib: number) => string;
156
147
  //#endregion
157
- export { ActionName, ActionRecord, ActionStatus, Capacity, Checkpoint, ClankerboxError, client_d_exports as Client, Conflict, ConflictKind, CreateRequest, Declared, Host, HostError, Http, Internal, Invalid, Machine, MachineSpec, Missing, NotFound, NotMade, NotOffered, NotReady, PinMismatch, prebuild_d_exports as Prebuild, Reading, Refused, Runtime, ScriptFailed, Setup, SshEndpoint, SshLogin, Unavailable, Unsizable, Usage, WrongState, actionsByName, hostErrors, isReady, readTimeout, retryable, stateLabel };
148
+ export { Capacity, Checkpoint, ClankerboxError, client_d_exports as Client, Conflict, CreateRequest, Declared, Desired, Host, HostError, Http, Internal, Invalid, Machine, MachineSpec, Missing, NotFound, NotMade, NotOffered, Phase, PinMismatch, prebuild_d_exports as Prebuild, PrebuildRequest, Prebuilt, Reading, Refused, Runtime, ScriptFailed, Setup, SshEndpoint, SshLogin, Superseded, TailnetStatus, Unavailable, Unsizable, Usage, WrongState, actionsByName, hostErrors, readTimeout, retryable, stateLabel };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { A as parseId, B as NotFound, C as Usage, D as Id, E as HostId, F as ConflictKind, G as Refused, H as NotOffered, I as HostError, J as Unsizable, K as ScriptFailed, L as Internal, M as Capacity, N as ClankerboxError, O as Name, P as Conflict, R as Invalid, S as SshLogin, T as stateLabel, U as NotReady, V as NotMade, W as PinMismatch, X as hostErrors, Y as WrongState, Z as retryable, _ as Machine, a as release, b as Setup, c as Http, d as ActionName, f as ActionRecord, g as Host, h as CreateRequest, i as describeIssues, j as parseName, k as formatId, l as actionsByName, m as Checkpoint, o as version, p as ActionStatus, q as Unavailable, r as describeFileError, s as versionHeader, t as client_exports, u as readTimeout, v as MachineSpec, w as isReady, x as SshEndpoint, y as Runtime, z as Missing } from "./client-VX9csS7I.mjs";
2
+ import { A as formatId, B as NotFound, C as SshLogin, D as HostId, E as stateLabel, F as Conflict, G as ScriptFailed, H as NotOffered, I as HostError, J as Unsizable, K as Superseded, L as Internal, M as parseName, N as Capacity, O as Id, P as ClankerboxError, R as Invalid, S as SshEndpoint, T as Usage, U as PinMismatch, V as NotMade, W as Refused, X as hostErrors, Y as WrongState, Z as retryable, _ as Phase, a as release, b as Runtime, c as Http, d as Checkpoint, f as CreateRequest, g as MachineSpec, h as Machine, i as describeIssues, j as parseId, k as Name, l as actionsByName, m as Host, o as version, p as Desired, q as Unavailable, r as describeFileError, s as versionHeader, t as client_exports, u as readTimeout, v as PrebuildRequest, w as TailnetStatus, x as Setup, y as Prebuilt, z as Missing } from "./client-BwhQ_WUi.mjs";
3
3
  import { Effect, FileSystem, Option, Path, Predicate, Record, Schema } from "effect";
4
4
  import { Base64, Hex } from "effect/encoding";
5
5
  //#region src/prebuild.ts
@@ -10,7 +10,6 @@ var prebuild_exports = /* @__PURE__ */ __exportAll({
10
10
  });
11
11
  const prefix = "prebuilt-";
12
12
  const digestDigits = 12;
13
- const builderBytes = 8;
14
13
  /**
15
14
  * A digest of the spec's label, base, sizes, setup script as sent, and the host's runtime
16
15
  * version: a `ram` checkpoint restores only under the release that saved it, so after a runtime
@@ -28,15 +27,15 @@ const nameOf = (spec, host) => Effect.promise(() => globalThis.crypto.subtle.dig
28
27
  ])))).pipe(Effect.map((digest) => `${prefix}${Hex.encode(new Uint8Array(digest)).slice(0, digestDigits)}`));
29
28
  const lookup = (client, id) => client.getCheckpoint({ id }).pipe(Effect.map(Option.some), Effect.catchTag("NotFound", () => Effect.succeedNone));
30
29
  /**
31
- * `client.create`, restoring the spec's prebuild when the host it is placed on has one whose
32
- * capture is done, unless `fresh`. A failed restore is the reply.
30
+ * `client.create`, restoring the spec's prebuild when the host it is placed on has one, unless
31
+ * `fresh`. A failed restore is the reply.
33
32
  */
34
33
  const create = (client, name, spec, options) => Effect.gen(function* () {
35
34
  if (spec.setup === void 0 || options?.fresh === true) return { machine: yield* client.create(name, spec, { host: options?.host }) };
36
35
  const host = yield* client.place(spec.base, options);
37
36
  const id = yield* formatId(host.id, yield* nameOf(spec, host));
38
37
  const found = yield* lookup(client, id);
39
- if (Option.isSome(found) && isReady(found.value)) return {
38
+ if (Option.isSome(found)) return {
40
39
  machine: yield* client.restoreMachine({
41
40
  checkpoint: id,
42
41
  name
@@ -46,47 +45,16 @@ const create = (client, name, spec, options) => Effect.gen(function* () {
46
45
  return { machine: yield* client.create(name, spec, { host: host.id }) };
47
46
  });
48
47
  /**
49
- * Builds the spec's prebuild on the host a create of it is placed on, with a machine of its own
50
- * that it deletes however it ends. A prebuild that is there and done is the answer, one that
51
- * failed is deleted and built again, and one still running is `Conflict{busy}`, as its capture
52
- * holds it. Of two builds of one spec at once, the second's capture is `Conflict`, and neither
53
- * touches the other's machine.
48
+ * Asks the host a create of the spec is placed on for the spec's prebuild, which it builds with a
49
+ * machine of its own unless it has it. Two builds of one spec at once share the host's one build.
54
50
  */
55
51
  const build = (client, spec, options) => Effect.gen(function* () {
56
52
  const host = yield* client.place(spec.base, options);
57
- const name = yield* nameOf(spec, host);
58
- const id = yield* formatId(host.id, name);
59
- const found = yield* lookup(client, id);
60
- if (Option.isSome(found)) {
61
- const { action } = found.value;
62
- if (isReady(found.value)) return {
63
- checkpoint: found.value,
64
- built: false
65
- };
66
- if (action.status === "running") return yield* new Conflict({
67
- message: `prebuild ${id} is busy: its ${action.name} is running`,
68
- kind: "busy",
69
- host: host.id,
70
- action: "captureCheckpoint",
71
- id
72
- });
73
- yield* client.deleteCheckpoint({ id });
74
- }
75
- const builder = `prebuilding-${Hex.encode(globalThis.crypto.getRandomValues(new Uint8Array(builderBytes)))}`;
76
- const builderId = yield* formatId(host.id, builder);
77
- const removal = client.deleteMachine({ id: builderId });
78
- return {
79
- checkpoint: yield* Effect.gen(function* () {
80
- yield* client.create(builder, spec, { host: host.id });
81
- if (host.captureFrom === "stopped") yield* client.stopMachine({ id: builderId });
82
- return yield* client.captureCheckpoint({
83
- machine: builderId,
84
- name
85
- });
86
- }).pipe(Effect.onError(() => Effect.ignore(removal))),
87
- built: true,
88
- leftover: yield* removal.pipe(Effect.as(void 0), Effect.catch(() => Effect.succeed(builderId)))
89
- };
53
+ const id = yield* formatId(host.id, yield* nameOf(spec, host));
54
+ return yield* client.prebuildCheckpoint({
55
+ id,
56
+ ...spec
57
+ });
90
58
  });
91
59
  //#endregion
92
60
  //#region src/setup.ts
@@ -248,7 +216,7 @@ const specRequest = (what, profile, overrides, names) => Effect.gen(function* ()
248
216
  * either is `WrongState`, naming what it lacks and why.
249
217
  */
250
218
  const sshTarget = (machine) => {
251
- const { id, ssh: login, hostKey, action } = machine;
219
+ const { id, ssh: login, hostKey } = machine;
252
220
  if (login !== void 0 && hostKey !== void 0) return Effect.succeed({
253
221
  id,
254
222
  login,
@@ -256,7 +224,7 @@ const sshTarget = (machine) => {
256
224
  });
257
225
  const lacks = login === void 0 ? "SSH endpoint" : "SSH host key on record";
258
226
  const state = stateLabel(machine);
259
- const message = `${id} has no ${lacks} (${state}, ${action.name} ${action.status}): see clankerbox get ${id}`;
227
+ const message = `${id} has no ${lacks} (${state}): see clankerbox get ${id}`;
260
228
  return Effect.fail(new WrongState({
261
229
  message,
262
230
  machine: id,
@@ -306,4 +274,4 @@ const formatMib = (mib) => mib >= 1024 && mib % 512 === 0 ? `${mib / mibPerGib}G
306
274
  /** As a size flag takes it: `60G`. */
307
275
  const formatGib = (gib) => `${gib}G`;
308
276
  //#endregion
309
- export { ActionName, ActionRecord, ActionStatus, Capacity, Checkpoint, ClankerboxError, client_exports as Client, Conflict, ConflictKind, CreateRequest, Host, HostError, HostId, Http, Id, Internal, Invalid, Machine, MachineSpec, Missing, Name, NotFound, NotMade, NotOffered, NotReady, PinMismatch, prebuild_exports as Prebuild, Profile, Refused, Runtime, ScriptFailed, Setup, SshEndpoint, SshLogin, Unavailable, Unsizable, Usage, WrongState, actionsByName, describeFileError, describeIssues, formatGib, formatId, formatMib, hostErrors, isReady, knownHostsLine, loadProfile, mibPerGib, packRecipe, parseId, parseName, pinnedSsh, readSetup, readTimeout, release, retryable, specRequest, sshTarget, stateLabel, version, versionHeader };
277
+ export { Capacity, Checkpoint, ClankerboxError, client_exports as Client, Conflict, CreateRequest, Desired, Host, HostError, HostId, Http, Id, Internal, Invalid, Machine, MachineSpec, Missing, Name, NotFound, NotMade, NotOffered, Phase, PinMismatch, prebuild_exports as Prebuild, PrebuildRequest, Prebuilt, Profile, Refused, Runtime, ScriptFailed, Setup, SshEndpoint, SshLogin, Superseded, TailnetStatus, Unavailable, Unsizable, Usage, WrongState, actionsByName, describeFileError, describeIssues, formatGib, formatId, formatMib, hostErrors, knownHostsLine, loadProfile, mibPerGib, packRecipe, parseId, parseName, pinnedSsh, readSetup, readTimeout, release, retryable, specRequest, sshTarget, stateLabel, version, versionHeader };
package/dist/node.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { N as Invalid, a as Options, r as HostEntry, t as Client } from "./client-8af586hb.mjs";
1
+ import { N as Invalid, a as Options, r as HostEntry, t as Client } from "./client-BodRGKAX.mjs";
2
2
  import { Layer } from "effect";
3
3
  //#region src/node.d.ts
4
4
  /**
package/dist/node.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as layer$1 } from "./client-VX9csS7I.mjs";
1
+ import { n as layer$1 } from "./client-BwhQ_WUi.mjs";
2
2
  import { Layer } from "effect";
3
3
  import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient";
4
4
  //#region src/node.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjermundgaraba/clankerbox-sdk",
3
- "version": "0.18.2",
3
+ "version": "0.19.0",
4
4
  "description": "clankerbox's API contract and client library, for Effect",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,21 +27,20 @@
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "dependencies": {
31
- "@gjermundgaraba/effect-actions": "0.17.0"
32
- },
33
30
  "devDependencies": {
34
- "@effect/platform-node": "4.0.4",
35
- "@effect/vitest": "4.0.4",
36
- "@types/node": "26.6.4",
37
- "effect": "4.0.4",
31
+ "@effect/platform-node": "4.0.5",
32
+ "@effect/vitest": "4.0.5",
33
+ "@gjermundgaraba/effect-actions": "0.18.2",
34
+ "@types/node": "26.6.5",
35
+ "effect": "4.0.5",
38
36
  "typescript": "7.0.2",
39
- "vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
40
- "vite-plus": "1.2.0",
41
- "vitest": "5.0.4"
37
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
38
+ "vite-plus": "1.3.0",
39
+ "vitest": "5.0.5"
42
40
  },
43
41
  "peerDependencies": {
44
42
  "@effect/platform-node": "~4.0.4",
43
+ "@gjermundgaraba/effect-actions": "^0.18.0",
45
44
  "effect": "~4.0.4"
46
45
  },
47
46
  "peerDependenciesMeta": {