@emulates/cloudcontrol 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 +12 -2
- package/DISCOVERY.md +1 -1
- package/README.md +1 -1
- package/dist/{chunk-NUJZDZXB.js → chunk-3UTVNUF3.js} +53 -33
- package/dist/chunk-3UTVNUF3.js.map +7 -0
- package/dist/{chunk-ZDT2BIBT.js → chunk-MGG75IFP.js} +3 -3
- package/dist/{chunk-ZDT2BIBT.js.map → chunk-MGG75IFP.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +5 -5
- package/dist/chunk-NUJZDZXB.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# Changelog — @emulates/cloudcontrol
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 1.0.0 (2026-10-07)
|
|
4
4
|
|
|
5
|
-
|
|
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/
|
|
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/cloudcontrol
|
|
2
2
|
|
|
3
|
-
> Part of [Emulates](https://github.com/crvouga/
|
|
3
|
+
> Part of [Emulates](https://github.com/crvouga/emulates): high-fidelity, in-process emulators for APIs and databases.
|
|
4
4
|
|
|
5
5
|
Transport scaffold for Amazon Cloud Control API. ESM; Node 22+ or Bun 1.2+.
|
|
6
6
|
|
|
@@ -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
|
|
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
|
|
45
|
-
ON
|
|
46
|
-
CREATE TABLE IF NOT EXISTS
|
|
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
|
|
62
|
-
sqlite.prepare("DELETE FROM
|
|
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
|
|
|
@@ -4220,9 +4240,9 @@ var Collection = class {
|
|
|
4220
4240
|
this.collectionName = collectionName;
|
|
4221
4241
|
}
|
|
4222
4242
|
bumpCollectionSeq() {
|
|
4223
|
-
const row = this.sqlite.prepare("SELECT value FROM
|
|
4243
|
+
const row = this.sqlite.prepare("SELECT value FROM emulates_sequences WHERE namespace = ? AND name = ? AND kind = 'collection'").get(this.namespace, this.collectionName);
|
|
4224
4244
|
const next = (row?.value ?? 0) + 1;
|
|
4225
|
-
this.sqlite.prepare(`INSERT INTO
|
|
4245
|
+
this.sqlite.prepare(`INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, 'collection', ?)
|
|
4226
4246
|
ON CONFLICT(namespace, name, kind) DO UPDATE SET value = excluded.value`).run(this.namespace, this.collectionName, next);
|
|
4227
4247
|
return next;
|
|
4228
4248
|
}
|
|
@@ -4230,13 +4250,13 @@ var Collection = class {
|
|
|
4230
4250
|
return this.sqlite.transaction(() => this.bumpCollectionSeq());
|
|
4231
4251
|
}
|
|
4232
4252
|
get(id) {
|
|
4233
|
-
const row = this.sqlite.prepare("SELECT value FROM
|
|
4253
|
+
const row = this.sqlite.prepare("SELECT value FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
|
|
4234
4254
|
if (!row)
|
|
4235
4255
|
return void 0;
|
|
4236
4256
|
return JSON.parse(row.value).value;
|
|
4237
4257
|
}
|
|
4238
4258
|
has(id) {
|
|
4239
|
-
const row = this.sqlite.prepare("SELECT 1 AS ok FROM
|
|
4259
|
+
const row = this.sqlite.prepare("SELECT 1 AS ok FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
|
|
4240
4260
|
return row !== void 0;
|
|
4241
4261
|
}
|
|
4242
4262
|
/** Insert a new record, assigning it the next sequence number. */
|
|
@@ -4244,7 +4264,7 @@ var Collection = class {
|
|
|
4244
4264
|
return this.sqlite.transaction(() => {
|
|
4245
4265
|
const seq = this.bumpCollectionSeq();
|
|
4246
4266
|
const stored = { seq, value };
|
|
4247
|
-
this.sqlite.prepare(`INSERT INTO
|
|
4267
|
+
this.sqlite.prepare(`INSERT INTO emulates_records (namespace, collection, id, seq, value)
|
|
4248
4268
|
VALUES (?, ?, ?, ?, ?)
|
|
4249
4269
|
ON CONFLICT(namespace, collection, id) DO UPDATE SET seq = excluded.seq, value = excluded.value`).run(this.namespace, this.collectionName, id, seq, JSON.stringify(stored));
|
|
4250
4270
|
return stored;
|
|
@@ -4253,25 +4273,25 @@ var Collection = class {
|
|
|
4253
4273
|
/** Replace an existing record's value, keeping its position. */
|
|
4254
4274
|
update(id, value) {
|
|
4255
4275
|
return this.sqlite.transaction(() => {
|
|
4256
|
-
const row = this.sqlite.prepare("SELECT seq, value FROM
|
|
4276
|
+
const row = this.sqlite.prepare("SELECT seq, value FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").get(this.namespace, this.collectionName, id);
|
|
4257
4277
|
if (!row)
|
|
4258
4278
|
return void 0;
|
|
4259
4279
|
const stored = { seq: row.seq, value };
|
|
4260
|
-
this.sqlite.prepare("UPDATE
|
|
4280
|
+
this.sqlite.prepare("UPDATE emulates_records SET value = ? WHERE namespace = ? AND collection = ? AND id = ?").run(JSON.stringify(stored), this.namespace, this.collectionName, id);
|
|
4261
4281
|
return stored;
|
|
4262
4282
|
});
|
|
4263
4283
|
}
|
|
4264
4284
|
delete(id) {
|
|
4265
|
-
const result = this.sqlite.prepare("DELETE FROM
|
|
4285
|
+
const result = this.sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ? AND collection = ? AND id = ?").run(this.namespace, this.collectionName, id);
|
|
4266
4286
|
return result.changes > 0;
|
|
4267
4287
|
}
|
|
4268
4288
|
/** How many records the collection holds, without reading them. */
|
|
4269
4289
|
count() {
|
|
4270
|
-
const row = this.sqlite.prepare("SELECT COUNT(*) AS n FROM
|
|
4290
|
+
const row = this.sqlite.prepare("SELECT COUNT(*) AS n FROM emulates_records WHERE namespace = ? AND collection = ?").get(this.namespace, this.collectionName);
|
|
4271
4291
|
return Number(row?.n ?? 0);
|
|
4272
4292
|
}
|
|
4273
4293
|
list(options = {}) {
|
|
4274
|
-
const rows = this.sqlite.prepare("SELECT id, seq, value FROM
|
|
4294
|
+
const rows = this.sqlite.prepare("SELECT id, seq, value FROM emulates_records WHERE namespace = ? AND collection = ?").all(this.namespace, this.collectionName);
|
|
4275
4295
|
const out = [];
|
|
4276
4296
|
for (const row of rows) {
|
|
4277
4297
|
const stored = JSON.parse(row.value);
|
|
@@ -4320,9 +4340,9 @@ var IdSequence = class {
|
|
|
4320
4340
|
}
|
|
4321
4341
|
next(prefix, length = 14) {
|
|
4322
4342
|
return this.sqlite.transaction(() => {
|
|
4323
|
-
const row = this.sqlite.prepare("SELECT value FROM
|
|
4343
|
+
const row = this.sqlite.prepare("SELECT value FROM emulates_sequences WHERE namespace = ? AND name = ? AND kind = 'id'").get(this.namespace, prefix);
|
|
4324
4344
|
const value = (row?.value ?? 0) + 1;
|
|
4325
|
-
this.sqlite.prepare(`INSERT INTO
|
|
4345
|
+
this.sqlite.prepare(`INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, 'id', ?)
|
|
4326
4346
|
ON CONFLICT(namespace, name, kind) DO UPDATE SET value = excluded.value`).run(this.namespace, prefix, value);
|
|
4327
4347
|
return `${prefix}${opaqueToken(`${this.salt}:${prefix}:${value}`, length)}`;
|
|
4328
4348
|
});
|
|
@@ -5159,7 +5179,7 @@ var json = (status, body) => new Response(JSON.stringify(body), {
|
|
|
5159
5179
|
status,
|
|
5160
5180
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
5161
5181
|
});
|
|
5162
|
-
var adminError = (status, message) => json(status, { error: { type: "
|
|
5182
|
+
var adminError = (status, message) => json(status, { error: { type: "emulates_admin", message } });
|
|
5163
5183
|
var UNITS = {
|
|
5164
5184
|
ms: 1,
|
|
5165
5185
|
s: 1e3,
|
|
@@ -6031,18 +6051,18 @@ var adminUiRoutes = (service, ui, adminPrefix = ADMIN_PREFIX) => {
|
|
|
6031
6051
|
// ../core/dist/snapshot.js
|
|
6032
6052
|
var snapshotNamespace = (sqlite, namespace) => ({
|
|
6033
6053
|
namespace,
|
|
6034
|
-
records: sqlite.prepare("SELECT collection, id, seq, value FROM
|
|
6035
|
-
sequences: sqlite.prepare("SELECT name, kind, value FROM
|
|
6054
|
+
records: sqlite.prepare("SELECT collection, id, seq, value FROM emulates_records WHERE namespace = ? ORDER BY collection, seq").all(namespace),
|
|
6055
|
+
sequences: sqlite.prepare("SELECT name, kind, value FROM emulates_sequences WHERE namespace = ? ORDER BY name, kind").all(namespace)
|
|
6036
6056
|
});
|
|
6037
6057
|
var restoreNamespace = (sqlite, namespace, snapshot) => {
|
|
6038
6058
|
sqlite.transaction(() => {
|
|
6039
|
-
sqlite.prepare("DELETE FROM
|
|
6040
|
-
sqlite.prepare("DELETE FROM
|
|
6041
|
-
const record = sqlite.prepare("INSERT INTO
|
|
6059
|
+
sqlite.prepare("DELETE FROM emulates_records WHERE namespace = ?").run(namespace);
|
|
6060
|
+
sqlite.prepare("DELETE FROM emulates_sequences WHERE namespace = ?").run(namespace);
|
|
6061
|
+
const record = sqlite.prepare("INSERT INTO emulates_records (namespace, collection, id, seq, value) VALUES (?, ?, ?, ?, ?)");
|
|
6042
6062
|
for (const row of snapshot.records) {
|
|
6043
6063
|
record.run(namespace, row.collection, row.id, row.seq, row.value);
|
|
6044
6064
|
}
|
|
6045
|
-
const sequence = sqlite.prepare("INSERT INTO
|
|
6065
|
+
const sequence = sqlite.prepare("INSERT INTO emulates_sequences (namespace, name, kind, value) VALUES (?, ?, ?, ?)");
|
|
6046
6066
|
for (const row of snapshot.sequences) {
|
|
6047
6067
|
sequence.run(namespace, row.name, row.kind, row.value);
|
|
6048
6068
|
}
|
|
@@ -6141,8 +6161,8 @@ var discoverCollections = (root) => {
|
|
|
6141
6161
|
return found;
|
|
6142
6162
|
};
|
|
6143
6163
|
var storedNames = (sqlite, namespace) => {
|
|
6144
|
-
const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM
|
|
6145
|
-
const sequences = sqlite.prepare("SELECT DISTINCT name FROM
|
|
6164
|
+
const records = sqlite.prepare("SELECT DISTINCT collection AS name FROM emulates_records WHERE namespace = ?").all(namespace);
|
|
6165
|
+
const sequences = sqlite.prepare("SELECT DISTINCT name FROM emulates_sequences WHERE namespace = ? AND kind = 'collection'").all(namespace);
|
|
6146
6166
|
return [...records, ...sequences].map((row) => row.name);
|
|
6147
6167
|
};
|
|
6148
6168
|
var blankAccum = (name) => ({
|
|
@@ -6383,7 +6403,7 @@ var json3 = (status, body) => new Response(JSON.stringify(body), {
|
|
|
6383
6403
|
status,
|
|
6384
6404
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
6385
6405
|
});
|
|
6386
|
-
var adminError2 = (status, message) => json3(status, { error: { type: "
|
|
6406
|
+
var adminError2 = (status, message) => json3(status, { error: { type: "emulates_admin", message } });
|
|
6387
6407
|
var fromResult = (result, status) => result.ok ? json3(status, result.value) : adminError2(result.status, result.message);
|
|
6388
6408
|
var integerParam = (value) => {
|
|
6389
6409
|
if (value === null)
|
|
@@ -6484,14 +6504,14 @@ var stateAdminRoutes = (routes) => {
|
|
|
6484
6504
|
};
|
|
6485
6505
|
|
|
6486
6506
|
// ../core/dist/version.js
|
|
6487
|
-
var PACKAGE_VERSION = true ? "0.
|
|
6507
|
+
var PACKAGE_VERSION = true ? "1.0.0" : UNRELEASED_VERSION;
|
|
6488
6508
|
|
|
6489
6509
|
// ../core/dist/webhooks.js
|
|
6490
6510
|
var json4 = (status, body) => new Response(JSON.stringify(body), {
|
|
6491
6511
|
status,
|
|
6492
6512
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
6493
6513
|
});
|
|
6494
|
-
var adminError3 = (status, message) => json4(status, { error: { type: "
|
|
6514
|
+
var adminError3 = (status, message) => json4(status, { error: { type: "emulates_admin", message } });
|
|
6495
6515
|
var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6496
6516
|
var parseEndpoint = (value) => {
|
|
6497
6517
|
if (!isRecord4(value) || typeof value.url !== "string")
|
|
@@ -7093,7 +7113,7 @@ var createRuntime = (options) => {
|
|
|
7093
7113
|
log(400);
|
|
7094
7114
|
return stamp(new Response(JSON.stringify({
|
|
7095
7115
|
error: {
|
|
7096
|
-
type: "
|
|
7116
|
+
type: "emulates_admin",
|
|
7097
7117
|
message: `${NAMESPACE_HEADER} must match ${NAMESPACE_PATTERN}`
|
|
7098
7118
|
}
|
|
7099
7119
|
}), { status: 400, headers: { "content-type": "application/json; charset=utf-8" } }));
|
|
@@ -7259,7 +7279,7 @@ var adminJson = (status, body) => new Response(JSON.stringify(body), {
|
|
|
7259
7279
|
status,
|
|
7260
7280
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
7261
7281
|
});
|
|
7262
|
-
var adminFail = (status, message) => adminJson(status, { error: { type: "
|
|
7282
|
+
var adminFail = (status, message) => adminJson(status, { error: { type: "emulates_admin", message } });
|
|
7263
7283
|
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7264
7284
|
var credentialRoutes = (registry) => ({
|
|
7265
7285
|
"GET /credentials": () => adminJson(200, {
|
|
@@ -7371,4 +7391,4 @@ export {
|
|
|
7371
7391
|
createRuntime2 as createRuntime,
|
|
7372
7392
|
CloudcontrolAPI
|
|
7373
7393
|
};
|
|
7374
|
-
//# sourceMappingURL=chunk-
|
|
7394
|
+
//# sourceMappingURL=chunk-3UTVNUF3.js.map
|