@emulates/cognito 2.3.1 → 3.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/cognito
2
2
 
3
- ## 2.3.1 (2026-10-06)
3
+ ## 3.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
+ ## 2.3.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/cognito
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
  Stateful local emulator of Amazon Cognito User Pools for the AWS SDK and `amazon-cognito-identity-js`. It implements the authentication, user administration, group, federation, recovery, JWT, discovery, and JWKS surface the consumer app uses without contacting AWS.
6
6
 
@@ -20,7 +20,7 @@ Point `COGNITO_ENDPOINT` or the AWS SDK `endpoint` option at the served emulator
20
20
  import { createRuntime } from "@emulates/cognito"
21
21
 
22
22
  const cognito = createRuntime({
23
- poolId: "us-east-1_emulators",
23
+ poolId: "us-east-1_emulates",
24
24
  clientId: "emulates-client",
25
25
  users: [
26
26
  {
@@ -33,7 +33,7 @@ const cognito = createRuntime({
33
33
  })
34
34
  ```
35
35
 
36
- The Node adapter is `createServer()` from `./server`; the CLI is `npx emulates-cognito serve --port 8811 --pool-id us-east-1_emulators --client-id emulates-client`.
36
+ The Node adapter is `createServer()` from `./server`; the CLI is `npx emulates-cognito serve --port 8811 --pool-id us-east-1_emulates --client-id emulates-client`.
37
37
 
38
38
  ### AWS JSON operations
39
39
 
@@ -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
  });
@@ -875,7 +895,7 @@ var json = (status, body) => new Response(JSON.stringify(body), {
875
895
  status,
876
896
  headers: { "content-type": "application/json; charset=utf-8" }
877
897
  });
878
- var adminError = (status, message) => json(status, { error: { type: "emulators_admin", message } });
898
+ var adminError = (status, message) => json(status, { error: { type: "emulates_admin", message } });
879
899
  var UNITS = {
880
900
  ms: 1,
881
901
  s: 1e3,
@@ -1747,18 +1767,18 @@ var adminUiRoutes = (service, ui, adminPrefix = ADMIN_PREFIX) => {
1747
1767
  // ../core/dist/snapshot.js
1748
1768
  var snapshotNamespace = (sqlite, namespace) => ({
1749
1769
  namespace,
1750
- records: sqlite.prepare("SELECT collection, id, seq, value FROM emulators_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1751
- sequences: sqlite.prepare("SELECT name, kind, value FROM emulators_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1770
+ records: sqlite.prepare("SELECT collection, id, seq, value FROM emulates_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
1771
+ sequences: sqlite.prepare("SELECT name, kind, value FROM emulates_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
1752
1772
  });
1753
1773
  var restoreNamespace = (sqlite, namespace, snapshot) => {
1754
1774
  sqlite.transaction(() => {
1755
- sqlite.prepare("DELETE FROM emulators_records WHERE namespace = ?").run(namespace);
1756
- sqlite.prepare("DELETE FROM emulators_sequences WHERE namespace = ?").run(namespace);
1757
- const record = sqlite.prepare("INSERT INTO emulators_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1775
+ sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ?").run(namespace);
1776
+ sqlite.prepare("DELETE FROM emulates_sequences WHERE namespace = ?").run(namespace);
1777
+ const record = sqlite.prepare("INSERT INTO emulates_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
1758
1778
  for (const row of snapshot.records) {
1759
1779
  record.run(namespace, row.collection, row.id, row.seq, row.value);
1760
1780
  }
1761
- const sequence = sqlite.prepare("INSERT INTO emulators_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1781
+ const sequence = sqlite.prepare("INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
1762
1782
  for (const row of snapshot.sequences) {
1763
1783
  sequence.run(namespace, row.name, row.kind, row.value);
1764
1784
  }
@@ -1857,8 +1877,8 @@ var discoverCollections = (root) => {
1857
1877
  return found;
1858
1878
  };
1859
1879
  var storedNames = (sqlite, namespace) => {
1860
- const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulators_records WHERE namespace = ?").all(namespace);
1861
- const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulators_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1880
+ const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulates_records WHERE namespace = ?").all(namespace);
1881
+ const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulates_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
1862
1882
  return [...records, ...sequences].map((row) => row.name);
1863
1883
  };
1864
1884
  var blankAccum = (name) => ({
@@ -2099,7 +2119,7 @@ var json3 = (status, body) => new Response(JSON.stringify(body), {
2099
2119
  status,
2100
2120
  headers: { "content-type": "application/json; charset=utf-8" }
2101
2121
  });
2102
- var adminError2 = (status, message) => json3(status, { error: { type: "emulators_admin", message } });
2122
+ var adminError2 = (status, message) => json3(status, { error: { type: "emulates_admin", message } });
2103
2123
  var fromResult = (result, status) => result.ok ? json3(status, result.value) : adminError2(result.status, result.message);
2104
2124
  var integerParam = (value) => {
2105
2125
  if (value === null)
@@ -2200,14 +2220,14 @@ var stateAdminRoutes = (routes) => {
2200
2220
  };
2201
2221
 
2202
2222
  // ../core/dist/version.js
2203
- var PACKAGE_VERSION = true ? "2.3.1" : UNRELEASED_VERSION;
2223
+ var PACKAGE_VERSION = true ? "3.0.0" : UNRELEASED_VERSION;
2204
2224
 
2205
2225
  // ../core/dist/webhooks.js
2206
2226
  var json4 = (status, body) => new Response(JSON.stringify(body), {
2207
2227
  status,
2208
2228
  headers: { "content-type": "application/json; charset=utf-8" }
2209
2229
  });
2210
- var adminError3 = (status, message) => json4(status, { error: { type: "emulators_admin", message } });
2230
+ var adminError3 = (status, message) => json4(status, { error: { type: "emulates_admin", message } });
2211
2231
  var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2212
2232
  var parseEndpoint = (value) => {
2213
2233
  if (!isRecord4(value) || typeof value.url !== "string")
@@ -2809,7 +2829,7 @@ var createRuntime = (options) => {
2809
2829
  log(400);
2810
2830
  return stamp(new Response(JSON.stringify({
2811
2831
  error: {
2812
- type: "emulators_admin",
2832
+ type: "emulates_admin",
2813
2833
  message: `${NAMESPACE_HEADER} must match ${NAMESPACE_PATTERN}`
2814
2834
  }
2815
2835
  }), { status: 400, headers: { "content-type": "application/json; charset=utf-8" } }));
@@ -2975,7 +2995,7 @@ var adminJson = (status, body) => new Response(JSON.stringify(body), {
2975
2995
  status,
2976
2996
  headers: { "content-type": "application/json; charset=utf-8" }
2977
2997
  });
2978
- var adminFail = (status, message) => adminJson(status, { error: { type: "emulators_admin", message } });
2998
+ var adminFail = (status, message) => adminJson(status, { error: { type: "emulates_admin", message } });
2979
2999
  var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2980
3000
  var credentialRoutes = (registry) => ({
2981
3001
  "GET /credentials": () => adminJson(200, {
@@ -3187,7 +3207,7 @@ var admin = (runtime) => ({
3187
3207
  const input = body;
3188
3208
  if (!input || typeof input.username !== "string" || typeof input.password !== "string")
3189
3209
  return json5(
3190
- { error: { type: "emulators_admin", message: "username and password are required" } },
3210
+ { error: { type: "emulates_admin", message: "username and password are required" } },
3191
3211
  400
3192
3212
  );
3193
3213
  return json5(runtime.instance(namespace).state.put(input), 201);
@@ -3198,7 +3218,7 @@ var admin = (runtime) => ({
3198
3218
  username: user.username,
3199
3219
  confirmationCode: user.confirmationCode,
3200
3220
  resetCode: user.resetCode
3201
- }) : json5({ error: { type: "emulators_admin", message: "user not found" } }, 404);
3221
+ }) : json5({ error: { type: "emulates_admin", message: "user not found" } }, 404);
3202
3222
  },
3203
3223
  "POST /keys/rotate": ({ namespace, body }) => json5(
3204
3224
  runtime.instance(namespace).rotateSigningKey(body?.retainPrevious !== false)
@@ -3206,7 +3226,7 @@ var admin = (runtime) => ({
3206
3226
  "POST /sessions/revoke": ({ namespace, body }) => {
3207
3227
  const username = body?.username;
3208
3228
  if (typeof username !== "string")
3209
- return json5({ error: { type: "emulators_admin", message: "username is required" } }, 400);
3229
+ return json5({ error: { type: "emulates_admin", message: "username is required" } }, 400);
3210
3230
  const api = runtime.instance(namespace);
3211
3231
  for (const row of api.state.sessions.list({
3212
3232
  where: (session) => session.username === username
@@ -3268,7 +3288,7 @@ var CognitoAPI = class {
3268
3288
  this.sqlite = bootSqlite(options.sqlite);
3269
3289
  this.namespace = options.namespace ?? COGNITO_NAMESPACE;
3270
3290
  this.now = options.now ?? Date.now;
3271
- this.poolId = options.poolId ?? "us-east-1_emulators";
3291
+ this.poolId = options.poolId ?? "us-east-1_emulates";
3272
3292
  this.defaultClientId = options.clientId ?? "emulates-client";
3273
3293
  this.state = new CognitoState(this.sqlite, this.namespace, options.users ?? []);
3274
3294
  }
@@ -3632,4 +3652,4 @@ export {
3632
3652
  accessKeyCredential,
3633
3653
  CognitoAPI
3634
3654
  };
3635
- //# sourceMappingURL=chunk-ZLLODF3V.js.map
3655
+ //# sourceMappingURL=chunk-BU4ORISY.js.map