@lossless.org/client 1.9.0 → 1.11.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@lossless.org/client',
6
- version: '1.9.0',
6
+ version: '1.11.0',
7
7
  description: 'One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.'
8
8
  };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDBGQUEwRjtDQUN4RyxDQUFBIn0=
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLDBGQUEwRjtDQUN4RyxDQUFBIn0=
@@ -23,32 +23,61 @@ export declare class EasyStore<T> {
23
23
  private easyStorePromise?;
24
24
  private getEasyStore;
25
25
  /**
26
- * reads all keyValue pairs at once and returns them
26
+ * Runs store operations one at a time, in the order they were called. Every
27
+ * read and write of this instance goes through here, so a write builds its
28
+ * next state from the state every earlier write left, and a read never sees
29
+ * the state of a write whose save has not resolved yet. A rejected operation
30
+ * does not stop the ones queued behind it.
27
31
  */
28
- readAll(): Promise<any>;
32
+ private operationQueue;
33
+ private runExclusive;
29
34
  /**
30
- * reads a keyValueFile from disk
35
+ * Persists `nextDataArg` as the store's data. The document's `save()` writes
36
+ * the instance's own fields, so the next state is installed for the save and
37
+ * the previous one is put back when the save rejects: a failed write leaves
38
+ * the cache as it was. Callers hold the operation queue.
39
+ */
40
+ private commit;
41
+ /**
42
+ * reads all keyValue pairs at once and returns them as a copy in the
43
+ * persisted form: mutating the result does not change the store, and later
44
+ * writes do not change the result.
45
+ */
46
+ readAll(): Promise<Partial<T>>;
47
+ /**
48
+ * reads one key and returns a copy of its value in the persisted form, or
49
+ * `undefined` when the key is absent
31
50
  */
32
51
  readKey<TKey extends keyof T>(keyArg: TKey): Promise<Partial<T>[TKey]>;
33
52
  /**
34
- * writes a specific key to the keyValueStore
53
+ * writes a specific key to the keyValueStore. The store keeps a copy, so
54
+ * mutating `valueArg` afterwards does not change the store. When the save
55
+ * rejects, the store keeps its previous state.
35
56
  */
36
57
  writeKey<TKey extends keyof T>(keyArg: TKey, valueArg: T[TKey]): Promise<void>;
58
+ /**
59
+ * deletes a key. When the save rejects, the store keeps its previous state.
60
+ */
37
61
  deleteKey(keyArg: keyof T): Promise<void>;
38
62
  /**
39
63
  * merges all keyValue pairs from the object argument into the store.
40
64
  * Existing keys that are not present in `keyValueObject` are preserved.
41
65
  * To overwrite the entire store and drop missing keys, use `replace()`.
66
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
67
+ * change the store. When the save rejects, the store keeps its previous state.
42
68
  */
43
69
  writeAll(keyValueObject: Partial<T>): Promise<void>;
44
70
  /**
45
71
  * atomically replaces the entire store with the given object.
46
72
  * Unlike `writeAll` (which merges), `replace` clears any keys not
47
73
  * present in `keyValueObject`. Useful when you need to drop a key.
74
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
75
+ * change the store. When the save rejects, the store keeps its previous state.
48
76
  */
49
77
  replace(keyValueObject: Partial<T>): Promise<void>;
50
78
  /**
51
- * wipes a key value store from disk
79
+ * wipes a key value store from disk. When the save rejects, the store keeps
80
+ * its previous state.
52
81
  */
53
82
  wipe(): Promise<void>;
54
83
  cleanUpEphemeral(): Promise<void>;
@@ -91,6 +91,21 @@ const getEasyStoreClassForDb = (smartdataDbArg) => {
91
91
  easyStoreClassByDb.set(smartdataDbArg, SmartdataEasyStore);
92
92
  return SmartdataEasyStore;
93
93
  };
94
+ /**
95
+ * Copies a store value into the form the store persists: undefined object
96
+ * properties are dropped, an undefined array element becomes null and every
97
+ * value takes its BSON form, exactly as a save and a later read from the
98
+ * database do. The copy shares no object with the argument, so neither side can
99
+ * change the other afterwards. A value BSON cannot encode (a cycle, for
100
+ * example) throws here, before the store's cache is touched.
101
+ */
102
+ const copyInPersistedForm = (valueArg) => {
103
+ if (valueArg === undefined) {
104
+ return valueArg;
105
+ }
106
+ const document = plugins.mongodb.BSON.deserialize(plugins.mongodb.BSON.serialize({ value: valueArg }, { ignoreUndefined: true }));
107
+ return document.value;
108
+ };
94
109
  /**
95
110
  * EasyStore allows the storage of easy objects. It also allows easy sharing of the object between different instances
96
111
  */
@@ -148,59 +163,118 @@ export class EasyStore {
148
163
  return deferred.promise;
149
164
  }
150
165
  /**
151
- * reads all keyValue pairs at once and returns them
166
+ * Runs store operations one at a time, in the order they were called. Every
167
+ * read and write of this instance goes through here, so a write builds its
168
+ * next state from the state every earlier write left, and a read never sees
169
+ * the state of a write whose save has not resolved yet. A rejected operation
170
+ * does not stop the ones queued behind it.
171
+ */
172
+ operationQueue = Promise.resolve();
173
+ runExclusive(operationArg) {
174
+ const result = this.operationQueue.then(operationArg);
175
+ this.operationQueue = result.then(() => undefined, () => undefined);
176
+ return result;
177
+ }
178
+ /**
179
+ * Persists `nextDataArg` as the store's data. The document's `save()` writes
180
+ * the instance's own fields, so the next state is installed for the save and
181
+ * the previous one is put back when the save rejects: a failed write leaves
182
+ * the cache as it was. Callers hold the operation queue.
183
+ */
184
+ async commit(easyStoreArg, nextDataArg) {
185
+ const previousData = easyStoreArg.data;
186
+ easyStoreArg.data = nextDataArg;
187
+ try {
188
+ await easyStoreArg.save();
189
+ }
190
+ catch (error) {
191
+ easyStoreArg.data = previousData;
192
+ throw error;
193
+ }
194
+ }
195
+ /**
196
+ * reads all keyValue pairs at once and returns them as a copy in the
197
+ * persisted form: mutating the result does not change the store, and later
198
+ * writes do not change the result.
152
199
  */
153
200
  async readAll() {
154
- const easyStore = await this.getEasyStore();
155
- return easyStore.data;
201
+ return this.runExclusive(async () => {
202
+ const easyStore = await this.getEasyStore();
203
+ return copyInPersistedForm(easyStore.data);
204
+ });
156
205
  }
157
206
  /**
158
- * reads a keyValueFile from disk
207
+ * reads one key and returns a copy of its value in the persisted form, or
208
+ * `undefined` when the key is absent
159
209
  */
160
210
  async readKey(keyArg) {
161
- const easyStore = await this.getEasyStore();
162
- return easyStore.data[keyArg];
211
+ return this.runExclusive(async () => {
212
+ const easyStore = await this.getEasyStore();
213
+ return copyInPersistedForm(easyStore.data[keyArg]);
214
+ });
163
215
  }
164
216
  /**
165
- * writes a specific key to the keyValueStore
217
+ * writes a specific key to the keyValueStore. The store keeps a copy, so
218
+ * mutating `valueArg` afterwards does not change the store. When the save
219
+ * rejects, the store keeps its previous state.
166
220
  */
167
221
  async writeKey(keyArg, valueArg) {
168
- const easyStore = await this.getEasyStore();
169
- easyStore.data[keyArg] = valueArg;
170
- await easyStore.save();
222
+ const value = copyInPersistedForm(valueArg);
223
+ await this.runExclusive(async () => {
224
+ const easyStore = await this.getEasyStore();
225
+ const nextData = { ...easyStore.data };
226
+ nextData[keyArg] = value;
227
+ await this.commit(easyStore, nextData);
228
+ });
171
229
  }
230
+ /**
231
+ * deletes a key. When the save rejects, the store keeps its previous state.
232
+ */
172
233
  async deleteKey(keyArg) {
173
- const easyStore = await this.getEasyStore();
174
- delete easyStore.data[keyArg];
175
- await easyStore.save();
234
+ await this.runExclusive(async () => {
235
+ const easyStore = await this.getEasyStore();
236
+ const nextData = { ...easyStore.data };
237
+ delete nextData[keyArg];
238
+ await this.commit(easyStore, nextData);
239
+ });
176
240
  }
177
241
  /**
178
242
  * merges all keyValue pairs from the object argument into the store.
179
243
  * Existing keys that are not present in `keyValueObject` are preserved.
180
244
  * To overwrite the entire store and drop missing keys, use `replace()`.
245
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
246
+ * change the store. When the save rejects, the store keeps its previous state.
181
247
  */
182
248
  async writeAll(keyValueObject) {
183
- const easyStore = await this.getEasyStore();
184
- easyStore.data = { ...easyStore.data, ...keyValueObject };
185
- await easyStore.save();
249
+ const values = copyInPersistedForm(keyValueObject);
250
+ await this.runExclusive(async () => {
251
+ const easyStore = await this.getEasyStore();
252
+ await this.commit(easyStore, { ...easyStore.data, ...values });
253
+ });
186
254
  }
187
255
  /**
188
256
  * atomically replaces the entire store with the given object.
189
257
  * Unlike `writeAll` (which merges), `replace` clears any keys not
190
258
  * present in `keyValueObject`. Useful when you need to drop a key.
259
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
260
+ * change the store. When the save rejects, the store keeps its previous state.
191
261
  */
192
262
  async replace(keyValueObject) {
193
- const easyStore = await this.getEasyStore();
194
- easyStore.data = { ...keyValueObject };
195
- await easyStore.save();
263
+ const values = copyInPersistedForm(keyValueObject);
264
+ await this.runExclusive(async () => {
265
+ const easyStore = await this.getEasyStore();
266
+ await this.commit(easyStore, values);
267
+ });
196
268
  }
197
269
  /**
198
- * wipes a key value store from disk
270
+ * wipes a key value store from disk. When the save rejects, the store keeps
271
+ * its previous state.
199
272
  */
200
273
  async wipe() {
201
- const easyStore = await this.getEasyStore();
202
- easyStore.data = {};
203
- await easyStore.save();
274
+ await this.runExclusive(async () => {
275
+ const easyStore = await this.getEasyStore();
276
+ await this.commit(easyStore, {});
277
+ });
204
278
  }
205
279
  async cleanUpEphemeral() {
206
280
  // Clean up ephemeral data periodically while connected
@@ -211,4 +285,4 @@ export class EasyStore {
211
285
  }
212
286
  }
213
287
  }
