@lossless.org/nosqldb 8.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.
Files changed (81) hide show
  1. package/.smartconfig.json +107 -0
  2. package/dist_rust/rustdb_linux_amd64 +0 -0
  3. package/dist_rust/rustdb_linux_amd64.tsrust-build.json +14 -0
  4. package/dist_rust/rustdb_linux_arm64 +0 -0
  5. package/dist_rust/rustdb_linux_arm64.tsrust-build.json +14 -0
  6. package/dist_rust/rustdb_macos_amd64 +0 -0
  7. package/dist_rust/rustdb_macos_amd64.tsrust-build.json +14 -0
  8. package/dist_rust/rustdb_macos_arm64 +0 -0
  9. package/dist_rust/rustdb_macos_arm64.tsrust-build.json +14 -0
  10. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  11. package/dist_ts/00_commitinfo_data.js +9 -0
  12. package/dist_ts/index.d.ts +8 -0
  13. package/dist_ts/index.js +10 -0
  14. package/dist_ts/ts_local/classes.localnosqldb.d.ts +119 -0
  15. package/dist_ts/ts_local/classes.localnosqldb.js +386 -0
  16. package/dist_ts/ts_local/index.d.ts +5 -0
  17. package/dist_ts/ts_local/index.js +3 -0
  18. package/dist_ts/ts_local/plugins.d.ts +1 -0
  19. package/dist_ts/ts_local/plugins.js +3 -0
  20. package/dist_ts/ts_nosqldb/classes.storagerehearsal.d.ts +19 -0
  21. package/dist_ts/ts_nosqldb/classes.storagerehearsal.js +122 -0
  22. package/dist_ts/ts_nosqldb/file-storage-options.d.ts +13 -0
  23. package/dist_ts/ts_nosqldb/file-storage-options.js +24 -0
  24. package/dist_ts/ts_nosqldb/file-storage-startup.d.ts +3 -0
  25. package/dist_ts/ts_nosqldb/file-storage-startup.js +6 -0
  26. package/dist_ts/ts_nosqldb/index.d.ts +14 -0
  27. package/dist_ts/ts_nosqldb/index.js +11 -0
  28. package/dist_ts/ts_nosqldb/offline-inspection.d.ts +72 -0
  29. package/dist_ts/ts_nosqldb/offline-inspection.js +282 -0
  30. package/dist_ts/ts_nosqldb/plugins.d.ts +7 -0
  31. package/dist_ts/ts_nosqldb/plugins.js +10 -0
  32. package/dist_ts/ts_nosqldb/resource-fencing.d.ts +39 -0
  33. package/dist_ts/ts_nosqldb/resource-fencing.js +271 -0
  34. package/dist_ts/ts_nosqldb/rust-db-bridge.d.ts +213 -0
  35. package/dist_ts/ts_nosqldb/rust-db-bridge.js +439 -0
  36. package/dist_ts/ts_nosqldb/server/classes.nosqldbserver.d.ts +204 -0
  37. package/dist_ts/ts_nosqldb/server/classes.nosqldbserver.js +456 -0
  38. package/dist_ts/ts_nosqldb/server/index.d.ts +3 -0
  39. package/dist_ts/ts_nosqldb/server/index.js +3 -0
  40. package/dist_ts/ts_nosqldb/service-types.d.ts +341 -0
  41. package/dist_ts/ts_nosqldb/service-types.js +62 -0
  42. package/dist_ts/ts_nosqldb/storage-rehearsal.d.ts +103 -0
  43. package/dist_ts/ts_nosqldb/storage-rehearsal.js +131 -0
  44. package/dist_ts/ts_nosqldb/storage-root-relocation.d.ts +27 -0
  45. package/dist_ts/ts_nosqldb/storage-root-relocation.js +211 -0
  46. package/dist_ts_debugserver/bundled.d.ts +4 -0
  47. package/dist_ts_debugserver/bundled.js +16 -0
  48. package/dist_ts_debugserver/classes.debugserver.d.ts +36 -0
  49. package/dist_ts_debugserver/classes.debugserver.js +95 -0
  50. package/dist_ts_debugserver/index.d.ts +2 -0
  51. package/dist_ts_debugserver/index.js +2 -0
  52. package/dist_ts_debugserver/plugins.d.ts +2 -0
  53. package/dist_ts_debugserver/plugins.js +3 -0
  54. package/dist_ts_debugui/index.d.ts +2 -0
  55. package/dist_ts_debugui/index.js +2 -0
  56. package/dist_ts_debugui/nosqldb-debugui.d.ts +62 -0
  57. package/dist_ts_debugui/nosqldb-debugui.js +1132 -0
  58. package/dist_ts_debugui/plugins.d.ts +1 -0
  59. package/dist_ts_debugui/plugins.js +2 -0
  60. package/license +21 -0
  61. package/package.json +82 -0
  62. package/readme.md +1733 -0
  63. package/third-party-notices.md +925 -0
  64. package/ts/00_commitinfo_data.ts +8 -0
  65. package/ts/index.ts +85 -0
  66. package/ts/ts_local/classes.localnosqldb.ts +500 -0
  67. package/ts/ts_local/index.ts +19 -0
  68. package/ts/ts_local/plugins.ts +1 -0
  69. package/ts/ts_nosqldb/classes.storagerehearsal.ts +109 -0
  70. package/ts/ts_nosqldb/file-storage-options.ts +33 -0
  71. package/ts/ts_nosqldb/file-storage-startup.ts +9 -0
  72. package/ts/ts_nosqldb/index.ts +104 -0
  73. package/ts/ts_nosqldb/offline-inspection.ts +375 -0
  74. package/ts/ts_nosqldb/plugins.ts +12 -0
  75. package/ts/ts_nosqldb/resource-fencing.ts +368 -0
  76. package/ts/ts_nosqldb/rust-db-bridge.ts +964 -0
  77. package/ts/ts_nosqldb/server/classes.nosqldbserver.ts +696 -0
  78. package/ts/ts_nosqldb/server/index.ts +4 -0
  79. package/ts/ts_nosqldb/service-types.ts +484 -0
  80. package/ts/ts_nosqldb/storage-rehearsal.ts +215 -0
  81. package/ts/ts_nosqldb/storage-root-relocation.ts +277 -0
