@lossless.org/client 0.1.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 (255) hide show
  1. package/.smartconfig.json +37 -0
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/classes.losslessorgclient.d.ts +32 -0
  5. package/dist_ts/classes.losslessorgclient.js +103 -0
  6. package/dist_ts/core/classes.error.d.ts +16 -0
  7. package/dist_ts/core/classes.error.js +29 -0
  8. package/dist_ts/core/classes.operation.d.ts +17 -0
  9. package/dist_ts/core/classes.operation.js +70 -0
  10. package/dist_ts/core/interfaces.d.ts +18 -0
  11. package/dist_ts/core/interfaces.js +2 -0
  12. package/dist_ts/index.d.ts +4 -0
  13. package/dist_ts/index.js +3 -0
  14. package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
  15. package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
  16. package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
  17. package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
  18. package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
  19. package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
  20. package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
  21. package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
  22. package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
  23. package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
  24. package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
  25. package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
  26. package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
  27. package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
  28. package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
  29. package/dist_ts/nosqldb/classes.cached-document.js +112 -0
  30. package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
  31. package/dist_ts/nosqldb/classes.collection.js +1568 -0
  32. package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
  33. package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
  34. package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
  35. package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
  36. package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
  37. package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
  38. package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
  39. package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
  40. package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
  41. package/dist_ts/nosqldb/classes.connection.js +23 -0
  42. package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
  43. package/dist_ts/nosqldb/classes.convenience.js +5 -0
  44. package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
  45. package/dist_ts/nosqldb/classes.cursor.js +82 -0
  46. package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
  47. package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
  48. package/dist_ts/nosqldb/classes.db.d.ts +98 -0
  49. package/dist_ts/nosqldb/classes.db.js +434 -0
  50. package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
  51. package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
  52. package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
  53. package/dist_ts/nosqldb/classes.doc.js +2976 -0
  54. package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
  55. package/dist_ts/nosqldb/classes.easystore.js +199 -0
  56. package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
  57. package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
  58. package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
  59. package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
  60. package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
  61. package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
  62. package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
  63. package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
  64. package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
  65. package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
  66. package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
  67. package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
  68. package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
  69. package/dist_ts/nosqldb/classes.persistence.js +34 -0
  70. package/dist_ts/nosqldb/classes.session.d.ts +28 -0
  71. package/dist_ts/nosqldb/classes.session.js +246 -0
  72. package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
  73. package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
  74. package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
  75. package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
  76. package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
  77. package/dist_ts/nosqldb/classes.watcher.js +98 -0
  78. package/dist_ts/nosqldb/index.d.ts +27 -0
  79. package/dist_ts/nosqldb/index.js +18 -0
  80. package/dist_ts/nosqldb/logging.d.ts +2 -0
  81. package/dist_ts/nosqldb/logging.js +3 -0
  82. package/dist_ts/nosqldb/plugins.d.ts +17 -0
  83. package/dist_ts/nosqldb/plugins.js +20 -0
  84. package/dist_ts/nosqldb/shim.d.ts +1 -0
  85. package/dist_ts/nosqldb/shim.js +8 -0
  86. package/dist_ts/nosqldb/testsupport.d.ts +3 -0
  87. package/dist_ts/nosqldb/testsupport.js +3 -0
  88. package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
  89. package/dist_ts/objectstorage/classes.bucket.js +939 -0
  90. package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
  91. package/dist_ts/objectstorage/classes.connection.js +27 -0
  92. package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
  93. package/dist_ts/objectstorage/classes.directory.js +335 -0
  94. package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
  95. package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
  96. package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
  97. package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
  98. package/dist_ts/objectstorage/classes.file.d.ts +91 -0
  99. package/dist_ts/objectstorage/classes.file.js +255 -0
  100. package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
  101. package/dist_ts/objectstorage/classes.listcursor.js +67 -0
  102. package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
  103. package/dist_ts/objectstorage/classes.metadata.js +113 -0
  104. package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
  105. package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
  106. package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
  107. package/dist_ts/objectstorage/classes.trash.js +22 -0
  108. package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
  109. package/dist_ts/objectstorage/classes.watcher.js +249 -0
  110. package/dist_ts/objectstorage/helpers.d.ts +25 -0
  111. package/dist_ts/objectstorage/helpers.js +215 -0
  112. package/dist_ts/objectstorage/index.d.ts +13 -0
  113. package/dist_ts/objectstorage/index.js +13 -0
  114. package/dist_ts/objectstorage/interfaces.d.ts +276 -0
  115. package/dist_ts/objectstorage/interfaces.js +2 -0
  116. package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
  117. package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
  118. package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
  119. package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
  120. package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
  121. package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
  122. package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
  123. package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
  124. package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
  125. package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
  126. package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
  127. package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
  128. package/dist_ts/objectstorage/plugins.d.ts +17 -0
  129. package/dist_ts/objectstorage/plugins.js +23 -0
  130. package/dist_ts/plugins.d.ts +4 -0
  131. package/dist_ts/plugins.js +5 -0
  132. package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
  133. package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
  134. package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
  135. package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
  136. package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
  137. package/dist_ts/sqldb/classes.sqltable.js +70 -0
  138. package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
  139. package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
  140. package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
  141. package/dist_ts/sqldb/clickhouse/index.js +13 -0
  142. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
  143. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
  144. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
  145. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
  146. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
  147. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
  148. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
  149. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
  150. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
  151. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
  152. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
  153. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
  154. package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
  155. package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
  156. package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
  157. package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
  158. package/dist_ts/sqldb/index.d.ts +6 -0
  159. package/dist_ts/sqldb/index.js +6 -0
  160. package/dist_ts/sqldb/interfaces.d.ts +53 -0
  161. package/dist_ts/sqldb/interfaces.js +19 -0
  162. package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
  163. package/dist_ts/sqldb/internal.sqlpool.js +214 -0
  164. package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
  165. package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
  166. package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
  167. package/dist_ts/sqldb/plugins.mariadb.js +5 -0
  168. package/docs/source/smartbucket/license.md +19 -0
  169. package/docs/source/smartclickhouse/license.md +19 -0
  170. package/license.md +21 -0
  171. package/package.json +101 -0
  172. package/readme.md +157 -0
  173. package/ts/00_commitinfo_data.ts +8 -0
  174. package/ts/classes.losslessorgclient.ts +104 -0
  175. package/ts/core/classes.error.ts +31 -0
  176. package/ts/core/classes.operation.ts +60 -0
  177. package/ts/core/interfaces.ts +24 -0
  178. package/ts/index.ts +4 -0
  179. package/ts/nosqldb/classes.atomicdelete.ts +81 -0
  180. package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
  181. package/ts/nosqldb/classes.atomicupdate.ts +99 -0
  182. package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
  183. package/ts/nosqldb/classes.bsonassertion.ts +25 -0
  184. package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
  185. package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
  186. package/ts/nosqldb/classes.cached-document.ts +67 -0
  187. package/ts/nosqldb/classes.collection.ts +2399 -0
  188. package/ts/nosqldb/classes.collectionfactory.ts +87 -0
  189. package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
  190. package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
  191. package/ts/nosqldb/classes.collectiontopology.ts +645 -0
  192. package/ts/nosqldb/classes.connection.ts +31 -0
  193. package/ts/nosqldb/classes.convenience.ts +5 -0
  194. package/ts/nosqldb/classes.cursor.ts +88 -0
  195. package/ts/nosqldb/classes.cursoroperation.ts +38 -0
  196. package/ts/nosqldb/classes.db.ts +637 -0
  197. package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
  198. package/ts/nosqldb/classes.doc.ts +4928 -0
  199. package/ts/nosqldb/classes.easystore.ts +154 -0
  200. package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
  201. package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
  202. package/ts/nosqldb/classes.mongoadministration.ts +867 -0
  203. package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
  204. package/ts/nosqldb/classes.operationbudget.ts +75 -0
  205. package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
  206. package/ts/nosqldb/classes.persistence.ts +62 -0
  207. package/ts/nosqldb/classes.session.ts +389 -0
  208. package/ts/nosqldb/classes.storedinspection.ts +151 -0
  209. package/ts/nosqldb/classes.testdatabase.ts +272 -0
  210. package/ts/nosqldb/classes.watcher.ts +96 -0
  211. package/ts/nosqldb/index.ts +51 -0
  212. package/ts/nosqldb/logging.ts +3 -0
  213. package/ts/nosqldb/plugins.ts +37 -0
  214. package/ts/nosqldb/shim.ts +6 -0
  215. package/ts/nosqldb/testsupport.ts +13 -0
  216. package/ts/objectstorage/classes.bucket.ts +1114 -0
  217. package/ts/objectstorage/classes.connection.ts +36 -0
  218. package/ts/objectstorage/classes.directory.ts +425 -0
  219. package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
  220. package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
  221. package/ts/objectstorage/classes.file.ts +303 -0
  222. package/ts/objectstorage/classes.listcursor.ts +89 -0
  223. package/ts/objectstorage/classes.metadata.ts +134 -0
  224. package/ts/objectstorage/classes.smartbucket.ts +445 -0
  225. package/ts/objectstorage/classes.trash.ts +30 -0
  226. package/ts/objectstorage/classes.watcher.ts +289 -0
  227. package/ts/objectstorage/helpers.ts +254 -0
  228. package/ts/objectstorage/index.ts +13 -0
  229. package/ts/objectstorage/interfaces.ts +389 -0
  230. package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
  231. package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
  232. package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
  233. package/ts/objectstorage/internal.multipart.planner.ts +90 -0
  234. package/ts/objectstorage/internal.multipart.stream.ts +606 -0
  235. package/ts/objectstorage/internal.multipart.types.ts +106 -0
  236. package/ts/objectstorage/plugins.ts +35 -0
  237. package/ts/plugins.ts +4 -0
  238. package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
  239. package/ts/sqldb/classes.sqlconnection.ts +350 -0
  240. package/ts/sqldb/classes.sqltable.ts +70 -0
  241. package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
  242. package/ts/sqldb/clickhouse/index.ts +16 -0
  243. package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
  244. package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
  245. package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
  246. package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
  247. package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
  248. package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
  249. package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
  250. package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
  251. package/ts/sqldb/index.ts +6 -0
  252. package/ts/sqldb/interfaces.ts +61 -0
  253. package/ts/sqldb/internal.sqlpool.ts +179 -0
  254. package/ts/sqldb/plugins.clickhouse.ts +4 -0
  255. package/ts/sqldb/plugins.mariadb.ts +4 -0