214
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lYXN5c3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMuZWFzeXN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRTdELE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxPQUFPLEVBQW9CLENBQUM7QUFFM0QsTUFBTSxzQkFBc0IsR0FBRyxDQUFJLGNBQTJCLEVBQUUsRUFBRTtJQUNoRSxNQUFNLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0QsSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUNsQixPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO1FBRUssa0JBQWtCO2dDQUR2QixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsY0FBYyxDQUFDOzs7OzBCQUNBLGNBQWM7Ozs7Ozs7Ozs7Ozs7c0NBQXRCLFNBQVEsV0FHaEM7Ozs7c0NBQ0UsR0FBRyxFQUFFO3lDQUdMLElBQUksRUFBRTt3Q0FNTixJQUFJLEVBQUU7b0NBR04sSUFBSSxFQUFFO2dCQVhQLG9LQUFPLE1BQU0sNkJBQU4sTUFBTSx1RkFBVTtnQkFHdkIsNktBQU8sU0FBUyw2QkFBVCxTQUFTLDZGQUdkO2dCQUdGLDBLQUFBLFFBQVEsNkJBQVIsUUFBUSwyRkFBVTtnQkFHbEIsOEpBQU8sSUFBSSw2QkFBSixJQUFJLG1GQUFjO2dCQWpCM0IsNktBa0JDOzs7Z0JBbEJLLHVEQUFrQjs7WUFLZixNQUFN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
288
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lYXN5c3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMuZWFzeXN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRTdELE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxPQUFPLEVBQW9CLENBQUM7QUFFM0QsTUFBTSxzQkFBc0IsR0FBRyxDQUFJLGNBQTJCLEVBQUUsRUFBRTtJQUNoRSxNQUFNLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0QsSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUNsQixPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO1FBRUssa0JBQWtCO2dDQUR2QixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsY0FBYyxDQUFDOzs7OzBCQUNBLGNBQWM7Ozs7Ozs7Ozs7Ozs7c0NBQXRCLFNBQVEsV0FHaEM7Ozs7c0NBQ0UsR0FBRyxFQUFFO3lDQUdMLElBQUksRUFBRTt3Q0FNTixJQUFJLEVBQUU7b0NBR04sSUFBSSxFQUFFO2dCQVhQLG9LQUFPLE1BQU0sNkJBQU4sTUFBTSx1RkFBVTtnQkFHdkIsNktBQU8sU0FBUyw2QkFBVCxTQUFTLDZGQUdkO2dCQUdGLDBLQUFBLFFBQVEsNkJBQVIsUUFBUSwyRkFBVTtnQkFHbEIsOEpBQU8sSUFBSSw2QkFBSixJQUFJLG1GQUFjO2dCQWpCM0IsNktBa0JDOzs7Z0JBbEJLLHVEQUFrQjs7WUFLZixNQUFN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
@@ -1,6 +1,7 @@
1
1
  import { SmartdataDb } from './classes.db.js';