@@ -0,0 +1,368 @@
1
+ import * as plugins from './plugins.js';
2
+ import type {
3
+ INoSqlDbDatabaseAllocationIdentity,
4
+ INoSqlDbDatabaseExport,
5
+ } from './service-types.js';
6
+
7
+ export type TNoSqlDbEffectivePayloadInputV1 =
8
+ | {
9
+ version: 1;
10
+ kind: 'smartdb.database.replace.v1';
11
+ databaseName: string;
12
+ source: INoSqlDbDatabaseExport;
13
+ /** Exact exclusive tenant owner; omission retains the legacy v1 digest. */
14
+ username?: string;
15
+ allocation?: INoSqlDbDatabaseAllocationIdentity;
16
+ holdPublication?: boolean;
17
+ }
18
+ | {
19
+ version: 1;
20
+ kind: 'smartdb.database.delete.v1';
21
+ databaseName: string;
22
+ username?: string;
23
+ allocation?: INoSqlDbDatabaseAllocationIdentity;
24
+ holdPublication?: boolean;
25
+ }
26
+ | {
27
+ version: 1;
28
+ kind: 'smartdb.database.ensure.v1';
29
+ databaseName: string;
30
+ username: string;
31
+ password: string;
32
+ roles?: string[];
33
+ allocation?: INoSqlDbDatabaseAllocationIdentity;
34
+ }
35
+ | {
36
+ version: 1;
37
+ kind: 'smartdb.database.allocate.v1';
38
+ databaseName: string;
39
+ expectedAbsent: true;
40
+ username: string;
41
+ password: string;
42
+ roles?: string[];
43
+ };
44
+
45
+ type TCanonicalJsonValue =
46
+ | null
47
+ | boolean
48
+ | number
49
+ | string
50
+ | TCanonicalJsonValue[]
51
+ | { [key: string]: TCanonicalJsonValue };
52
+
53
+ const typedPayloadPrefix = plugins.buffer.Buffer.from(
54
+ 'smartdb.effective-payload.typed.v1\0',
55
+ 'utf8',
56
+ );
57
+ const minimumI64 = -9_223_372_036_854_775_808n;
58
+ const maximumU64 = 18_446_744_073_709_551_615n;
59
+
60
+ const compareUtf8Keys = (leftArg: string, rightArg: string): number =>
61
+ plugins.buffer.Buffer.compare(
62
+ plugins.buffer.Buffer.from(leftArg, 'utf8'),
63
+ plugins.buffer.Buffer.from(rightArg, 'utf8'),
64
+ );
65
+
66
+ const formatSerdeJsonFloat = (valueArg: number): string => {
67
+ const transportNumber = JSON.stringify(valueArg);
68
+ if (/^-?\d+$/.test(transportNumber)) {
69
+ const integer = BigInt(transportNumber);
70
+ if (integer >= minimumI64 && integer <= maximumU64) {
71
+ return transportNumber;
72
+ }
73
+ }
74
+
75
+ const negative = valueArg < 0;
76
+ const source = Math.abs(valueArg).toString().toLowerCase();
77
+ let digits: string;
78
+ let decimalExponent: number;
79
+ if (source.includes('e')) {
80
+ const [coefficient, exponent] = source.split('e');
81
+ digits = coefficient.replace('.', '').replace(/^0+|0+$/g, '');
82
+ decimalExponent = Number.parseInt(exponent, 10);
83
+ } else {
84
+ const [integerPart, fractionPart = ''] = source.split('.');
85
+ const rawDigits = `${integerPart}${fractionPart}`;
86
+ const firstSignificant = rawDigits.search(/[1-9]/);
87
+ const lastSignificant = rawDigits.search(/[1-9](?!.*[1-9])/);
88
+ if (firstSignificant < 0) {
89
+ return '0.0';
90
+ }
91
+ digits = rawDigits.slice(firstSignificant, lastSignificant + 1);
92
+ decimalExponent = integerPart.length - firstSignificant - 1;
93
+ }
94
+
95
+ let rendered: string;
96
+ if (decimalExponent >= -5 && decimalExponent <= 15) {
97
+ const integerDigits = decimalExponent + 1;
98
+ if (digits.length <= integerDigits) {
99
+ rendered = `${digits}${'0'.repeat(integerDigits - digits.length)}.0`;
100
+ } else if (integerDigits > 0) {
101
+ rendered = `${digits.slice(0, integerDigits)}.${digits.slice(integerDigits)}`;
102
+ } else {
103
+ rendered = `0.${'0'.repeat(-integerDigits)}${digits}`;
104
+ }
105
+ } else {
106
+ const significand =
107
+ digits.length === 1 ? digits : `${digits[0]}.${digits.slice(1)}`;
108
+ rendered = `${significand}e${decimalExponent >= 0 ? '+' : ''}${decimalExponent}`;
109
+ }
110
+ return negative ? `-${rendered}` : rendered;
111
+ };
112
+
113
+ const canonicalJsonStringify = (valueArg: TCanonicalJsonValue): string => {
114
+ if (typeof valueArg === 'number') {
115
+ return formatSerdeJsonFloat(valueArg);
116
+ }
117
+ if (valueArg === null || typeof valueArg !== 'object') {
118
+ const serialized = JSON.stringify(valueArg);
119
+ if (serialized === undefined) {
120
+ throw new TypeError('NoSQLDB effective payload contains unsupported JSON');
121
+ }
122
+ return serialized;
123
+ }
124
+ if (Array.isArray(valueArg)) {
125
+ return `[${valueArg.map((entryArg) => canonicalJsonStringify(entryArg)).join(',')}]`;
126
+ }
127
+ return `{${Object.keys(valueArg)
128
+ .map(
129
+ (keyArg) =>
130
+ `${JSON.stringify(keyArg)}:${canonicalJsonStringify(valueArg[keyArg])}`,
131
+ )
132
+ .join(',')}}`;
133
+ };
134
+
135
+ const encodeTypedLength = (lengthArg: number): Uint8Array => {
136
+ const encoded = plugins.buffer.Buffer.allocUnsafe(8);
137
+ encoded.writeBigUInt64BE(BigInt(lengthArg));
138
+ return encoded;
139
+ };
140
+
141
+ const encodeTypedBytes = (valueArg: Uint8Array): Uint8Array[] => [
142
+ encodeTypedLength(valueArg.byteLength),
143
+ valueArg,
144
+ ];
145
+
146
+ const encodeTypedValue = (
147
+ valueArg: TCanonicalJsonValue,
148
+ chunksArg: Uint8Array[],
149
+ ): void => {
150
+ if (valueArg === null) {
151
+ chunksArg.push(plugins.buffer.Buffer.from([0]));
152
+ return;
153
+ }
154
+ if (valueArg === false) {
155
+ chunksArg.push(plugins.buffer.Buffer.from([1]));
156
+ return;
157
+ }
158
+ if (valueArg === true) {
159
+ chunksArg.push(plugins.buffer.Buffer.from([2]));
160
+ return;
161
+ }
162
+ if (typeof valueArg === 'number') {
163
+ if (!Number.isFinite(valueArg)) {
164
+ throw new TypeError('NoSQLDB exact replace contains a non-finite number');
165
+ }
166
+ const encoded = plugins.buffer.Buffer.allocUnsafe(9);
167
+ encoded[0] = 3;
168
+ encoded.writeDoubleBE(valueArg, 1);
169
+ chunksArg.push(encoded);
170
+ return;
171
+ }
172
+ if (typeof valueArg === 'string') {
173
+ const encoded = plugins.buffer.Buffer.from(valueArg, 'utf8');
174
+ chunksArg.push(plugins.buffer.Buffer.from([4]), ...encodeTypedBytes(encoded));
175
+ return;
176
+ }
177
+ if (Array.isArray(valueArg)) {
178
+ chunksArg.push(
179
+ plugins.buffer.Buffer.from([5]),
180
+ encodeTypedLength(valueArg.length),
181
+ );
182
+ for (const value of valueArg) {
183
+ encodeTypedValue(value, chunksArg);
184
+ }
185
+ return;
186
+ }
187
+ const keys = Object.keys(valueArg).sort(compareUtf8Keys);
188
+ chunksArg.push(
189
+ plugins.buffer.Buffer.from([6]),
190
+ encodeTypedLength(keys.length),
191
+ );
192
+ for (const key of keys) {
193
+ const encodedKey = plugins.buffer.Buffer.from(key, 'utf8');
194
+ chunksArg.push(
195
+ plugins.buffer.Buffer.from([4]),
196
+ ...encodeTypedBytes(encodedKey),
197
+ );
198
+ encodeTypedValue(valueArg[key], chunksArg);
199
+ }
200
+ };
201
+
202
+ const encodeTypedPayload = (valueArg: TCanonicalJsonValue): Uint8Array => {
203
+ const chunks: Uint8Array[] = [typedPayloadPrefix];
204
+ encodeTypedValue(valueArg, chunks);
205
+ return plugins.buffer.Buffer.concat(chunks);
206
+ };
207
+
208
+ /**
209
+ * Computes the provider-derived SHA-256 identity for NoSQLDB's version 1
210
+ * fenced replace, exact-user delete, and exact-user ensure payload profiles.
211
+ */
212
+ export const createNoSqlDbEffectivePayloadSha256V1 = (
213
+ inputArg: TNoSqlDbEffectivePayloadInputV1,
214
+ ): string => {
215
+ if (inputArg.version !== 1) {
216
+ throw new TypeError('NoSQLDB effective payload version must be 1');
217
+ }
218
+ if (typeof inputArg.databaseName !== 'string') {
219
+ throw new TypeError('NoSQLDB effective payload databaseName must be a string');
220
+ }
221
+
222
+ let effectivePayload: object;
223
+ let useTypedEncoding = false;
224
+ switch (inputArg.kind) {
225
+ case 'smartdb.database.replace.v1':
226
+ if (
227
+ inputArg.username !== undefined &&
228
+ typeof inputArg.username !== 'string'
229
+ ) {
230
+ throw new TypeError('NoSQLDB exact replace username must be a string');
231
+ }
232
+ if (
233
+ inputArg.holdPublication !== undefined &&
234
+ typeof inputArg.holdPublication !== 'boolean'
235
+ ) {
236
+ throw new TypeError('NoSQLDB holdPublication must be a Boolean');
237
+ }
238
+ effectivePayload = {
239
+ version: 1,
240
+ kind: inputArg.kind,
241
+ databaseName: inputArg.databaseName,
242
+ source: inputArg.source,
243
+ ...(inputArg.username === undefined
244
+ ? {}
245
+ : { username: inputArg.username }),
246
+ ...(inputArg.allocation === undefined
247
+ ? {}
248
+ : { allocation: inputArg.allocation }),
249
+ ...(inputArg.holdPublication === true
250
+ ? { holdPublication: true }
251
+ : {}),
252
+ };
253
+ useTypedEncoding =
254
+ inputArg.username !== undefined ||
255
+ inputArg.allocation !== undefined ||
256
+ inputArg.holdPublication === true;
257
+ break;
258
+ case 'smartdb.database.ensure.v1': {
259
+ if (typeof inputArg.username !== 'string') {
260
+ throw new TypeError('NoSQLDB exact ensure username must be a string');
261
+ }
262
+ if (typeof inputArg.password !== 'string') {
263
+ throw new TypeError('NoSQLDB exact ensure password must be a string');
264
+ }
265
+ const roles = inputArg.roles ?? ['readWrite', 'dbAdmin'];
266
+ if (
267
+ !Array.isArray(roles) ||
268
+ roles.some(
269
+ (roleArg) => typeof roleArg !== 'string' || roleArg.length === 0,
270
+ )
271
+ ) {
272
+ throw new TypeError(
273
+ 'NoSQLDB exact ensure roles must be an array of non-empty strings',
274
+ );
275
+ }
276
+ const canonicalRoles = [...new Set(roles)].sort(compareUtf8Keys);
277
+ effectivePayload = {
278
+ version: 1,
279
+ kind: inputArg.kind,
280
+ databaseName: inputArg.databaseName,
281
+ username: inputArg.username,
282
+ passwordSha256: plugins.crypto
283
+ .createHash('sha256')
284
+ .update(inputArg.password, 'utf8')
285
+ .digest('hex'),
286
+ roles: canonicalRoles,
287
+ ...(inputArg.allocation === undefined
288
+ ? {}
289
+ : { allocation: inputArg.allocation }),
290
+ };
291
+ useTypedEncoding = inputArg.allocation !== undefined;
292
+ break;
293
+ }
294
+ case 'smartdb.database.allocate.v1': {
295
+ if (inputArg.expectedAbsent !== true) {
296
+ throw new TypeError('NoSQLDB allocation expectedAbsent must be true');
297
+ }
298
+ if (typeof inputArg.username !== 'string') {
299
+ throw new TypeError('NoSQLDB allocation username must be a string');
300
+ }
301
+ if (typeof inputArg.password !== 'string') {
302
+ throw new TypeError('NoSQLDB allocation password must be a string');
303
+ }
304
+ const roles = inputArg.roles ?? ['readWrite', 'dbAdmin'];
305
+ if (!Array.isArray(roles) || roles.some((roleArg) => typeof roleArg !== 'string' || roleArg.length === 0)) {
306
+ throw new TypeError('NoSQLDB allocation roles must be an array of non-empty strings');
307
+ }
308
+ effectivePayload = {
309
+ version: 1,
310
+ kind: inputArg.kind,
311
+ databaseName: inputArg.databaseName,
312
+ expectedAbsent: true,
313
+ username: inputArg.username,
314
+ passwordSha256: plugins.crypto
315
+ .createHash('sha256')
316
+ .update(inputArg.password, 'utf8')
317
+ .digest('hex'),
318
+ roles: [...new Set(roles)].sort(compareUtf8Keys),
319
+ };
320
+ useTypedEncoding = true;
321
+ break;
322
+ }
323
+ case 'smartdb.database.delete.v1':
324
+ if (
325
+ inputArg.username !== undefined &&
326
+ typeof inputArg.username !== 'string'
327
+ ) {
328
+ throw new TypeError('NoSQLDB exact delete username must be a string when supplied');
329
+ }
330
+ if (
331
+ inputArg.holdPublication !== undefined &&
332
+ typeof inputArg.holdPublication !== 'boolean'
333
+ ) {
334
+ throw new TypeError('NoSQLDB holdPublication must be a Boolean');
335
+ }
336
+ effectivePayload = {
337
+ version: 1,
338
+ kind: inputArg.kind,
339
+ databaseName: inputArg.databaseName,
340
+ ...(inputArg.username === undefined
341
+ ? { rawDatabaseOnly: true }
342
+ : { username: inputArg.username, rawDatabaseOnly: false }),
343
+ ...(inputArg.allocation === undefined
344
+ ? {}
345
+ : { allocation: inputArg.allocation }),
346
+ ...(inputArg.holdPublication === true
347
+ ? { holdPublication: true }
348
+ : {}),
349
+ };
350
+ useTypedEncoding = inputArg.allocation !== undefined;
351
+ break;
352
+ default:
353
+ throw new TypeError('NoSQLDB mutation kind has no version 1 payload profile');
354
+ }
355
+
356
+ const transportJson = JSON.stringify(effectivePayload);
357
+ if (transportJson === undefined) {
358
+ throw new TypeError('NoSQLDB effective payload cannot be encoded as JSON');
359
+ }
360
+ const normalizedPayload = JSON.parse(transportJson) as TCanonicalJsonValue;
361
+ const encodedPayload = useTypedEncoding
362
+ ? encodeTypedPayload(normalizedPayload)
363
+ : canonicalJsonStringify(normalizedPayload);
364
+ return plugins.crypto
365
+ .createHash('sha256')
366
+ .update(encodedPayload)
367
+ .digest('hex');
368
+ };