@@ -0,0 +1,99 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { SmartdataCollection } from './classes.collection.js';
3
+ import { normalizeOrdinaryPersistenceError } from './classes.persistence.js';
4
+ import {
5
+ runWithOrdinarySmartdataSession,
6
+ type TSmartdataOrdinarySession,
7
+ } from './classes.session.js';
8
+
9
+ /**
10
+ * Executes a model-validated atomic update against MongoDB.
11
+ *
12
+ * This helper is package-internal. `SmartDataDbDoc.atomicUpdate()` owns the
13
+ * public API and must validate and normalize every filter and update before
14
+ * calling this raw persistence boundary.
15
+ */
16
+ export const executeAtomicUpdate = async <T>(
17
+ collectionArg: SmartdataCollection<T>,
18
+ filterArg: plugins.mongodb.Filter<plugins.mongodb.Document>,
19
+ updateArg: plugins.mongodb.UpdateFilter<plugins.mongodb.Document>,
20
+ optsArg?: {
21
+ upsert?: boolean;
22
+ session?: TSmartdataOrdinarySession;
23
+ },
24
+ ): Promise<plugins.mongodb.UpdateResult> => {
25
+ return runWithOrdinarySmartdataSession(
26
+ optsArg?.session,
27
+ collectionArg.smartdataDb,
28
+ {
29
+ ordinaryWrite: true,
30
+ prepared: collectionArg.isInitializedForCurrentDatabase(),
31
+ preparationMessage:
32
+ `Initialize collection "${collectionArg.collectionName}" before using an owned SmartData session.`,
33
+ },
34
+ async (rawSessionArg) => {
35
+ await collectionArg.init();
36
+ try {
37
+ return await collectionArg.mongoDbCollection.updateOne(
38
+ filterArg,
39
+ updateArg,
40
+ {
41
+ upsert: optsArg?.upsert === true,
42
+ session: rawSessionArg,
43
+ },
44
+ );
45
+ } catch (errorArg) {
46
+ return normalizeOrdinaryPersistenceError(
47
+ errorArg,
48
+ `Atomic update conflicts with a unique index in collection "${collectionArg.collectionName}".`,
49
+ );
50
+ }
51
+ },
52
+ );
53
+ };
54
+
55
+ /**
56
+ * Executes a model-validated atomic update-many against MongoDB.
57
+ *
58
+ * This helper is package-internal. `SmartDataDbDoc.atomicUpdateMany()` owns
59
+ * the public API and must validate and normalize every filter and update
60
+ * before calling this raw persistence boundary. Each matched document is
61
+ * updated atomically; the batch as a whole is not isolated and no upsert is
62
+ * possible.
63
+ */
64
+ export const executeAtomicUpdateMany = async <T>(
65
+ collectionArg: SmartdataCollection<T>,
66
+ filterArg: plugins.mongodb.Filter<plugins.mongodb.Document>,
67
+ updateArg: plugins.mongodb.UpdateFilter<plugins.mongodb.Document>,
68
+ optsArg?: {
69
+ session?: TSmartdataOrdinarySession;
70
+ },
71
+ ): Promise<plugins.mongodb.UpdateResult> => {
72
+ return runWithOrdinarySmartdataSession(
73
+ optsArg?.session,
74
+ collectionArg.smartdataDb,
75
+ {
76
+ ordinaryWrite: true,
77
+ prepared: collectionArg.isInitializedForCurrentDatabase(),
78
+ preparationMessage:
79
+ `Initialize collection "${collectionArg.collectionName}" before using an owned SmartData session.`,
80
+ },
81
+ async (rawSessionArg) => {
82
+ await collectionArg.init();
83
+ try {
84
+ return await collectionArg.mongoDbCollection.updateMany(
85
+ filterArg,
86
+ updateArg,
87
+ {
88
+ session: rawSessionArg,
89
+ },
90
+ );
91
+ } catch (errorArg) {
92
+ return normalizeOrdinaryPersistenceError(
93
+ errorArg,
94
+ `Atomic update-many conflicts with a unique index in collection "${collectionArg.collectionName}".`,
95
+ );
96
+ }
97
+ },
98
+ );
99
+ };
@@ -0,0 +1,107 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { SmartdataDb } from './classes.db.js';
3
+ import type { INormalizedCollectionModelSchema } from './classes.collection.js';
4
+ import { assertDataOptions, SmartdataOperationBudget } from './classes.operationbudget.js';
5
+ import { snapshotBoundedBsonDocument } from './classes.bsonsnapshot.js';
6
+ import { validateOrdinaryStoredDocument } from './classes.ordinarypersistence.js';
7
+ import { SmartdataPersistenceError, isMongoDuplicateKeyError } from './classes.persistence.js';
8
+ import { readBoundedInspectionCursor } from './classes.namespaceinspection.js';
9
+ import {
10
+ collectionModelSchemaResolverSymbol, collectionTopologyDbInspectionSymbol,
11
+ getExpectedCollectionTopologyForSchema, inspectCollectionTopologySnapshot,
12
+ } from './classes.collectiontopology.js';
13
+
14
+ export interface ISmartdataBootstrapRecordOptions {
15
+ /** Default 5000; maximum 120000 ms, shared by inspection and insertion. */
16
+ timeoutMs?: number;
17
+ signal?: AbortSignal;
18
+ /** Default 64 KiB, maximum 1 MiB of bounded inert BSON. */
19
+ maxBytes?: number;
20
+ }
21
+
22
+ export interface ISmartdataBootstrapRecordResult {
23
+ readonly acknowledged: true;
24
+ readonly insertedId: string;
25
+ }
26
+
27
+ type TBootstrapOutcome = 'inserted' | 'unique_conflict' | 'invalid_configuration' | 'ambiguous_write';
28
+
29
+ /** @internal One validated insert command; no collection/index DDL or readiness publication. */
30
+ export const insertBootstrapRecord = async (
31
+ modelArg: unknown,
32
+ dbArg: SmartdataDb,
33
+ recordArg: unknown,
34
+ optionsArg: ISmartdataBootstrapRecordOptions = {},
35
+ ): Promise<ISmartdataBootstrapRecordResult> => {
36
+ const options = assertDataOptions(optionsArg, ['timeoutMs', 'signal', 'maxBytes']);
37
+ const maxBytes = options.maxBytes === undefined ? 64 * 1024 : options.maxBytes;
38
+ if (!Number.isSafeInteger(maxBytes) || (maxBytes as number) < 1 || (maxBytes as number) > 1024 * 1024) {
39
+ throw new SmartdataPersistenceError('invalid_argument', 'Invalid bootstrap record size bound.');
40
+ }
41
+ const budget = new SmartdataOperationBudget(options.timeoutMs === undefined ? 5000 : options.timeoutMs, options.signal);
42
+ try {
43
+ budget.check();
44
+ const model = modelArg as { [collectionModelSchemaResolverSymbol]?: () => INormalizedCollectionModelSchema };
45
+ if (!model || !Object.hasOwn(model, collectionModelSchemaResolverSymbol) ||
46
+ typeof model[collectionModelSchemaResolverSymbol] !== 'function') {
47
+ throw new SmartdataPersistenceError('invalid_configuration', 'Bootstrap insertion requires a declared model.');
48
+ }
49
+ const schema = model[collectionModelSchemaResolverSymbol]!();
50
+ if (!schema.ordinaryPersistence || schema.ordinaryPersistence.idType !== 'string' ||
51
+ schema.ordinaryPersistence.timestamps !== 'none' || schema.indexes.length !== 0) {
52
+ throw new SmartdataPersistenceError('invalid_configuration',
53
+ 'Bootstrap insertion requires strict ordinary string-ID persistence without timestamps or secondary indexes.');
54
+ }
55
+ const document = validateOrdinaryStoredDocument(
56
+ snapshotBoundedBsonDocument(recordArg, maxBytes as number, () => new SmartdataPersistenceError(
57
+ 'invalid_document', 'Bootstrap record must be bounded, inert, canonical BSON with an explicit string ID.',
58
+ )), schema.ordinaryPersistence, schema.persistedFields,
59
+ );
60
+ const expected = getExpectedCollectionTopologyForSchema(schema);
61
+ let dispatched = false;
62
+ let outcome: TBootstrapOutcome;
63
+ try {
64
+ // Explicit preparation uses this same connection-generation guard.
65
+ outcome = await dbArg[collectionTopologyDbInspectionSymbol](async (mongoDbArg, assertCurrentArg) => {
66
+ budget.check();
67
+ const namespaces = await readBoundedInspectionCursor(mongoDbArg.listCollections(
68
+ { name: schema.collectionName },
69
+ { nameOnly: false, batchSize: 1, ...budget.operationOptions() },
70
+ ), 1, budget.signal, () => budget.cleanupOptions());
71
+ budget.check();
72
+ assertCurrentArg();
73
+ const namespace = namespaces[0] as unknown as Record<string, unknown> | undefined;
74
+ const collection = mongoDbArg.collection(schema.collectionName);
75
+ const indexes = namespace?.type === 'collection'
76
+ ? await readBoundedInspectionCursor(collection.listIndexes({
77
+ batchSize: 1, ...budget.cleanupOptions(),
78
+ }), 64, budget.signal, () => budget.cleanupOptions())
79
+ : [];
80
+ budget.check();
81
+ assertCurrentArg();
82
+ const topology = inspectCollectionTopologySnapshot(expected, { namespace: namespace ?? null, indexes });
83
+ if (topology.status !== 'absent' && topology.status !== 'exact') return 'invalid_configuration';
84
+ const insertOptions = budget.operationOptions();
85
+ dispatched = true;
86
+ try {
87
+ const result = await collection.insertOne(document, insertOptions);
88
+ budget.check();
89
+ return result.acknowledged && result.insertedId === document._id ? 'inserted' : 'ambiguous_write';
90
+ } catch (errorArg) {
91
+ return isMongoDuplicateKeyError(errorArg) ? 'unique_conflict' : 'ambiguous_write';
92
+ }
93
+ });
94
+ } catch {
95
+ throw new SmartdataPersistenceError(dispatched ? 'ambiguous_write' : 'unsupported_operation',
96
+ dispatched ? 'Bootstrap insertion outcome is uncertain; inspect its explicit ID before proceeding.'
97
+ : 'Bootstrap insertion could not inspect the current database connection.');
98
+ }
99
+ if (outcome === 'inserted') return Object.freeze({ acknowledged: true, insertedId: document._id as string });
100
+ const messages = {
101
+ unique_conflict: 'Bootstrap record conflicts with a unique index.',
102
+ invalid_configuration: 'Bootstrap insertion requires absent or exact primary-only collection topology.',
103
+ ambiguous_write: 'Bootstrap insertion outcome is uncertain; inspect its explicit ID before proceeding.',
104
+ };
105
+ throw new SmartdataPersistenceError(outcome, messages[outcome]);
106
+ } finally { budget.close(); }
107
+ };
@@ -0,0 +1,25 @@
1
+ import * as plugins from './plugins.js';
2
+
3
+ /** @internal Shared ordinary/exact assertion invariant. */
4
+ export const assertBsonWithoutMutation = (
5
+ documentArg: object,
6
+ assertionArg: (valueArg: unknown) => void,
7
+ errorArg: (reasonArg: 'assertion' | 'bson' | 'mutation', causeArg?: unknown) => Error,
8
+ ): void => {
9
+ const before = plugins.mongodb.BSON.serialize(documentArg);
10
+ try {
11
+ const result = assertionArg(documentArg) as unknown;
12
+ if (result !== undefined) {
13
+ // Reject asynchronous assertions and consume a native rejection so it
14
+ // cannot escape later as an unhandled process error.
15
+ if (result instanceof Promise) void result.catch(() => undefined);
16
+ throw new Error('Document assertions must be synchronous and return undefined.');
17
+ }
18
+ } catch (causeArg) { throw errorArg('assertion', causeArg); }
19
+ let after: Uint8Array;
20
+ try { after = plugins.mongodb.BSON.serialize(documentArg); }
21
+ catch (causeArg) { throw errorArg('bson', causeArg); }
22
+ if (before.length !== after.length || before.some((valueArg, indexArg) => valueArg !== after[indexArg])) {
23
+ throw errorArg('mutation');
24
+ }
25
+ };
@@ -0,0 +1,45 @@
1
+ import * as plugins from './plugins.js';
2
+
3
+ const typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
4
+ const bufferGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, 'buffer')!.get!;
5
+ const offsetGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, 'byteOffset')!.get!;
6
+ const lengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, 'byteLength')!.get!;
7
+
8
+ /** @internal Read the official ObjectId layouts without executing caller code. */
9
+ export const getInertObjectIdBytes = (valueArg: object, errorArg: () => Error): Uint8Array => {
10
+ if (plugins.nodeUtil.types.isProxy(valueArg) ||
11
+ Object.getPrototypeOf(valueArg) !== plugins.mongodb.ObjectId.prototype) throw errorArg();
12
+ const toBson = Object.getOwnPropertyDescriptor(valueArg, 'toBSON');
13
+ if (toBson && (!('value' in toBson) || toBson.value !== undefined || toBson.enumerable)) throw errorArg();
14
+ const keys = Reflect.ownKeys(valueArg).filter((keyArg) => keyArg !== 'toBSON');
15
+ const getData = (keyArg: string): unknown => {
16
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, keyArg);
17
+ if (!descriptor || !('value' in descriptor)) throw errorArg();
18
+ return descriptor.value;
19
+ };
20
+ if (keys.length === 1 && keys[0] === 'buffer') {
21
+ const buffer = getData('buffer');
22
+ if (typeof buffer !== 'object' || !buffer || plugins.nodeUtil.types.isProxy(buffer) ||
23
+ !ArrayBuffer.isView(buffer)) throw errorArg();
24
+ const prototype = Object.getPrototypeOf(buffer);
25
+ if (prototype !== Uint8Array.prototype && prototype !== Buffer.prototype) throw errorArg();
26
+ if (Reflect.apply(lengthGetter, buffer, []) !== 12 || Reflect.ownKeys(buffer).length !== 12) throw errorArg();
27
+ return new Uint8Array(Reflect.apply(bufferGetter, buffer, []),
28
+ Reflect.apply(offsetGetter, buffer, []), 12).slice();
29
+ }
30
+ // BSON 7.3.2 replaced the byte buffer with four unsigned 24-bit words.
31
+ const wordKeys = ['i0', 'i1', 'i2', 'i3'];
32
+ if (keys.length !== 4 || keys.some((keyArg) => typeof keyArg !== 'string' || !wordKeys.includes(keyArg))) {
33
+ throw errorArg();
34
+ }
35
+ const bytes = new Uint8Array(12);
36
+ for (let index = 0; index < wordKeys.length; index++) {
37
+ const word = getData(wordKeys[index]);
38
+ if (typeof word !== 'number' || !Number.isInteger(word) ||
39
+ word < 0 || word > 0xffffff || Object.is(word, -0)) throw errorArg();
40
+ bytes[index * 3] = (word >>> 16) & 0xff;
41
+ bytes[index * 3 + 1] = (word >>> 8) & 0xff;
42
+ bytes[index * 3 + 2] = word & 0xff;
43
+ }
44
+ return bytes;
45
+ };
@@ -0,0 +1,105 @@
1
+ import * as plugins from './plugins.js';
2
+ import { getInertObjectIdBytes } from './classes.bsonobjectid.js';
3
+
4
+ /** @internal Snapshot bounded inert BSON without invoking caller serialization. */
5
+ export const snapshotBoundedBsonDocument = (
6
+ valueArg: unknown, maxBytesArg: number, errorArg: () => Error,
7
+ ): plugins.mongodb.Document => {
8
+ const faultError = errorArg;
9
+ /** A deliberately small BSON subset; descriptors are read without invoking user code. */
10
+ const snapshotBsonValue = (
11
+ valueArg: unknown,
12
+ budgetArg: { remaining: number; bytes: number },
13
+ seenArg = new WeakSet<object>(),
14
+ depthArg = 0,
15
+ ): unknown => {
16
+ if (--budgetArg.remaining < 0 || depthArg > 64) throw faultError();
17
+ if (typeof valueArg === 'string') {
18
+ if (valueArg.length > budgetArg.bytes) throw faultError();
19
+ budgetArg.bytes -= Buffer.byteLength(valueArg, 'utf8');
20
+ if (budgetArg.bytes < 0) throw faultError();
21
+ return valueArg;
22
+ }
23
+ if (valueArg === null || typeof valueArg === 'boolean') return valueArg;
24
+ if (typeof valueArg === 'number' && Number.isFinite(valueArg)) return valueArg;
25
+ if (typeof valueArg !== 'object' || !valueArg || plugins.nodeUtil.types.isProxy(valueArg) ||
26
+ seenArg.has(valueArg)) throw faultError();
27
+ seenArg.add(valueArg);
28
+ try {
29
+ const prototype = Object.getPrototypeOf(valueArg);
30
+ if (prototype === Date.prototype && Reflect.ownKeys(valueArg).length === 0) {
31
+ const time = Date.prototype.getTime.call(valueArg);
32
+ if (!Number.isFinite(time)) throw faultError();
33
+ return new Date(time);
34
+ }
35
+ if (prototype === plugins.mongodb.ObjectId.prototype) {
36
+ if (Object.hasOwn(valueArg, 'toBSON')) throw faultError();
37
+ const bytes = getInertObjectIdBytes(valueArg, faultError);
38
+ budgetArg.bytes -= bytes.length;
39
+ if (budgetArg.bytes < 0) throw faultError();
40
+ return new plugins.mongodb.ObjectId(bytes);
41
+ }
42
+ if (prototype === Uint8Array.prototype || prototype === Buffer.prototype) {
43
+ // TypedArray intrinsics avoid overridable length, iterator and buffer getters.
44
+ const typedPrototype = Object.getPrototypeOf(Uint8Array.prototype);
45
+ const length = Reflect.apply(Object.getOwnPropertyDescriptor(typedPrototype, 'byteLength')!.get!, valueArg, []);
46
+ if (length > budgetArg.bytes || Reflect.ownKeys(valueArg).length !== length) throw faultError();
47
+ budgetArg.bytes -= length;
48
+ const buffer = Reflect.apply(Object.getOwnPropertyDescriptor(typedPrototype, 'buffer')!.get!, valueArg, []);
49
+ const offset = Reflect.apply(Object.getOwnPropertyDescriptor(typedPrototype, 'byteOffset')!.get!, valueArg, []);
50
+ return new plugins.mongodb.Binary(new Uint8Array(buffer, offset, length).slice());
51
+ }
52
+ if (prototype === plugins.mongodb.Binary.prototype) {
53
+ const buffer = Object.getOwnPropertyDescriptor(valueArg, 'buffer');
54
+ const position = Object.getOwnPropertyDescriptor(valueArg, 'position');
55
+ const subtype = Object.getOwnPropertyDescriptor(valueArg, 'sub_type');
56
+ if (Reflect.ownKeys(valueArg).length !== 3 || !buffer || !position || !subtype ||
57
+ !('value' in buffer) || !('value' in position) || !('value' in subtype) ||
58
+ !Number.isSafeInteger(position.value) || position.value < 0 ||
59
+ !Number.isSafeInteger(subtype.value) || subtype.value < 0 || subtype.value > 255) throw faultError();
60
+ const bytes = snapshotBsonValue(buffer.value, budgetArg, seenArg, depthArg + 1);
61
+ if (!(bytes instanceof plugins.mongodb.Binary) || position.value > bytes.buffer.length) throw faultError();
62
+ return new plugins.mongodb.Binary(bytes.buffer.slice(0, position.value), subtype.value);
63
+ }
64
+ const array = Array.isArray(valueArg);
65
+ if (array ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) throw faultError();
66
+ const keys = Reflect.ownKeys(valueArg);
67
+ if (keys.length > budgetArg.remaining || (array && keys.length !== valueArg.length + 1)) throw faultError();
68
+ const result: Record<string, unknown> | unknown[] = array ? [] : Object.create(null);
69
+ if (keys.some((keyArg) => typeof keyArg !== 'string')) throw faultError();
70
+ for (const key of (keys as string[]).sort()) {
71
+ if (array && key === 'length') continue;
72
+ if (typeof key !== 'string' || key.includes('\0') || key === 'toBSON' || key === '_bsontype') throw faultError();
73
+ if (key.length > budgetArg.bytes) throw faultError();
74
+ budgetArg.bytes -= Buffer.byteLength(key, 'utf8');
75
+ if (budgetArg.bytes < 0) throw faultError();
76
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key)!;
77
+ if (!('value' in descriptor) || !descriptor.enumerable ||
78
+ (array && (!/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= valueArg.length))) throw faultError();
79
+ Object.defineProperty(result, key, { value: snapshotBsonValue(descriptor.value, budgetArg, seenArg, depthArg + 1),
80
+ enumerable: true, writable: true, configurable: true });
81
+ }
82
+ return result;
83
+ } finally { seenArg.delete(valueArg); }
84
+ };
85
+
86
+ const canonicalBsonDocument = (valueArg: unknown, maxBytesArg: number): plugins.mongodb.Document => {
87
+ try {
88
+ const snapshot = snapshotBsonValue(valueArg, { remaining: 100_000, bytes: maxBytesArg });
89
+ if (!snapshot || Array.isArray(snapshot) || Object.getPrototypeOf(snapshot) !== null ||
90
+ !Object.hasOwn(snapshot, '_id')) throw faultError();
91
+ const document = snapshot as plugins.mongodb.Document;
92
+ const id = document._id;
93
+ if (!(typeof id === 'string' && id.length > 0) &&
94
+ !(typeof id === 'number' && Number.isFinite(id)) &&
95
+ !(id instanceof plugins.mongodb.ObjectId)) throw faultError();
96
+ const bytes = plugins.mongodb.BSON.serialize(document);
97
+ if (bytes.byteLength > maxBytesArg) throw faultError();
98
+ const canonical = plugins.mongodb.BSON.deserialize(bytes);
99
+ if (!Buffer.from(bytes).equals(Buffer.from(plugins.mongodb.BSON.serialize(canonical)))) throw faultError();
100
+ return canonical;
101
+ } catch { throw faultError(); }
102
+ };
103
+
104
+ return canonicalBsonDocument(valueArg, maxBytesArg);
105
+ };
@@ -0,0 +1,67 @@
1
+ import { SmartDataDbDoc, index, svDb } from './classes.doc.js';
2
+
3
+ /**
4
+ * Common TTL values in milliseconds for cache-like documents.
5
+ */
6
+ export const smartdataTtlValues = {
7
+ HOURS_1: 1 * 60 * 60 * 1000,
8
+ HOURS_24: 24 * 60 * 60 * 1000,
9
+ DAYS_7: 7 * 24 * 60 * 60 * 1000,
10
+ DAYS_30: 30 * 24 * 60 * 60 * 1000,
11
+ DAYS_90: 90 * 24 * 60 * 60 * 1000,
12
+ } as const;
13
+
14
+ /**
15
+ * Base class for SmartData documents that should expire after an absolute date.
16
+ */
17
+ export abstract class SmartdataCachedDocument<
18
+ T extends SmartdataCachedDocument<T>,
19
+ > extends SmartDataDbDoc<T, T> {
20
+ @svDb()
21
+ public createdAt: Date = new Date();
22
+
23
+ @index({ expireAfterSeconds: 0 })
24
+ public expiresAt?: Date;
25
+
26
+ @svDb()
27
+ public lastAccessedAt: Date = new Date();
28
+
29
+ public setTTL(ttlMs: number): void {
30
+ this.expiresAt = new Date(Date.now() + ttlMs);
31
+ }
32
+
33
+ public setTTLDays(days: number): void {
34
+ this.setTTL(days * 24 * 60 * 60 * 1000);
35
+ }
36
+
37
+ public setTTLHours(hours: number): void {
38
+ this.setTTL(hours * 60 * 60 * 1000);
39
+ }
40
+
41
+ public isExpired(): boolean {
42
+ if (!this.expiresAt) {
43
+ return false;
44
+ }
45
+ return Date.now() > this.expiresAt.getTime();
46
+ }
47
+
48
+ public touch(): void {
49
+ this.lastAccessedAt = new Date();
50
+ }
51
+
52
+ public getRemainingTTL(): number {
53
+ if (!this.expiresAt) {
54
+ return -1;
55
+ }
56
+ const remaining = this.expiresAt.getTime() - Date.now();
57
+ return remaining > 0 ? remaining : 0;
58
+ }
59
+
60
+ public extendTTL(ttlMs: number): void {
61
+ this.expiresAt = new Date(Date.now() + ttlMs);
62
+ }
63
+
64
+ public setNeverExpires(): void {
65
+ this.expiresAt = new Date(Date.now() + 100 * 365 * 24 * 60 * 60 * 1000);
66
+ }
67
+ }