2
2
  import { SmartDataDbDoc } from './classes.doc.js';
3
3
  import { SmartdataPersistenceError } from './classes.persistence.js';
4
+ /** A loopback TCP engine endpoint. */
4
5
  export interface ISmartdataTestConnection {
5
6
  /** Literal loopback IPv4, ::1, or localhost (normalized to 127.0.0.1). */
6
7
  host: string;
@@ -9,8 +10,20 @@ export interface ISmartdataTestConnection {
9
10
  username?: string;
10
11
  password?: string;
11
12
  }
13
+ /** A unix-domain socket engine endpoint. */
14
+ export interface ISmartdataTestSocketConnection {
15
+ /**
16
+ * Absolute canonical path ending in `.sock` (the MongoDB connection-string rule for
17
+ * socket hosts), at most 107 UTF-8 bytes, without control characters, lone surrogates or `%`.
18
+ */
19
+ socketPath: string;
20
+ /** Supply both credentials or neither. Authentication uses admin. */
21
+ username?: string;
22
+ password?: string;
23
+ }
24
+ export type TSmartdataTestConnection = ISmartdataTestConnection | ISmartdataTestSocketConnection;
12
25
  export interface ISmartdataTestDatabaseOptions {
13
- connection: ISmartdataTestConnection;
26
+ connection: TSmartdataTestConnection;
14
27
  /** Default 5000; maximum 120000 ms, shared by connection and ownership checks. */
15
28
  timeoutMs?: number;
16
29
  signal?: AbortSignal;
@@ -16,6 +16,32 @@ export class SmartdataTestDatabaseCreationError extends SmartdataPersistenceErro
16
16
  }
17
17
  const faultError = () => new SmartdataPersistenceError('invalid_argument', 'Fault data must be bounded, inert, canonical BSON with an explicit scalar _id.');
18
18
  const canonicalFaultDocument = (valueArg, maxBytesArg) => snapshotBoundedBsonDocument(valueArg, maxBytesArg, faultError);
19
+ /** Linux `sun_path` holds 108 bytes including the terminating NUL. */
20
+ const socketPathMaxBytes = 107;
21
+ /**
22
+ * mongodb 7.6.0 percent-decodes a socket host once when parsing it and again when it rebuilds
23
+ * the server address, so a path containing `%` cannot be reached as written and is refused.
24
+ */
25
+ const isSocketPath = (valueArg) => typeof valueArg === 'string' &&
26
+ valueArg.startsWith('/') && valueArg.endsWith('.sock') && Buffer.byteLength(valueArg) <= socketPathMaxBytes &&
27
+ !/[\p{Cc}\p{Cs}%]/u.test(valueArg) &&
28
+ valueArg.split('/').slice(1).every((partArg) => partArg !== '' && partArg !== '.' && partArg !== '..');
29
+ /**
30
+ * The connection-string host of an accepted endpoint, or undefined. The driver reads a
31
+ * percent-encoded host ending in `.sock` as a unix-domain socket path.
32
+ */
33
+ const connectionHost = (connectionArg) => {
34
+ if (Object.hasOwn(connectionArg, 'socketPath')) {
35
+ return Object.hasOwn(connectionArg, 'host') || Object.hasOwn(connectionArg, 'port') ||
36
+ !isSocketPath(connectionArg.socketPath) ? undefined : encodeURIComponent(connectionArg.socketPath);
37
+ }
38
+ const { host, port } = connectionArg;
39
+ if (typeof host !== 'string' ||
40
+ !(host === 'localhost' || host === '::1' || (plugins.nodeNet.isIP(host) === 4 && host.startsWith('127.'))) ||
41
+ !Number.isSafeInteger(port) || port < 1 || port > 65535)
42
+ return undefined;
43
+ return `${host === 'localhost' ? '127.0.0.1' : host === '::1' ? '[::1]' : host}:${port}`;
44
+ };
19
45
  /** Disposable fault injection is available only through the testsupport package subpath. */
20
46
  export class SmartdataTestDatabase {
21
47
  db;
@@ -27,34 +53,30 @@ export class SmartdataTestDatabase {
27
53
  #reconnectForRemoval = false;
28
54
  #active;
29
55
  #closing;
30
- constructor(connectionArg) {
31
- const host = connectionArg.host === 'localhost' ? '127.0.0.1' : connectionArg.host;
32
- const authority = host === '::1' ? '[::1]' : host;
33
- const credentials = connectionArg.username === undefined ? ''
34
- : `${encodeURIComponent(connectionArg.username)}:${encodeURIComponent(connectionArg.password)}@`;
56
+ constructor(hostArg, usernameArg, passwordArg) {
57
+ const credentials = usernameArg === undefined ? ''
58
+ : `${encodeURIComponent(usernameArg)}:${encodeURIComponent(passwordArg)}@`;
35
59
  this.#descriptor = Object.freeze({
36
60
  mongoDbName: this.#name,
37
- mongoDbUrl: `mongodb://${credentials}${authority}:${connectionArg.port}/?directConnection=true&authSource=admin`,
61
+ mongoDbUrl: `mongodb://${credentials}${hostArg}/?directConnection=true&authSource=admin`,
38
62
  });
39
63
  this.db = new SmartdataDb(this.#descriptor);
40
64
  }
41
65
  static async create(optionsArg) {
42
66
  const options = assertDataOptions(optionsArg, ['connection', 'timeoutMs', 'signal']);
43
- const connection = assertDataOptions(options.connection, ['host', 'port', 'username', 'password']);
44
- if (typeof connection.host !== 'string' ||
45
- !(connection.host === 'localhost' || connection.host === '::1' ||
46
- (plugins.nodeNet.isIP(connection.host) === 4 && connection.host.startsWith('127.'))) ||
47
- !Number.isSafeInteger(connection.port) || connection.port < 1 || connection.port > 65535 ||
48
- ((connection.username === undefined) !== (connection.password === undefined)) ||
49
- [connection.username, connection.password].some((valueArg) => valueArg !== undefined &&
67
+ const connection = assertDataOptions(options.connection, ['host', 'port', 'socketPath', 'username', 'password']);
68
+ const { username, password } = connection;
69
+ const host = connectionHost(connection);
70
+ if (host === undefined || ((username === undefined) !== (password === undefined)) ||
71
+ [username, password].some((valueArg) => valueArg !== undefined &&
50
72
  (typeof valueArg !== 'string' || valueArg.length < 1 || valueArg.length > 1024))) {
51
- throw new SmartdataPersistenceError('invalid_argument', 'An explicit loopback host, port and optional credential pair are required.');
73
+ throw new SmartdataPersistenceError('invalid_argument', 'An explicit loopback host and port or unix socket path, and an optional credential pair, are required.');
52
74
  }
53
75
  const budget = new SmartdataOperationBudget(options.timeoutMs ?? 5000, options.signal);
54
76
  let fixture;
55
77
  try {
56
78
  budget.check();
57
- fixture = new SmartdataTestDatabase(connection);
79
+ fixture = new SmartdataTestDatabase(host, username, password);
58
80
  await fixture.db.init({ timeoutMs: budget.remainingMs(), signal: budget.signal });
59
81
  const databases = await fixture.db.mongoDb.admin().listDatabases({
60
82
  filter: { name: fixture.#name }, nameOnly: true, authorizedDatabases: false,
@@ -247,4 +269,4 @@ export class SmartdataTestDatabase {
247
269
  this.#owned = false;
248
270
  }
249
271
  }
250
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50ZXN0ZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMudGVzdGRhdGFiYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHdCQUF3QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFvQzNGLDhGQUE4RjtBQUM5RixNQUFNLE9BQU8sa0NBQW1DLFNBQVEseUJBQXlCO0lBQ3RFLFFBQVEsQ0FBc0I7SUFDdkMsWUFBWSxVQUErQjtRQUN6QyxLQUFLLENBQUMsdUJBQXVCLEVBQUUsNEVBQTRFLENBQUMsQ0FBQztRQUM3RyxJQUFJLENBQUMsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFDTSxLQUFLLEtBQW9CLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztDQUMxRDtBQUVELE1BQU0sVUFBVSxHQUFHLEdBQThCLEVBQUUsQ0FBQyxJQUFJLHlCQUF5QixDQUMvRSxrQkFBa0IsRUFBRSxnRkFBZ0YsQ0FDckcsQ0FBQztBQUVGLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUFFLFdBQW1CLEVBQTRCLEVBQUUsQ0FDbEcsMkJBQTJCLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUVqRSw0RkFBNEY7QUFDNUYsTUFBTSxP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
272
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50ZXN0ZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMudGVzdGRhdGFiYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHdCQUF3QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFtRDNGLDhGQUE4RjtBQUM5RixNQUFNLE9BQU8sa0NBQW1DLFNBQVEseUJBQXlCO0lBQ3RFLFFBQVEsQ0FBc0I7SUFDdkMsWUFBWSxVQUErQjtRQUN6QyxLQUFLLENBQUMsdUJBQXVCLEVBQUUsNEVBQTRFLENBQUMsQ0FBQztRQUM3RyxJQUFJLENBQUMsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFDTSxLQUFLLEtBQW9CLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztDQUMxRDtBQUVELE1BQU0sVUFBVSxHQUFHLEdBQThCLEVBQUUsQ0FBQyxJQUFJLHlCQUF5QixDQUMvRSxrQkFBa0IsRUFBRSxnRkFBZ0YsQ0FDckcsQ0FBQztBQUVGLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUFFLFdBQW1CLEVBQTRCLEVBQUUsQ0FDbEcsMkJBQTJCLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUVqRSxzRUFBc0U7QUFDdEUsTUFBTSxr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
@@ -1,3 +1,3 @@
1
1
  import './shim.js';
2
2
  export { SmartdataTestDatabase, SmartdataTestDatabaseCreationError, } from './classes.testdatabase.js';
3
- export type { ISmartdataTestConnection, ISmartdataTestDatabaseOptions, ISmartdataStoredDocumentFaultOptions, ISmartdataIndexFaultOptions, TSmartdataTestModel, } from './classes.testdatabase.js';
3
+ export type { ISmartdataTestConnection, ISmartdataTestSocketConnection, TSmartdataTestConnection, ISmartdataTestDatabaseOptions, ISmartdataStoredDocumentFaultOptions, ISmartdataIndexFaultOptions, TSmartdataTestModel, } from './classes.testdatabase.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lossless.org/client",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "private": false,
5
5
  "description": "One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.",
6
6
  "exports": {
package/readme.md CHANGED
@@ -102,8 +102,10 @@ Family imports preserve the established SmartData and SmartBucket names and cons
102
102
  | Migration-owned indexes | `toleratedIndexNames` on the model — named undeclared indexes are observed, never created, dropped or verified, and no longer make the topology divergent |
103
103
  | Partial index filters in inspection | `inspectNamespace()`, `inspectCollectionTopology()` and `getIndexInfo()` report a partial index's `partialFilterExpression` exactly as the backend lists it, as a frozen snapshot present only on a partial index |
104
104
  | Key-value store readiness | `EasyStore.ensureInitialized()` — installs the store's declared index at startup, outside any transaction window, so a first `readKey()`/`writeKey()` needs no index DDL |
105
+ | Key-value store copies | `EasyStore` `readKey()`/`readAll()` return copies and `writeKey()`/`writeAll()`/`replace()` store copies, in the persisted BSON form, so a read result is a stable snapshot and a caller-side mutation never reaches the store |
105
106
  | Client deadlines | `timeoutMS` (1..120000) on every ordinary model read and write, instance `save()`/`saveIf()`/`delete()` included, on every exact call, and `session.withTransaction(callback, { timeoutMS })` for a whole transaction, retries and commit included; expiry rejects with `SmartdataPersistenceError` code `timeout`, and an exact write interrupted in flight with `ambiguous_write` |
106
107
  | Cancellation | `signal` on every exact call, `atomicDeleteMany()` and `session.withTransaction(callback, { signal })`, which interrupts the session's operation in flight, rolls the attempt back and never commits after an abort |
108
+ | Disposable test databases on a unix socket | `SmartdataTestDatabase.create({ connection: { socketPath } })` from `@lossless.org/client/testsupport` reaches an engine that listens only on a unix-domain socket, fault helpers included; the loopback `host`/`port` form is unchanged |
107
109
 
108
110
  `docs/source/smartdata/readme.md` documents each one with its refusals.
109
111
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@lossless.org/client',
6
- version: '1.9.0',
6
+ version: '1.11.0',
7
7
  description: 'One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.'
8
8
  }
@@ -34,6 +34,24 @@ const getEasyStoreClassForDb = <T>(smartdataDbArg: SmartdataDb) => {
34
34
  return SmartdataEasyStore;
35
35
  };
36
36
 
37
+ /**
38
+ * Copies a store value into the form the store persists: undefined object
39
+ * properties are dropped, an undefined array element becomes null and every
40
+ * value takes its BSON form, exactly as a save and a later read from the
41
+ * database do. The copy shares no object with the argument, so neither side can
42
+ * change the other afterwards. A value BSON cannot encode (a cycle, for
43
+ * example) throws here, before the store's cache is touched.
44
+ */
45
+ const copyInPersistedForm = <TValue>(valueArg: TValue): TValue => {
46
+ if (valueArg === undefined) {
47
+ return valueArg;
48
+ }
49
+ const document = plugins.mongodb.BSON.deserialize(
50
+ plugins.mongodb.BSON.serialize({ value: valueArg }, { ignoreUndefined: true }),
51
+ );
52
+ return document.value as TValue;
53
+ };
54
+
37
55
  /**
38
56
  * EasyStore allows the storage of easy objects. It also allows easy sharing of the object between different instances
39
57
  */
@@ -98,65 +116,131 @@ export class EasyStore<T> {
98
116
  }
99
117
 
100
118
  /**
101
- * reads all keyValue pairs at once and returns them
119
+ * Runs store operations one at a time, in the order they were called. Every
120
+ * read and write of this instance goes through here, so a write builds its
121
+ * next state from the state every earlier write left, and a read never sees
122
+ * the state of a write whose save has not resolved yet. A rejected operation
123
+ * does not stop the ones queued behind it.
124
+ */
125
+ private operationQueue: Promise<void> = Promise.resolve();
126
+ private runExclusive<TResult>(operationArg: () => Promise<TResult>): Promise<TResult> {
127
+ const result = this.operationQueue.then(operationArg);
128
+ this.operationQueue = result.then(
129
+ () => undefined,
130
+ () => undefined,
131
+ );
132
+ return result;
133
+ }
134
+
135
+ /**
136
+ * Persists `nextDataArg` as the store's data. The document's `save()` writes
137
+ * the instance's own fields, so the next state is installed for the save and
138
+ * the previous one is put back when the save rejects: a failed write leaves
139
+ * the cache as it was. Callers hold the operation queue.
102
140
  */
103
- public async readAll() {
104
- const easyStore = await this.getEasyStore();
105
- return easyStore.data;
141
+ private async commit(
142
+ easyStoreArg: InstanceType<typeof this.easyStoreClass>,
143
+ nextDataArg: Partial<T>,
144
+ ): Promise<void> {
145
+ const previousData = easyStoreArg.data;
146
+ easyStoreArg.data = nextDataArg;
147
+ try {
148
+ await easyStoreArg.save();
149
+ } catch (error) {
150
+ easyStoreArg.data = previousData;
151
+ throw error;
152
+ }
106
153
  }
107
154
 
108
155
  /**
109
- * reads a keyValueFile from disk
156
+ * reads all keyValue pairs at once and returns them as a copy in the
157
+ * persisted form: mutating the result does not change the store, and later
158
+ * writes do not change the result.
159
+ */
160
+ public async readAll(): Promise<Partial<T>> {
161
+ return this.runExclusive(async () => {
162
+ const easyStore = await this.getEasyStore();
163
+ return copyInPersistedForm(easyStore.data);
164
+ });
165
+ }
166
+
167
+ /**
168
+ * reads one key and returns a copy of its value in the persisted form, or
169
+ * `undefined` when the key is absent
110
170
  */
111
171
  public async readKey<TKey extends keyof T>(keyArg: TKey): Promise<Partial<T>[TKey]> {
112
- const easyStore = await this.getEasyStore();
113
- return easyStore.data[keyArg];
172
+ return this.runExclusive(async () => {
173
+ const easyStore = await this.getEasyStore();
174
+ return copyInPersistedForm(easyStore.data[keyArg]);
175
+ });
114
176
  }
115
177
 
116
178
  /**
117
- * writes a specific key to the keyValueStore
179
+ * writes a specific key to the keyValueStore. The store keeps a copy, so
180
+ * mutating `valueArg` afterwards does not change the store. When the save
181
+ * rejects, the store keeps its previous state.
118
182
  */
119
183
  public async writeKey<TKey extends keyof T>(keyArg: TKey, valueArg: T[TKey]) {
120
- const easyStore = await this.getEasyStore();
121
- easyStore.data[keyArg] = valueArg;
122
- await easyStore.save();
184
+ const value = copyInPersistedForm(valueArg);
185
+ await this.runExclusive(async () => {
186
+ const easyStore = await this.getEasyStore();
187
+ const nextData: Partial<T> = { ...easyStore.data };
188
+ nextData[keyArg] = value;
189
+ await this.commit(easyStore, nextData);
190
+ });
123
191
  }
124
192
 
193
+ /**
194
+ * deletes a key. When the save rejects, the store keeps its previous state.
195
+ */
125
196
  public async deleteKey(keyArg: keyof T) {
126
- const easyStore = await this.getEasyStore();
127
- delete easyStore.data[keyArg];
128
- await easyStore.save();
197
+ await this.runExclusive(async () => {
198
+ const easyStore = await this.getEasyStore();
199
+ const nextData: Partial<T> = { ...easyStore.data };
200
+ delete nextData[keyArg];
201
+ await this.commit(easyStore, nextData);
202
+ });
129
203
  }
130
204
 
131
205
  /**
132
206
  * merges all keyValue pairs from the object argument into the store.
133
207
  * Existing keys that are not present in `keyValueObject` are preserved.
134
208
  * To overwrite the entire store and drop missing keys, use `replace()`.
209
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
210
+ * change the store. When the save rejects, the store keeps its previous state.
135
211
  */
136
212
  public async writeAll(keyValueObject: Partial<T>) {
137
- const easyStore = await this.getEasyStore();
138
- easyStore.data = { ...easyStore.data, ...keyValueObject };
139
- await easyStore.save();
213
+ const values = copyInPersistedForm(keyValueObject);
214
+ await this.runExclusive(async () => {
215
+ const easyStore = await this.getEasyStore();
216
+ await this.commit(easyStore, { ...easyStore.data, ...values });
217
+ });
140
218
  }
141
219
 
142
220
  /**
143
221
  * atomically replaces the entire store with the given object.
144
222
  * Unlike `writeAll` (which merges), `replace` clears any keys not
145
223
  * present in `keyValueObject`. Useful when you need to drop a key.
224
+ * The store keeps a copy, so mutating `keyValueObject` afterwards does not
225
+ * change the store. When the save rejects, the store keeps its previous state.
146
226
  */
147
227
  public async replace(keyValueObject: Partial<T>) {
148
- const easyStore = await this.getEasyStore();
149
- easyStore.data = { ...keyValueObject };
150
- await easyStore.save();
228
+ const values = copyInPersistedForm(keyValueObject);
229
+ await this.runExclusive(async () => {
230
+ const easyStore = await this.getEasyStore();
231
+ await this.commit(easyStore, values);
232
+ });
151
233
  }
152
234
 
153
235
  /**
154
- * wipes a key value store from disk
236
+ * wipes a key value store from disk. When the save rejects, the store keeps
237
+ * its previous state.
155
238
  */
156
239
  public async wipe() {
157
- const easyStore = await this.getEasyStore();
158
- easyStore.data = {};
159
- await easyStore.save();
240
+ await this.runExclusive(async () => {
241
+ const easyStore = await this.getEasyStore();
242
+ await this.commit(easyStore, {});
243
+ });
160
244
  }
161
245
 
162
246
  public async cleanUpEphemeral() {
@@ -5,6 +5,7 @@ import { SmartDataDbDoc } from './classes.doc.js';
5
5
  import { SmartdataPersistenceError } from './classes.persistence.js';
6
6
  import { assertDataOptions, SmartdataOperationBudget } from './classes.operationbudget.js';
7
7
 
8
+ /** A loopback TCP engine endpoint. */
8
9
  export interface ISmartdataTestConnection {
9
10
  /** Literal loopback IPv4, ::1, or localhost (normalized to 127.0.0.1). */
10
11
  host: string;
@@ -14,8 +15,22 @@ export interface ISmartdataTestConnection {
14
15
  password?: string;
15
16
  }
16
17
 
18
+ /** A unix-domain socket engine endpoint. */
19
+ export interface ISmartdataTestSocketConnection {
20
+ /**
21
+ * Absolute canonical path ending in `.sock` (the MongoDB connection-string rule for
22
+ * socket hosts), at most 107 UTF-8 bytes, without control characters, lone surrogates or `%`.
23
+ */
24
+ socketPath: string;
25
+ /** Supply both credentials or neither. Authentication uses admin. */
26
+ username?: string;
27
+ password?: string;
28
+ }
29
+
30
+ export type TSmartdataTestConnection = ISmartdataTestConnection | ISmartdataTestSocketConnection;
31
+
17
32
  export interface ISmartdataTestDatabaseOptions {
18
- connection: ISmartdataTestConnection;
33
+ connection: TSmartdataTestConnection;
19
34
  /** Default 5000; maximum 120000 ms, shared by connection and ownership checks. */
20
35
  timeoutMs?: number;
21
36
  signal?: AbortSignal;
@@ -57,6 +72,34 @@ const faultError = (): SmartdataPersistenceError => new SmartdataPersistenceErro
57
72
  const canonicalFaultDocument = (valueArg: unknown, maxBytesArg: number): plugins.mongodb.Document =>
58
73
  snapshotBoundedBsonDocument(valueArg, maxBytesArg, faultError);
59
74
 
75
+ /** Linux `sun_path` holds 108 bytes including the terminating NUL. */
76
+ const socketPathMaxBytes = 107;
77
+
78
+ /**
79
+ * mongodb 7.6.0 percent-decodes a socket host once when parsing it and again when it rebuilds
80
+ * the server address, so a path containing `%` cannot be reached as written and is refused.
81
+ */
82
+ const isSocketPath = (valueArg: unknown): valueArg is string => typeof valueArg === 'string' &&
83
+ valueArg.startsWith('/') && valueArg.endsWith('.sock') && Buffer.byteLength(valueArg) <= socketPathMaxBytes &&
84
+ !/[\p{Cc}\p{Cs}%]/u.test(valueArg) &&
85
+ valueArg.split('/').slice(1).every((partArg) => partArg !== '' && partArg !== '.' && partArg !== '..');
86
+
87
+ /**
88
+ * The connection-string host of an accepted endpoint, or undefined. The driver reads a
89
+ * percent-encoded host ending in `.sock` as a unix-domain socket path.
90
+ */
91
+ const connectionHost = (connectionArg: Record<string, unknown>): string | undefined => {
92
+ if (Object.hasOwn(connectionArg, 'socketPath')) {
93
+ return Object.hasOwn(connectionArg, 'host') || Object.hasOwn(connectionArg, 'port') ||
94
+ !isSocketPath(connectionArg.socketPath) ? undefined : encodeURIComponent(connectionArg.socketPath);
95
+ }
96
+ const { host, port } = connectionArg;
97
+ if (typeof host !== 'string' ||
98
+ !(host === 'localhost' || host === '::1' || (plugins.nodeNet.isIP(host) === 4 && host.startsWith('127.'))) ||
99
+ !Number.isSafeInteger(port) || (port as number) < 1 || (port as number) > 65535) return undefined;
100
+ return `${host === 'localhost' ? '127.0.0.1' : host === '::1' ? '[::1]' : host}:${port}`;
101
+ };
102
+
60
103
  /** Disposable fault injection is available only through the testsupport package subpath. */
61
104
  export class SmartdataTestDatabase {
62
105
  public readonly db: SmartdataDb;
@@ -69,35 +112,32 @@ export class SmartdataTestDatabase {
69
112
  #active?: Promise<void>;
70
113
  #closing?: Promise<void>;
71
114
 
72
- private constructor(connectionArg: ISmartdataTestConnection) {
73
- const host = connectionArg.host === 'localhost' ? '127.0.0.1' : connectionArg.host;
74
- const authority = host === '::1' ? '[::1]' : host;
75
- const credentials = connectionArg.username === undefined ? ''
76
- : `${encodeURIComponent(connectionArg.username)}:${encodeURIComponent(connectionArg.password!)}@`;
115
+ private constructor(hostArg: string, usernameArg: string | undefined, passwordArg: string | undefined) {
116
+ const credentials = usernameArg === undefined ? ''
117
+ : `${encodeURIComponent(usernameArg)}:${encodeURIComponent(passwordArg!)}@`;
77
118
  this.#descriptor = Object.freeze({
78
119
  mongoDbName: this.#name,
79
- mongoDbUrl: `mongodb://${credentials}${authority}:${connectionArg.port}/?directConnection=true&authSource=admin`,
120
+ mongoDbUrl: `mongodb://${credentials}${hostArg}/?directConnection=true&authSource=admin`,
80
121
  });
81
122
  this.db = new SmartdataDb(this.#descriptor);
82
123
  }
83
124
 
84
125
  public static async create(optionsArg: ISmartdataTestDatabaseOptions): Promise<SmartdataTestDatabase> {
85
126
  const options = assertDataOptions(optionsArg, ['connection', 'timeoutMs', 'signal']);
86
- const connection = assertDataOptions(options.connection, ['host', 'port', 'username', 'password']);
87
- if (typeof connection.host !== 'string' ||
88
- !(connection.host === 'localhost' || connection.host === '::1' ||
89
- (plugins.nodeNet.isIP(connection.host) === 4 && connection.host.startsWith('127.'))) ||
90
- !Number.isSafeInteger(connection.port) || (connection.port as number) < 1 || (connection.port as number) > 65535 ||
91
- ((connection.username === undefined) !== (connection.password === undefined)) ||
92
- [connection.username, connection.password].some((valueArg) => valueArg !== undefined &&
127
+ const connection = assertDataOptions(options.connection, ['host', 'port', 'socketPath', 'username', 'password']);
128
+ const { username, password } = connection;
129
+ const host = connectionHost(connection);
130
+ if (host === undefined || ((username === undefined) !== (password === undefined)) ||
131
+ [username, password].some((valueArg) => valueArg !== undefined &&
93
132
  (typeof valueArg !== 'string' || valueArg.length < 1 || valueArg.length > 1024))) {
94
- throw new SmartdataPersistenceError('invalid_argument', 'An explicit loopback host, port and optional credential pair are required.');
133
+ throw new SmartdataPersistenceError('invalid_argument',
134
+ 'An explicit loopback host and port or unix socket path, and an optional credential pair, are required.');
95
135
  }
96
136
  const budget = new SmartdataOperationBudget(options.timeoutMs ?? 5000, options.signal);
97
137
  let fixture: SmartdataTestDatabase | undefined;
98
138
  try {
99
139
  budget.check();
100
- fixture = new SmartdataTestDatabase(connection as unknown as ISmartdataTestConnection);
140
+ fixture = new SmartdataTestDatabase(host, username as string | undefined, password as string | undefined);
101
141
  await fixture.db.init({ timeoutMs: budget.remainingMs(), signal: budget.signal });
102
142
  const databases = await fixture.db.mongoDb.admin().listDatabases({
103
143
  filter: { name: fixture.#name }, nameOnly: true, authorizedDatabases: false,
@@ -6,6 +6,8 @@ export {
6
6
  } from './classes.testdatabase.js';
7
7
  export type {
8
8
  ISmartdataTestConnection,
9
+ ISmartdataTestSocketConnection,
10
+ TSmartdataTestConnection,
9
11
  ISmartdataTestDatabaseOptions,
10
12
  ISmartdataStoredDocumentFaultOptions,
11
13
  ISmartdataIndexFaultOptions,