@impz/testing 6.3.1 → 6.4.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.
Files changed (2) hide show
  1. package/dist/index.js +108 -81
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -20055,6 +20055,7 @@ var ImpSchema = z16.object({
20055
20055
  public: z16.object({ auth: PublicAuthSchema }).optional(),
20056
20056
  createdAt: z16.date(),
20057
20057
  lastActiveAt: z16.date(),
20058
+ lastRequestAt: z16.date().optional(),
20058
20059
  ramMib: z16.int().nonnegative().optional(),
20059
20060
  rssMib: z16.int().nonnegative().optional(),
20060
20061
  sleptAt: z16.date().optional(),
@@ -21966,7 +21967,7 @@ import { join as join47 } from "path";
21966
21967
  // packages/daemon/package.json
21967
21968
  var package_default = {
21968
21969
  name: "@impz/daemon",
21969
- version: "6.3.1",
21970
+ version: "6.4.0",
21970
21971
  private: true,
21971
21972
  description: "impd: the imp host daemon",
21972
21973
  type: "module",
@@ -22336,6 +22337,7 @@ function toImpRecord(row) {
22336
22337
  ip: row.ip,
22337
22338
  createdAt: new Date(row.created_at),
22338
22339
  lastActiveAt: new Date(row.last_active_at),
22340
+ lastRequestAt: toDate(row.last_request_at),
22339
22341
  sleptAt: toDate(row.slept_at),
22340
22342
  holdUntil: toDate(row.hold_until),
22341
22343
  error: row.error,
@@ -22506,6 +22508,13 @@ async function updateImpMove(db, id, moveState) {
22506
22508
  async function updateImpActivity(db, id, at) {
22507
22509
  await db.updateTable("imps").set({ last_active_at: at.getTime() }).where("id", "=", id).execute();
22508
22510
  }
22511
+ async function updateImpRequest(db, id, at) {
22512
+ const atMs = at.getTime();
22513
+ await db.updateTable("imps").set({
22514
+ last_active_at: sql`MAX(last_active_at, ${atMs})`,
22515
+ last_request_at: sql`MAX(COALESCE(last_request_at, 0), ${atMs})`
22516
+ }).where("id", "=", id).execute();
22517
+ }
22509
22518
  async function updateImpDisk(db, id, disk) {
22510
22519
  const before = await readImpById(db, id);
22511
22520
  const row = await db.updateTable("imps").set({ disk_bytes: disk.diskBytes, disk_grow_pending: disk.isGrowPending ? 1 : 0 }).where("id", "=", id).returningAll().executeTakeFirstOrThrow();
@@ -26002,6 +26011,9 @@ function createImpPresenter(context, readSilentSince) {
26002
26011
  if (imp.maxMemoryMib > imp.memoryMib) {
26003
26012
  api.maxMemoryMib = imp.maxMemoryMib;
26004
26013
  }
26014
+ if (imp.lastRequestAt !== null) {
26015
+ api.lastRequestAt = imp.lastRequestAt;
26016
+ }
26005
26017
  if (imp.sleptAt !== null) {
26006
26018
  api.sleptAt = imp.sleptAt;
26007
26019
  }
@@ -28821,6 +28833,13 @@ var MIGRATION_044_ADD_IMP_IMAGE_DIGESTS = {
28821
28833
  }
28822
28834
  };
28823
28835
 
28836
+ // packages/daemon/src/platform/db/migrations/migration-045-add-imp-last-request.ts
28837
+ var MIGRATION_045_ADD_IMP_LAST_REQUEST = {
28838
+ async up(db) {
28839
+ await db.schema.alterTable("imps").addColumn("last_request_at", "integer").execute();
28840
+ }
28841
+ };
28842
+
28824
28843
  // packages/daemon/src/platform/db/run-migrations.ts
28825
28844
  var MIGRATIONS = {
28826
28845
  "001_create_initial_schema": MIGRATION_001_CREATE_INITIAL_SCHEMA,
@@ -28866,7 +28885,8 @@ var MIGRATIONS = {
28866
28885
  "041_add_move_send_steps": MIGRATION_041_ADD_MOVE_SEND_STEPS,
28867
28886
  "042_add_secret_env": MIGRATION_042_ADD_SECRET_ENV,
28868
28887
  "043_merge_secret_kinds": MIGRATION_043_MERGE_SECRET_KINDS,
28869
- "044_add_imp_image_digests": MIGRATION_044_ADD_IMP_IMAGE_DIGESTS
28888
+ "044_add_imp_image_digests": MIGRATION_044_ADD_IMP_IMAGE_DIGESTS,
28889
+ "045_add_imp_last_request": MIGRATION_045_ADD_IMP_LAST_REQUEST
28870
28890
  };
28871
28891
  var PROVIDER = {
28872
28892
  getMigrations: () => Promise.resolve(MIGRATIONS)
@@ -38204,12 +38224,9 @@ function createAgentWatchdog(deps) {
38204
38224
  import { chmodSync as chmodSync5, lchownSync, mkdirSync as mkdirSync10, rmSync as rmSync13 } from "fs";
38205
38225
 
38206
38226
  // packages/daemon/src/vm/storage/disk-full-error.ts
38207
- var GIB = 1024 ** 3;
38208
-
38209
38227
  class DiskFullError extends ImpdError {
38210
38228
  name = "DiskFullError";
38211
38229
  constructor(availableBytes, reserveBytes, requestedBytes) {
38212
- const formatGib = (bytes) => `${(bytes / GIB).toFixed(1)} GiB`;
38213
38230
  super("DISK_FULL", {
38214
38231
  status: 507,
38215
38232
  message: `not enough free disk: ${formatGib(availableBytes)} free, ${formatGib(requestedBytes)} wanted, and ${formatGib(reserveBytes)} is held in reserve (IMP_DISK_RESERVE_GIB)`,
@@ -38220,6 +38237,10 @@ class DiskFullError extends ImpdError {
38220
38237
  function isDiskFullError(error) {
38221
38238
  return isImpdError(error, "DISK_FULL");
38222
38239
  }
38240
+ var GIB = 1024 ** 3;
38241
+ function formatGib(bytes) {
38242
+ return `${(bytes / GIB).toFixed(1)} GiB`;
38243
+ }
38223
38244
 
38224
38245
  // packages/daemon/src/imp-ops/watchdog/write-watchdog-snapshot.ts
38225
38246
  async function writeWatchdogSnapshot(context, ops, imp) {
@@ -39187,6 +39208,10 @@ function createBootTemplates(deps) {
39187
39208
  return null;
39188
39209
  }
39189
39210
  };
39211
+ const probeCurrent = (name) => {
39212
+ const meta = readMeta(name);
39213
+ return meta !== null && buildTemplateKey(deps.identity, meta) === name;
39214
+ };
39190
39215
  const readReady = (key) => {
39191
39216
  const directory = join18(root, key);
39192
39217
  const meta = readMeta(key);
@@ -39458,10 +39483,6 @@ function createBootTemplates(deps) {
39458
39483
  return [];
39459
39484
  }
39460
39485
  const live = new Set(building.listKeys());
39461
- const probeCurrent = (name) => {
39462
- const meta = readMeta(name);
39463
- return meta !== null && buildTemplateKey(deps.identity, meta) === name;
39464
- };
39465
39486
  const stale = readdirSync3(root).filter((name) => name !== PLACEHOLDER_NAME && !live.has(name) && (name.startsWith(".") || !probeCurrent(name)));
39466
39487
  for (const name of stale) {
39467
39488
  removeDir(name);
@@ -42166,6 +42187,7 @@ function createImpRuntime(parts) {
42166
42187
  await updateImpActivity(context.db, imp.id, new Date);
42167
42188
  }
42168
42189
  },
42190
+ recordRequest: (impId) => updateImpRequest(context.db, impId, new Date(context.now())),
42169
42191
  requireRunning,
42170
42192
  trySleepImp: makeLockFreeSleep(lock.tryWithImpId, (imp, reason, policy) => imp !== undefined && isSleepAllowed(imp, policy) ? sleepIfRunning(imp, reason, buildYoungGuestWait(imp.id, policy)) : Promise.resolve("skipped")),
42171
42193
  sleepAllImps: async () => {
@@ -50358,44 +50380,6 @@ function createImageBuilds(deps, writer) {
50358
50380
  const logger = getImpdLogger("image");
50359
50381
  const buildRuns = createBuildRuns(() => deps.clock.now());
50360
50382
  const buildSlots = createBuildSlots();
50361
- const resolvePinnedDockerfile = async (dockerfile, images, engine, signal) => {
50362
- const platform = await engine.readPlatform(signal);
50363
- const pins = new Map;
50364
- const used = [];
50365
- const stores = new Set;
50366
- const keys = new Map;
50367
- for (const image of images) {
50368
- if (!ImageRefSchema.safeParse(image.ref).success) {
50369
- throw new ImpdError("BAD_REQUEST", {
50370
- message: `${image.use} ${JSON.stringify(image.ref)} is not an image reference`
50371
- });
50372
- }
50373
- const registryProblem = checkReferenceRegistry(image.ref);
50374
- if (registryProblem !== null) {
50375
- throw new ImpdError("BAD_REQUEST", {
50376
- message: `${image.use} ${image.ref}: ${registryProblem}`
50377
- });
50378
- }
50379
- const key = toImageKey(image.ref);
50380
- const known = keys.get(key);
50381
- if (known === undefined) {
50382
- signal.throwIfAborted();
50383
- const inspect = await engine.loadImage(image, signal);
50384
- keys.set(key, pickPin(image, inspect, platform));
50385
- stores.add(readImageStore(inspect));
50386
- }
50387
- pins.set(image.ref, keys.get(key) ?? "");
50388
- }
50389
- for (const image of images) {
50390
- used.push({ use: image.use, ref: image.ref, pin: pins.get(image.ref) ?? "" });
50391
- }
50392
- const store = [...stores].find((candidate) => candidate !== "unknown") ?? "unknown";
50393
- try {
50394
- return { dockerfile: renderPinnedDockerfile(dockerfile, pins, platform), pins: used, store };
50395
- } catch (error) {
50396
- throw toBadRequest(error);
50397
- }
50398
- };
50399
50383
  const createFromContext = async (tarPath, name, givenDockerfile, options) => {
50400
50384
  const signal = options.signal;
50401
50385
  const imageName = requireClientImageName(name);
@@ -50553,6 +50537,47 @@ function createImageBuilds(deps, writer) {
50553
50537
  listBuildRuns: buildRuns.list
50554
50538
  };
50555
50539
  }
50540
+ function toBadRequest(error) {
50541
+ return error instanceof DockerfileError ? new ImpdError("BAD_REQUEST", { message: `the Dockerfile: ${error.message}` }) : error;
50542
+ }
50543
+ async function resolvePinnedDockerfile(dockerfile, images, engine, signal) {
50544
+ const platform = await engine.readPlatform(signal);
50545
+ const pins = new Map;
50546
+ const used = [];
50547
+ const stores = new Set;
50548
+ const keys = new Map;
50549
+ for (const image of images) {
50550
+ if (!ImageRefSchema.safeParse(image.ref).success) {
50551
+ throw new ImpdError("BAD_REQUEST", {
50552
+ message: `${image.use} ${JSON.stringify(image.ref)} is not an image reference`
50553
+ });
50554
+ }
50555
+ const registryProblem = checkReferenceRegistry(image.ref);
50556
+ if (registryProblem !== null) {
50557
+ throw new ImpdError("BAD_REQUEST", {
50558
+ message: `${image.use} ${image.ref}: ${registryProblem}`
50559
+ });
50560
+ }
50561
+ const key = toImageKey(image.ref);
50562
+ const known = keys.get(key);
50563
+ if (known === undefined) {
50564
+ signal.throwIfAborted();
50565
+ const inspect = await engine.loadImage(image, signal);
50566
+ keys.set(key, pickPin(image, inspect, platform));
50567
+ stores.add(readImageStore(inspect));
50568
+ }
50569
+ pins.set(image.ref, keys.get(key) ?? "");
50570
+ }
50571
+ for (const image of images) {
50572
+ used.push({ use: image.use, ref: image.ref, pin: pins.get(image.ref) ?? "" });
50573
+ }
50574
+ const store = [...stores].find((candidate) => candidate !== "unknown") ?? "unknown";
50575
+ try {
50576
+ return { dockerfile: renderPinnedDockerfile(dockerfile, pins, platform), pins: used, store };
50577
+ } catch (error) {
50578
+ throw toBadRequest(error);
50579
+ }
50580
+ }
50556
50581
  function toImageKey(ref) {
50557
50582
  const named = parseImageReference(ref);
50558
50583
  return `${named.registry}/${named.path}:${named.tag ?? "latest"}@${named.digest ?? ""}`;
@@ -50581,9 +50606,6 @@ function pickPin(image, inspect, platform) {
50581
50606
  }
50582
50607
  return pin;
50583
50608
  }
50584
- function toBadRequest(error) {
50585
- return error instanceof DockerfileError ? new ImpdError("BAD_REQUEST", { message: `the Dockerfile: ${error.message}` }) : error;
50586
- }
50587
50609
  function normalizeDockerfilePath(path) {
50588
50610
  const normalized = posix3.normalize(path ?? "Dockerfile");
50589
50611
  if (normalized.startsWith("/") || normalized === ".." || normalized.startsWith("../") || normalized === "." || normalized.endsWith("/")) {
@@ -51544,7 +51566,8 @@ function checkIdle(signals, settings) {
51544
51566
  const activeReason = findActiveReason(signals, settings);
51545
51567
  return {
51546
51568
  activeReason,
51547
- sleep: activeReason === null && settings.now - signals.lastActiveAt >= settings.idleTimeoutMs
51569
+ sleep: activeReason === null && settings.now - signals.lastActiveAt >= settings.idleTimeoutMs,
51570
+ isRequestOpen: signals.proxyConnections > 0
51548
51571
  };
51549
51572
  }
51550
51573
  function findActiveReason(signals, settings) {
@@ -51617,6 +51640,10 @@ function createIdleLoop(deps) {
51617
51640
  idleTimeoutMs: deps.config.idleTimeoutS * 1000,
51618
51641
  cpuPercent: deps.config.idleCpuPercent
51619
51642
  });
51643
+ if (decision.isRequestOpen) {
51644
+ await updateImpRequest(deps.db, imp.id, new Date(now));
51645
+ return;
51646
+ }
51620
51647
  if (decision.activeReason !== null) {
51621
51648
  await updateImpActivity(deps.db, imp.id, new Date(now));
51622
51649
  return;
@@ -54532,7 +54559,7 @@ function startWakeProxy(deps) {
54532
54559
  });
54533
54560
  }
54534
54561
  try {
54535
- await deps.imps.recordActivity(name);
54562
+ await deps.imps.recordRequest(imp.id);
54536
54563
  } catch {}
54537
54564
  return sendUpstream(request, server, `${imp.ip}:${String(imp.httpPort)}`, {
54538
54565
  release: opened.release,
@@ -57135,7 +57162,6 @@ function createZfsCheckpoints(ctx) {
57135
57162
 
57136
57163
  // packages/daemon/src/vm/storage/zfs/create-zfs-moves.ts
57137
57164
  import { join as join43 } from "path";
57138
- var ID_ATTEMPTS3 = 5;
57139
57165
  function createZfsMoves(ctx) {
57140
57166
  const openMoveFiles = async (snapshots, removeMoveSnapshot) => {
57141
57167
  const moveId = Bun.randomUUIDv7();
@@ -57202,16 +57228,6 @@ function createZfsMoves(ctx) {
57202
57228
  }
57203
57229
  return steps;
57204
57230
  };
57205
- const pickCheckpointId = (entries, picked, buildId) => {
57206
- const tried = { id: "" };
57207
- for (let attempt = 0;attempt < ID_ATTEMPTS3; attempt += 1) {
57208
- tried.id = buildId();
57209
- if (listCheckpointSnapshots(entries, tried.id).length === 0 && !picked.includes(tried.id)) {
57210
- return tried.id;
57211
- }
57212
- }
57213
- throw new CheckpointIdTakenError(tried.id);
57214
- };
57215
57231
  const writeReceived = async (impId, steps, readStep, buildId) => {
57216
57232
  checkReceiveSteps(steps);
57217
57233
  const buildStaged = (dataset) => `${ctx.datasets.staging}/mvin-${impId}-${String(dataset)}`;
@@ -57325,6 +57341,17 @@ function checkReceiveSteps(steps) {
57325
57341
  throw new Error("zfs: a move with no steps");
57326
57342
  }
57327
57343
  }
57344
+ var ID_ATTEMPTS3 = 5;
57345
+ function pickCheckpointId(entries, picked, buildId) {
57346
+ const tried = { id: "" };
57347
+ for (let attempt = 0;attempt < ID_ATTEMPTS3; attempt += 1) {
57348
+ tried.id = buildId();
57349
+ if (listCheckpointSnapshots(entries, tried.id).length === 0 && !picked.includes(tried.id)) {
57350
+ return tried.id;
57351
+ }
57352
+ }
57353
+ throw new CheckpointIdTakenError(tried.id);
57354
+ }
57328
57355
 
57329
57356
  // packages/daemon/src/vm/storage/zfs/zfs-reclaim.ts
57330
57357
  function planReclaimStep(entries, roots) {
@@ -58566,13 +58593,26 @@ function buildStubVmm() {
58566
58593
  const serving = [...vms].filter(([pid, vm]) => alive.has(pid) && vm.apiSocket === paths.apiSocket);
58567
58594
  return serving.at(-1)?.[1];
58568
58595
  };
58596
+ const waitForever = (onPark) => {
58597
+ waiting.parked += 1;
58598
+ onPark?.();
58599
+ return new Promise(() => {});
58600
+ };
58601
+ const startFakeVm = async (step, paths) => {
58602
+ const outcome = await chooseOutcome(step);
58603
+ if (outcome === "fail") {
58604
+ throw new StubVmError(`${step} failed: no agent
58605
+ log tail`);
58606
+ }
58607
+ const pid = startPid();
58608
+ pidFiles.set(paths.pidFile, pid);
58609
+ if (outcome === "ok") {
58610
+ setVm(pid, paths, "Running");
58611
+ }
58612
+ return { pid, firecrackerVersion: "v1.17.0", agentVersion: agent.version, timings: {} };
58613
+ };
58569
58614
  const buildRunner = (generation) => {
58570
58615
  const parkedBuild = Promise.withResolvers();
58571
- const waitForever = (onPark) => {
58572
- waiting.parked += 1;
58573
- onPark?.();
58574
- return new Promise(() => {});
58575
- };
58576
58616
  const runInGeneration = async (call, onPark) => {
58577
58617
  if (generation !== counter.generation) {
58578
58618
  return waitForever(onPark);
@@ -58592,19 +58632,6 @@ function buildStubVmm() {
58592
58632
  }
58593
58633
  return read();
58594
58634
  };
58595
- const startFakeVm = async (step, paths) => {
58596
- const outcome = await chooseOutcome(step);
58597
- if (outcome === "fail") {
58598
- throw new StubVmError(`${step} failed: no agent
58599
- log tail`);
58600
- }
58601
- const pid = startPid();
58602
- pidFiles.set(paths.pidFile, pid);
58603
- if (outcome === "ok") {
58604
- setVm(pid, paths, "Running");
58605
- }
58606
- return { pid, firecrackerVersion: "v1.17.0", agentVersion: agent.version, timings: {} };
58607
- };
58608
58635
  const runner = {
58609
58636
  startVm: (plan) => runInGeneration(async () => {
58610
58637
  boots.push({ hostname: plan.hostname, isIdentityReset: plan.isIdentityReset });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impz/testing",
3
- "version": "6.3.1",
3
+ "version": "6.4.0",
4
4
  "description": "A real impd on stand-ins, for Bun tests of code that drives impd through @impz/client",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "@orpc/openapi": "^1.16.0",
29
29
  "@orpc/openapi-client": "^1.16.0",
30
30
  "@orpc/server": "^1.16.0",
31
- "@peculiar/x509": "^1.14.3",
31
+ "@peculiar/x509": "^2.2.0",
32
32
  "@zgeoff/kysely-bun-sqlite": "^0.3.0",
33
33
  "better-auth": "^1.7.11",
34
34
  "dns-packet": "^5.6.1",
@@ -43,7 +43,7 @@
43
43
  "ts-pattern": "^5.9.2",
44
44
  "xstate": "^5.33.3",
45
45
  "zod": "^4.6.7",
46
- "@impz/client": "6.3.1"
46
+ "@impz/client": "6.4.0"
47
47
  },
48
48
  "engines": {
49
49
  "bun": ">=1.4.3"