@emulates/ecs 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/ecs
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
@@ -47,7 +47,7 @@ designed for assertions and diagnosis by consuming test suites.
47
47
 
48
48
  ## Report a mismatch or missing capability
49
49
 
50
- Follow the [agent reporting contract](https://github.com/crvouga/emulators/blob/main/docs/REPORTING_ISSUES.md). Include package version,
50
+ Follow the [agent reporting contract](https://github.com/crvouga/emulates/blob/main/docs/REPORTING_ISSUES.md). Include package version,
51
51
  operation/command, a minimal redacted request, actual emulator result, expected oracle result or vendor
52
52
  documentation, and whether the mismatch appears in the matrix. Never include keys, tokens,
53
53
  customer data, prompts, PHI, card data, or unredacted recordings.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @emulates/ecs
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
  WIP AWS ECS Fargate RunTask control-plane emulator. It records task acceptance; it never starts
6
6
  containers. Wire contract follows [RunTask](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html).
@@ -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(prefix2, 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, prefix2);
197
+ const row = this.sqlite.prepare("SELECT value FROM emulates_sequences WHERE namespace = ? AND name = ? AND kind = 'id'").get(this.namespace, prefix2);
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, prefix2, value);
181
201
  return `${prefix2}${opaqueToken(`${this.salt}:${prefix2}:${value}`, length)}`;
182
202
  });
@@ -884,7 +904,7 @@ var json = (status, body) => new Response(JSON.stringify(body), {
884
904
  status,
885
905
  headers: { "content-type": "application/json; charset=utf-8" }
886
906
  });
887
- var adminError = (status, message) => json(status, { error: { type: "emulators_admin", message } });
907
+ var adminError = (status, message) => json(status, { error: { type: "emulates_admin", message } });
888
908
  var UNITS = {
889
909
  ms: 1,
890
910
  s: 1e3,
@@ -1756,18 +1776,18 @@ var adminUiRoutes = (service, ui, adminPrefix = ADMIN_PREFIX) => {
1756
1776
  // ../core/dist/snapshot.js
1757
1777
  var snapshotNamespace = (sqlite, namespace) => ({
1758
1778
  namespace,
1759
- records: sqlite.prepare("SELECT collection, id, seq, value FROM emulators_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1760
- sequences: sqlite.prepare("SELECT name, kind, value FROM emulators_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1779
+ records: sqlite.prepare("SELECT collection, id, seq, value FROM emulates_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1780
+ sequences: sqlite.prepare("SELECT name, kind, value FROM emulates_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1761
1781
  });
1762
1782
  var restoreNamespace = (sqlite, namespace, snapshot) => {
1763
1783
  sqlite.transaction(() => {
1764
- sqlite.prepare("DELETE FROM emulators_records WHERE namespace = ?").run(namespace);
1765
- sqlite.prepare("DELETE FROM emulators_sequences WHERE namespace = ?").run(namespace);
1766
- const record = sqlite.prepare("INSERT INTO emulators_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1784
+ sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ?").run(namespace);
1785
+ sqlite.prepare("DELETE FROM emulates_sequences WHERE namespace = ?").run(namespace);
1786
+ const record = sqlite.prepare("INSERT INTO emulates_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1767
1787
  for (const row of snapshot.records) {
1768
1788
  record.run(namespace, row.collection, row.id, row.seq, row.value);
1769
1789
  }
1770
- const sequence = sqlite.prepare("INSERT INTO emulators_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1790
+ const sequence = sqlite.prepare("INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1771
1791
  for (const row of snapshot.sequences) {
1772
1792
  sequence.run(namespace, row.name, row.kind, row.value);
1773
1793
  }
@@ -1866,8 +1886,8 @@ var discoverCollections = (root) => {
1866
1886
  return found;
1867
1887
  };
1868
1888
  var storedNames = (sqlite, namespace) => {
1869
- const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulators_records WHERE namespace = ?").all(namespace);
1870
- const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulators_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1889
+ const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulates_records WHERE namespace = ?").all(namespace);
1890
+ const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulates_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1871
1891
  return [...records, ...sequences].map((row) => row.name);
1872
1892
  };
1873
1893
  var blankAccum = (name) => ({
@@ -2108,7 +2128,7 @@ var json3 = (status, body) => new Response(JSON.stringify(body), {
2108
2128
  status,
2109
2129
  headers: { "content-type": "application/json; charset=utf-8" }
2110
2130
  });
2111
- var adminError2 = (status, message) => json3(status, { error: { type: "emulators_admin", message } });
2131
+ var adminError2 = (status, message) => json3(status, { error: { type: "emulates_admin", message } });
2112
2132
  var fromResult = (result, status) => result.ok ? json3(status, result.value) : adminError2(result.status, result.message);
2113
2133
  var integerParam = (value) => {
2114
2134
  if (value === null)
@@ -2209,14 +2229,14 @@ var stateAdminRoutes = (routes) => {
2209
2229
  };
2210
2230
 
2211
2231
  // ../core/dist/version.js
2212
- var PACKAGE_VERSION = true ? "0.1.1" : UNRELEASED_VERSION;
2232
+ var PACKAGE_VERSION = true ? "1.0.0" : UNRELEASED_VERSION;
2213
2233
 
2214
2234
  // ../core/dist/webhooks.js
2215
2235
  var json4 = (status, body) => new Response(JSON.stringify(body), {
2216
2236
  status,
2217
2237
  headers: { "content-type": "application/json; charset=utf-8" }
2218
2238
  });
2219
- var adminError3 = (status, message) => json4(status, { error: { type: "emulators_admin", message } });
2239
+ var adminError3 = (status, message) => json4(status, { error: { type: "emulates_admin", message } });
2220
2240
  var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2221
2241
  var parseEndpoint = (value) => {
2222
2242
  if (!isRecord4(value) || typeof value.url !== "string")
@@ -2818,7 +2838,7 @@ var createRuntime = (options) => {
2818
2838
  log(400);
2819
2839
  return stamp(new Response(JSON.stringify({
2820
2840
  error: {
2821
- type: "emulators_admin",
2841
+ type: "emulates_admin",
2822
2842
  message: `${NAMESPACE_HEADER} must match ${NAMESPACE_PATTERN}`
2823
2843
  }
2824
2844
  }), { status: 400, headers: { "content-type": "application/json; charset=utf-8" } }));
@@ -2984,7 +3004,7 @@ var adminJson = (status, body) => new Response(JSON.stringify(body), {
2984
3004
  status,
2985
3005
  headers: { "content-type": "application/json; charset=utf-8" }
2986
3006
  });
2987
- var adminFail = (status, message) => adminJson(status, { error: { type: "emulators_admin", message } });
3007
+ var adminFail = (status, message) => adminJson(status, { error: { type: "emulates_admin", message } });
2988
3008
  var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2989
3009
  var credentialRoutes = (registry) => ({
2990
3010
  "GET /credentials": () => adminJson(200, {
@@ -3272,4 +3292,4 @@ export {
3272
3292
  DEFAULT_TASK_DEFINITION,
3273
3293
  ECSAPI
3274
3294
  };
3275
- //# sourceMappingURL=chunk-3ZZ7W2QG.js.map
3295
+ //# sourceMappingURL=chunk-C2SUTQ6J.js.map