@emulates/docker 0.1.1 → 1.0.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.
package/CHANGELOG.md CHANGED
@@ -1,9 +1,19 @@
1
1
  # Changelog — @emulates/docker
2
2
 
3
- ## 0.1.1 (2026-10-06)
3
+ ## 1.0.0 (2026-10-07)
4
4
 
5
- Initial release.
5
+ ### ⚠️ Breaking changes
6
+
7
+ - point the repo at crvouga/emulates ([cdb5e53](https://github.com/crvouga/emulates/commit/cdb5e536ed8c1f52345e3984f089001c25fdb08a))
8
+
9
+ ### Fixes and improvements
10
+
11
+ - format the emulates records query ([8698872](https://github.com/crvouga/emulates/commit/8698872509d06002be5a8fcdc85d79f8462320c3))
6
12
 
7
13
  ### Dependencies
8
14
 
9
15
  - `@emulates/sqlite`
16
+
17
+ ## 0.1.1 (2026-10-06)
18
+
19
+ Initial release.
package/DISCOVERY.md CHANGED
@@ -46,7 +46,7 @@ designed for assertions and diagnosis by consuming test suites.
46
46
 
47
47
  ## Report a mismatch or missing capability
48
48
 
49
- Follow the [agent reporting contract](https://github.com/crvouga/emulators/blob/main/docs/REPORTING_ISSUES.md). Include package version,
49
+ Follow the [agent reporting contract](https://github.com/crvouga/emulates/blob/main/docs/REPORTING_ISSUES.md). Include package version,
50
50
  operation/command, a minimal redacted request, actual emulator result, expected oracle result or vendor
51
51
  documentation, and whether the mismatch appears in the matrix. Never include keys, tokens,
52
52
  customer data, prompts, PHI, card data, or unredacted recordings.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @emulates/docker
2
2
 
3
- > Part of [Emulates](https://github.com/crvouga/emulators): high-fidelity, in-process emulators for APIs and databases.
3
+ > Part of [Emulates](https://github.com/crvouga/emulates): high-fidelity, in-process emulators for APIs and databases.
4
4
 
5
5
  Work-in-progress Docker Engine API 1.52 emulator. It implements GET/HEAD `/_ping`,
6
6
  GET `/version`, `/info`, `/containers/json`, and `/containers/{id}/json`, plus
@@ -136,7 +136,7 @@ strings. Request environment keys and labels take precedence. `Entrypoint: [""]`
136
136
  clears the image entrypoint; provide a replacement command when doing so.
137
137
 
138
138
  Use `?name=...` for a stable name. Conflicting names return 409, including concurrent
139
- creation requests. Omitted names use `emulators_<id-prefix>`. Responses contain
139
+ creation requests. Omitted names use `emulates_<id-prefix>`. Responses contain
140
140
  `Id` and `Warnings`; IDs are deterministic synthetic 64-character hex strings,
141
141
  immutable within stored records and restored with the shared ID sequence by
142
142
  Timeline checkout. New records inspect as `created` with `Running: false`.
@@ -5,7 +5,7 @@ import {
5
5
  createRuntime,
6
6
  isRunning,
7
7
  jsonRes
8
- } from "./chunk-NSXRVOHP.js";
8
+ } from "./chunk-U6P6W4BK.js";
9
9
 
10
10
  // src/attach.ts
11
11
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -626,4 +626,4 @@ export {
626
626
  createServer2 as createServer,
627
627
  serveTarget
628
628
  };
629
- //# sourceMappingURL=chunk-ZO7PO2NA.js.map
629
+ //# sourceMappingURL=chunk-PYYL7YKU.js.map
@@ -33,7 +33,7 @@ var CORE_MIGRATIONS = [
33
33
  {
34
34
  id: "20260322_core_records_sequences",
35
35
  sql: `
36
- CREATE TABLE IF NOT EXISTS emulators_records (
36
+ CREATE TABLE IF NOT EXISTS emulates_records (
37
37
  namespace TEXT NOT NULL,
38
38
  collection TEXT NOT NULL,
39
39
  id TEXT NOT NULL,
@@ -41,9 +41,9 @@ var CORE_MIGRATIONS = [
41
41
  value TEXT NOT NULL,
42
42
  PRIMARY KEY (namespace, collection, id)
43
43
  );
44
- CREATE INDEX IF NOT EXISTS emulators_records_seq
45
- ON emulators_records (namespace, collection, seq);
46
- CREATE TABLE IF NOT EXISTS emulators_sequences (
44
+ CREATE INDEX IF NOT EXISTS emulates_records_seq
45
+ ON emulates_records (namespace, collection, seq);
46
+ CREATE TABLE IF NOT EXISTS emulates_sequences (
47
47
  namespace TEXT NOT NULL,
48
48
  name TEXT NOT NULL,
49
49
  kind TEXT NOT NULL,
@@ -53,13 +53,33 @@ var CORE_MIGRATIONS = [
53
53
  `
54
54
  }
55
55
  ];
56
+ var LEGACY_TABLES = [
57
+ ["emulators_records", "emulates_records"],
58
+ ["emulators_sequences", "emulates_sequences"]
59
+ ];
60
+ var LEGACY_INDEXES = [["emulators_records_seq", "emulates_records_seq"]];
61
+ var namesOf = (sqlite, type) => new Set(sqlite.prepare("SELECT name FROM sqlite_master WHERE type = ?").all(type).map((row) => row.name));
56
62
  var migrateCore = (sqlite) => {
57
63
  migrate(sqlite, CORE_MIGRATIONS);
64
+ const tables = namesOf(sqlite, "table");
65
+ const indexes = namesOf(sqlite, "index");
66
+ sqlite.transaction(() => {
67
+ for (const [from, to] of LEGACY_TABLES) {
68
+ if (tables.has(from) && !tables.has(to))
69
+ sqlite.exec(`ALTER TABLE ${from} RENAME TO ${to}`);
70
+ }
71
+ for (const [from, to] of LEGACY_INDEXES) {
72
+ if (!indexes.has(from) || indexes.has(to))
73
+ continue;
74
+ sqlite.exec(`DROP INDEX ${from}`);
75
+ sqlite.exec(`CREATE INDEX ${to} ON emulates_records (namespace, collection, seq)`);
76
+ }
77
+ });
58
78
  };
59
79
  var clearNamespace = (sqlite, namespace) => {
60
80
  sqlite.transaction(() => {
61
- sqlite.prepare("DELETE FROM emulators_records WHERE namespace = ?").run(namespace);
62
- sqlite.prepare("DELETE FROM emulators_sequences WHERE namespace = ?").run(namespace);
81
+ sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ?").run(namespace);
82
+ sqlite.prepare("DELETE FROM emulates_sequences WHERE namespace = ?").run(namespace);
63
83
  });
64
84
  };
65
85
 
@@ -74,9 +94,9 @@ var Collection = class {
74
94
  this.collectionName = collectionName;
75
95
  }
76
96
  bumpCollectionSeq() {
77
- const row = this.sqlite.prepare("SELECT value FROM emulators_sequences WHERE namespace = ? AND name = ? AND kind = 'collection'").get(this.namespace, this.collectionName);
97
+ const row = this.sqlite.prepare("SELECT value FROM emulates_sequences WHERE namespace = ? AND name = ? AND kind = 'collection'").get(this.namespace, this.collectionName);
78
98
  const next = (row?.value ?? 0) + 1;
79
- this.sqlite.prepare(`INSERT INTO emulators_sequences (namespace, name, kind, value) VALUES (?, ?, 'collection', ?)
99
+ this.sqlite.prepare(`INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, 'collection', ?)
80
100
  ON CONFLICT(namespace, name, kind) DO UPDATE SET value = excluded.value`).run(this.namespace, this.collectionName, next);
81
101
  return next;
82
102
  }
@@ -84,13 +104,13 @@ var Collection = class {
84
104
  return this.sqlite.transaction(() => this.bumpCollectionSeq());
85
105
  }
86
106
  get(id) {
87
- const row = this.sqlite.prepare("SELECT value FROM emulators_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
107
+ const row = this.sqlite.prepare("SELECT value FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
88
108
  if (!row)
89
109
  return void 0;
90
110
  return JSON.parse(row.value).value;
91
111
  }
92
112
  has(id) {
93
- const row = this.sqlite.prepare("SELECT 1 AS ok FROM emulators_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
113
+ const row = this.sqlite.prepare("SELECT 1 AS ok FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
94
114
  return row !== void 0;
95
115
  }
96
116
  /** Insert a new record, assigning it the next sequence number. */
@@ -98,7 +118,7 @@ var Collection = class {
98
118
  return this.sqlite.transaction(() => {
99
119
  const seq = this.bumpCollectionSeq();
100
120
  const stored = { seq, value };
101
- this.sqlite.prepare(`INSERT INTO emulators_records (namespace, collection, id, seq, value)
121
+ this.sqlite.prepare(`INSERT INTO emulates_records (namespace, collection, id, seq, value)
102
122
  VALUES (?, ?, ?, ?, ?)
103
123
  ON CONFLICT(namespace, collection, id) DO UPDATE SET seq = excluded.seq, value = excluded.value`).run(this.namespace, this.collectionName, id, seq, JSON.stringify(stored));
104
124
  return stored;
@@ -107,25 +127,25 @@ var Collection = class {
107
127
  /** Replace an existing record's value, keeping its position. */
108
128
  update(id, value) {
109
129
  return this.sqlite.transaction(() => {
110
- const row = this.sqlite.prepare("SELECT seq, value FROM emulators_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
130
+ const row = this.sqlite.prepare("SELECT seq, value FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
111
131
  if (!row)
112
132
  return void 0;
113
133
  const stored = { seq: row.seq, value };
114
- this.sqlite.prepare("UPDATE emulators_records SET value = ? WHERE namespace = ? AND collection = ? AND id = ?").run(JSON.stringify(stored), this.namespace, this.collectionName, id);
134
+ this.sqlite.prepare("UPDATE emulates_records SET value = ? WHERE namespace = ? AND collection = ? AND id = ?").run(JSON.stringify(stored), this.namespace, this.collectionName, id);
115
135
  return stored;
116
136
  });
117
137
  }
118
138
  delete(id) {
119
- const result = this.sqlite.prepare("DELETE FROM emulators_records WHERE namespace = ? AND collection = ? AND id = ?").run(this.namespace, this.collectionName, id);
139
+ const result = this.sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").run(this.namespace, this.collectionName, id);
120
140
  return result.changes > 0;
121
141
  }
122
142
  /** How many records the collection holds, without reading them. */
123
143
  count() {
124
- const row = this.sqlite.prepare("SELECT COUNT(*) AS n FROM emulators_records WHERE namespace = ? AND collection = ?").get(this.namespace, this.collectionName);
144
+ const row = this.sqlite.prepare("SELECT COUNT(*) AS n FROM emulates_records WHERE namespace = ? AND collection = ?").get(this.namespace, this.collectionName);
125
145
  return Number(row?.n ?? 0);
126
146
  }
127
147
  list(options = {}) {
128
- const rows = this.sqlite.prepare("SELECT id, seq, value FROM emulators_records WHERE namespace = ? AND collection = ?").all(this.namespace, this.collectionName);
148
+ const rows = this.sqlite.prepare("SELECT id, seq, value FROM emulates_records WHERE namespace = ? AND collection = ?").all(this.namespace, this.collectionName);
129
149
  const out = [];
130
150
  for (const row of rows) {
131
151
  const stored = JSON.parse(row.value);
@@ -174,9 +194,9 @@ var IdSequence = class {
174
194
  }
175
195
  next(prefix, length = 14) {
176
196
  return this.sqlite.transaction(() => {
177
- const row = this.sqlite.prepare("SELECT value FROM emulators_sequences WHERE namespace = ? AND name = ? AND kind = 'id'").get(this.namespace, prefix);
197
+ const row = this.sqlite.prepare("SELECT value FROM emulates_sequences WHERE namespace = ? AND name = ? AND kind = 'id'").get(this.namespace, prefix);
178
198
  const value = (row?.value ?? 0) + 1;
179
- this.sqlite.prepare(`INSERT INTO emulators_sequences (namespace, name, kind, value) VALUES (?, ?, 'id', ?)
199
+ this.sqlite.prepare(`INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, 'id', ?)
180
200
  ON CONFLICT(namespace, name, kind) DO UPDATE SET value = excluded.value`).run(this.namespace, prefix, value);
181
201
  return `${prefix}${opaqueToken(`${this.salt}:${prefix}:${value}`, length)}`;
182
202
  });
@@ -616,7 +636,7 @@ var serviceRoute = (template) => {
616
636
  offset = match.index + match[0].length;
617
637
  }
618
638
  expression += escapePattern(segment.slice(offset));
619
- return `:emulatorsSegment${index}{${expression}}`;
639
+ return `:emulatesSegment${index}{${expression}}`;
620
640
  }).join("/");
621
641
  return {
622
642
  path,
@@ -759,7 +779,7 @@ var json = (status, body) => new Response(JSON.stringify(body), {
759
779
  status,
760
780
  headers: { "content-type": "application/json; charset=utf-8" }
761
781
  });
762
- var adminError = (status, message) => json(status, { error: { type: "emulators_admin", message } });
782
+ var adminError = (status, message) => json(status, { error: { type: "emulates_admin", message } });
763
783
  var UNITS = {
764
784
  ms: 1,
765
785
  s: 1e3,
@@ -1629,18 +1649,18 @@ var adminUiRoutes = (service, ui, adminPrefix = ADMIN_PREFIX) => {
1629
1649
  // ../core/dist/snapshot.js
1630
1650
  var snapshotNamespace = (sqlite, namespace) => ({
1631
1651
  namespace,
1632
- records: sqlite.prepare("SELECT collection, id, seq, value FROM emulators_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1633
- sequences: sqlite.prepare("SELECT name, kind, value FROM emulators_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1652
+ records: sqlite.prepare("SELECT collection, id, seq, value FROM emulates_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1653
+ sequences: sqlite.prepare("SELECT name, kind, value FROM emulates_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1634
1654
  });
1635
1655
  var restoreNamespace = (sqlite, namespace, snapshot) => {
1636
1656
  sqlite.transaction(() => {
1637
- sqlite.prepare("DELETE FROM emulators_records WHERE namespace = ?").run(namespace);
1638
- sqlite.prepare("DELETE FROM emulators_sequences WHERE namespace = ?").run(namespace);
1639
- const record2 = sqlite.prepare("INSERT INTO emulators_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1657
+ sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ?").run(namespace);
1658
+ sqlite.prepare("DELETE FROM emulates_sequences WHERE namespace = ?").run(namespace);
1659
+ const record2 = sqlite.prepare("INSERT INTO emulates_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1640
1660
  for (const row of snapshot.records) {
1641
1661
  record2.run(namespace, row.collection, row.id, row.seq, row.value);
1642
1662
  }
1643
- const sequence = sqlite.prepare("INSERT INTO emulators_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1663
+ const sequence = sqlite.prepare("INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1644
1664
  for (const row of snapshot.sequences) {
1645
1665
  sequence.run(namespace, row.name, row.kind, row.value);
1646
1666
  }
@@ -1739,8 +1759,8 @@ var discoverCollections = (root) => {
1739
1759
  return found;
1740
1760
  };
1741
1761
  var storedNames = (sqlite, namespace) => {
1742
- const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulators_records WHERE namespace = ?").all(namespace);
1743
- const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulators_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1762
+ const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulates_records WHERE namespace = ?").all(namespace);
1763
+ const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulates_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1744
1764
  return [...records, ...sequences].map((row) => row.name);
1745
1765
  };
1746
1766
  var blankAccum = (name) => ({
@@ -1981,7 +2001,7 @@ var json3 = (status, body) => new Response(JSON.stringify(body), {
1981
2001
  status,
1982
2002
  headers: { "content-type": "application/json; charset=utf-8" }
1983
2003
  });
1984
- var adminError2 = (status, message) => json3(status, { error: { type: "emulators_admin", message } });
2004
+ var adminError2 = (status, message) => json3(status, { error: { type: "emulates_admin", message } });
1985
2005
  var fromResult = (result, status) => result.ok ? json3(status, result.value) : adminError2(result.status, result.message);
1986
2006
  var integerParam = (value) => {
1987
2007
  if (value === null)
@@ -2082,14 +2102,14 @@ var stateAdminRoutes = (routes) => {
2082
2102
  };
2083
2103
 
2084
2104
  // ../core/dist/version.js
2085
- var PACKAGE_VERSION = true ? "0.1.1" : UNRELEASED_VERSION;
2105
+ var PACKAGE_VERSION = true ? "1.0.0" : UNRELEASED_VERSION;
2086
2106
 
2087
2107
  // ../core/dist/webhooks.js
2088
2108
  var json4 = (status, body) => new Response(JSON.stringify(body), {
2089
2109
  status,
2090
2110
  headers: { "content-type": "application/json; charset=utf-8" }
2091
2111
  });
2092
- var adminError3 = (status, message) => json4(status, { error: { type: "emulators_admin", message } });
2112
+ var adminError3 = (status, message) => json4(status, { error: { type: "emulates_admin", message } });
2093
2113
  var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2094
2114
  var parseEndpoint = (value) => {
2095
2115
  if (!isRecord4(value) || typeof value.url !== "string")
@@ -2705,7 +2725,7 @@ var createRuntime = (options) => {
2705
2725
  log(400);
2706
2726
  return stamp(new Response(JSON.stringify({
2707
2727
  error: {
2708
- type: "emulators_admin",
2728
+ type: "emulates_admin",
2709
2729
  message: `${NAMESPACE_HEADER} must match ${NAMESPACE_PATTERN}`
2710
2730
  }
2711
2731
  }), { status: 400, headers: { "content-type": "application/json; charset=utf-8" } }));
@@ -2871,7 +2891,7 @@ var adminJson = (status, body) => new Response(JSON.stringify(body), {
2871
2891
  status,
2872
2892
  headers: { "content-type": "application/json; charset=utf-8" }
2873
2893
  });
2874
- var adminFail = (status, message) => adminJson(status, { error: { type: "emulators_admin", message } });
2894
+ var adminFail = (status, message) => adminJson(status, { error: { type: "emulates_admin", message } });
2875
2895
  var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2876
2896
  var credentialRoutes = (registry) => ({
2877
2897
  "GET /credentials": () => adminJson(200, {
@@ -3103,8 +3123,8 @@ var createContainer = (state, value, url, ids, now) => {
3103
3123
  let id;
3104
3124
  do {
3105
3125
  id = [...ids.next("", 32)].map((c) => c.charCodeAt(0).toString(16)).join("");
3106
- } while (state.containers.has(id) || !name && state.containers.list().some((c) => c.value.name === `emulators_${id.slice(0, 12)}`));
3107
- name ||= `emulators_${id.slice(0, 12)}`;
3126
+ } while (state.containers.has(id) || !name && state.containers.list().some((c) => c.value.name === `emulates_${id.slice(0, 12)}`));
3127
+ name ||= `emulates_${id.slice(0, 12)}`;
3108
3128
  config.Hostname ||= id.slice(0, 12);
3109
3129
  state.containers.insert(id, {
3110
3130
  id,
@@ -4086,4 +4106,4 @@ export {
4086
4106
  DOCKER_NAMESPACE,
4087
4107
  DockerAPI
4088
4108
  };
4089
- //# sourceMappingURL=chunk-NSXRVOHP.js.map
4109
+ //# sourceMappingURL=chunk-U6P6W4BK.js.map