@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,445 @@
1
+ // classes.smartbucket.ts
2
+
3
+ import * as plugins from './plugins.js';
4
+ import { Bucket } from './classes.bucket.js';
5
+ import { normalizeStorageDescriptor } from './helpers.js';
6
+ import {
7
+ beginOperationLifecycleClose,
8
+ commitOperationLifecycleClient,
9
+ completeOperationLifecycleClose,
10
+ registerOperationLifecycle,
11
+ reserveOperationLifecycleClientMutation,
12
+ rollbackOperationLifecycleClientMutation,
13
+ } from './internal.exactupload.capability.js';
14
+ import type {
15
+ ISmartBucketReadinessOptions,
16
+ TSmartBucketReadinessFailureReason,
17
+ TSmartBucketReadinessResult,
18
+ } from './interfaces.js';
19
+
20
+ type TSmartBucketLifecycleState = 'open' | 'closing' | 'closed';
21
+ type TSmartBucketReadinessAbortSource = 'caller' | 'deadline';
22
+ type TSmartBucketReadinessSendOutcome = 'ready' | 'aborted' | 'unavailable';
23
+
24
+ const readinessDefaultTimeoutMs = 2_000;
25
+ const readinessMaximumTimeoutMs = 30_000;
26
+
27
+ export class SmartBucket {
28
+ public config: plugins.tsclass.storage.IStorageDescriptor;
29
+
30
+ private currentStorageClient: plugins.s3.S3Client;
31
+ private ownedStorageClient: plugins.s3.S3Client;
32
+ private lifecycleState: TSmartBucketLifecycleState = 'open';
33
+ private lifecycleEpoch = 0;
34
+ private activeReadinessControllers = new Set<AbortController>();
35
+ private retiredStorageClients = new WeakSet<plugins.s3.S3Client>();
36
+ private storageClientMutationInProgress = false;
37
+ private closePromise: Promise<void> | undefined;
38
+ private operationCloseStarted = false;
39
+ private operationCloseSettlement: Promise<void> | undefined;
40
+
41
+ /**
42
+ * The current S3 client used by bucket operations.
43
+ */
44
+ public get storageClient(): plugins.s3.S3Client {
45
+ return this.currentStorageClient;
46
+ }
47
+
48
+ /**
49
+ * Changes the current S3 client without transferring lifecycle ownership.
50
+ */
51
+ public set storageClient(storageClientArg: plugins.s3.S3Client) {
52
+ if (!this.isStorageClient(storageClientArg)) {
53
+ throw new TypeError('storageClient must provide send() and destroy() methods.');
54
+ }
55
+ if (this.lifecycleState !== 'open') {
56
+ throw new Error(`Cannot assign storageClient while SmartBucket is ${this.lifecycleState}.`);
57
+ }
58
+ if (this.storageClientMutationInProgress) {
59
+ throw new Error('Cannot assign storageClient during another client change.');
60
+ }
61
+ if (storageClientArg === this.currentStorageClient) {
62
+ return;
63
+ }
64
+ if (this.retiredStorageClients.has(storageClientArg)) {
65
+ throw new Error('Cannot reuse a storageClient retired by this SmartBucket.');
66
+ }
67
+
68
+ this.storageClientMutationInProgress = true;
69
+ let mutationReserved = false;
70
+ try {
71
+ reserveOperationLifecycleClientMutation(this);
72
+ mutationReserved = true;
73
+ this.lifecycleEpoch++;
74
+ this.abortActiveReadinessProbes();
75
+ this.currentStorageClient = storageClientArg;
76
+ commitOperationLifecycleClient(this, storageClientArg);
77
+ mutationReserved = false;
78
+ } finally {
79
+ if (mutationReserved) {
80
+ rollbackOperationLifecycleClientMutation(this);
81
+ }
82
+ this.storageClientMutationInProgress = false;
83
+ }
84
+ }
85
+
86
+ /** @deprecated Use storageClient instead */
87
+ public get s3Client(): plugins.s3.S3Client {
88
+ return this.currentStorageClient;
89
+ }
90
+
91
+ /**
92
+ * the constructor of SmartBucket
93
+ */
94
+ constructor(configArg: plugins.tsclass.storage.IStorageDescriptor, clientOptions: { forcePathStyle?: boolean } = {}) {
95
+ this.config = configArg;
96
+
97
+ // Use the normalizer to handle various endpoint formats
98
+ const { normalized } = normalizeStorageDescriptor(configArg);
99
+
100
+ this.currentStorageClient = new plugins.s3.S3Client({
101
+ endpoint: normalized.endpointUrl,
102
+ region: normalized.region,
103
+ credentials: normalized.credentials,
104
+ forcePathStyle: clientOptions.forcePathStyle ?? normalized.forcePathStyle,
105
+ });
106
+ this.ownedStorageClient = this.currentStorageClient;
107
+ registerOperationLifecycle(this, this.currentStorageClient);
108
+ }
109
+
110
+ public async createBucket(bucketNameArg: string) {
111
+ const bucket = await Bucket.createBucketByName(this, bucketNameArg);
112
+ return bucket;
113
+ }
114
+
115
+ public async removeBucket(bucketName: string) {
116
+ await Bucket.removeBucketByName(this, bucketName);
117
+ }
118
+
119
+ public async getBucketByName(bucketNameArg: string) {
120
+ return Bucket.getBucketByName(this, bucketNameArg);
121
+ }
122
+
123
+ /**
124
+ * Check if a bucket exists
125
+ */
126
+ public async bucketExists(bucketNameArg: string): Promise<boolean> {
127
+ const command = new plugins.s3.ListBucketsCommand({});
128
+ const buckets = await this.currentStorageClient.send(command);
129
+ return buckets.Buckets?.some(bucket => bucket.Name === bucketNameArg) ?? false;
130
+ }
131
+
132
+ /**
133
+ * Transfers exclusive lifecycle ownership of an S3 client to this SmartBucket.
134
+ */
135
+ public replaceStorageClient(storageClientArg: plugins.s3.S3Client): void {
136
+ if (!this.isStorageClient(storageClientArg)) {
137
+ throw new TypeError('storageClient must provide send() and destroy() methods.');
138
+ }
139
+ if (this.lifecycleState !== 'open') {
140
+ throw new Error(`Cannot replace storageClient while SmartBucket is ${this.lifecycleState}.`);
141
+ }
142
+ if (this.storageClientMutationInProgress) {
143
+ throw new Error('Cannot replace storageClient during another client change.');
144
+ }
145
+ if (this.retiredStorageClients.has(storageClientArg)) {
146
+ throw new Error('Cannot reuse a storageClient retired by this SmartBucket.');
147
+ }
148
+ if (
149
+ storageClientArg === this.currentStorageClient &&
150
+ storageClientArg === this.ownedStorageClient
151
+ ) {
152
+ return;
153
+ }
154
+
155
+ this.storageClientMutationInProgress = true;
156
+ let mutationReserved = false;
157
+ try {
158
+ reserveOperationLifecycleClientMutation(this);
159
+ mutationReserved = true;
160
+ if (storageClientArg !== this.ownedStorageClient) {
161
+ const previousOwnedStorageClient = this.ownedStorageClient;
162
+ try {
163
+ previousOwnedStorageClient.destroy();
164
+ } catch (error) {
165
+ // A throwing destroy has an unknown partial-teardown outcome. Keep
166
+ // the lifecycle reserved so no later operation can reuse it.
167
+ mutationReserved = false;
168
+ this.lifecycleState = 'closing';
169
+ this.lifecycleEpoch++;
170
+ this.abortActiveReadinessProbes();
171
+ this.operationCloseSettlement = beginOperationLifecycleClose(this);
172
+ this.operationCloseStarted = true;
173
+ throw error;
174
+ }
175
+ this.retiredStorageClients.add(previousOwnedStorageClient);
176
+ this.ownedStorageClient = storageClientArg;
177
+ }
178
+ this.currentStorageClient = storageClientArg;
179
+ commitOperationLifecycleClient(this, storageClientArg);
180
+ mutationReserved = false;
181
+ this.lifecycleEpoch++;
182
+ this.abortActiveReadinessProbes();
183
+ } finally {
184
+ if (mutationReserved) {
185
+ rollbackOperationLifecycleClientMutation(this);
186
+ }
187
+ this.storageClientMutationInProgress = false;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Performs a bounded, read-only round trip to verify bucket readiness.
193
+ */
194
+ public async checkReadiness(
195
+ bucketNameArg: string,
196
+ optionsArg: ISmartBucketReadinessOptions = {},
197
+ ): Promise<TSmartBucketReadinessResult> {
198
+ const startedAt = performance.now();
199
+ if (
200
+ typeof bucketNameArg !== 'string' ||
201
+ bucketNameArg.length === 0 ||
202
+ bucketNameArg.trim() !== bucketNameArg
203
+ ) {
204
+ throw new TypeError('Readiness bucketName must be a non-empty trimmed string.');
205
+ }
206
+
207
+ const timeoutMs = optionsArg.timeoutMs ?? readinessDefaultTimeoutMs;
208
+ if (
209
+ !Number.isSafeInteger(timeoutMs) ||
210
+ timeoutMs <= 0 ||
211
+ timeoutMs > readinessMaximumTimeoutMs
212
+ ) {
213
+ throw new TypeError(
214
+ `Readiness timeoutMs must be a positive safe integer no greater than ${readinessMaximumTimeoutMs}.`,
215
+ );
216
+ }
217
+
218
+ const lifecycleReason = this.getReadinessLifecycleReason();
219
+ if (lifecycleReason) {
220
+ return this.createReadinessFailure(lifecycleReason, startedAt);
221
+ }
222
+ if (this.storageClientMutationInProgress) {
223
+ return this.createReadinessFailure('unavailable', startedAt);
224
+ }
225
+
226
+ const callerSignal = optionsArg.signal;
227
+ if (callerSignal?.aborted) {
228
+ return this.createReadinessFailure('aborted', startedAt);
229
+ }
230
+
231
+ const lifecycleEpoch = this.lifecycleEpoch;
232
+ const storageClient = this.currentStorageClient;
233
+ const readinessController = new AbortController();
234
+ let abortSource: TSmartBucketReadinessAbortSource | undefined;
235
+
236
+ const abortForCaller = (): void => {
237
+ if (!abortSource) {
238
+ abortSource = 'caller';
239
+ }
240
+ readinessController.abort();
241
+ };
242
+
243
+ callerSignal?.addEventListener('abort', abortForCaller, { once: true });
244
+ const deadlineTimer = setTimeout(() => {
245
+ if (!abortSource) {
246
+ abortSource = 'deadline';
247
+ }
248
+ readinessController.abort();
249
+ }, timeoutMs);
250
+ this.activeReadinessControllers.add(readinessController);
251
+
252
+ let sendOutcome: TSmartBucketReadinessSendOutcome;
253
+ try {
254
+ sendOutcome = await this.sendReadinessProbe(
255
+ storageClient,
256
+ bucketNameArg,
257
+ readinessController.signal,
258
+ );
259
+ } finally {
260
+ clearTimeout(deadlineTimer);
261
+ callerSignal?.removeEventListener('abort', abortForCaller);
262
+ this.activeReadinessControllers.delete(readinessController);
263
+ }
264
+
265
+ const staleReason = this.getStaleReadinessReason(lifecycleEpoch, storageClient);
266
+ if (staleReason) {
267
+ return this.createReadinessFailure(staleReason, startedAt);
268
+ }
269
+ if (sendOutcome === 'aborted') {
270
+ if (abortSource === 'caller') {
271
+ return this.createReadinessFailure('aborted', startedAt);
272
+ }
273
+ if (abortSource === 'deadline') {
274
+ return this.createReadinessFailure('timeout', startedAt);
275
+ }
276
+ return this.createReadinessFailure('unavailable', startedAt);
277
+ }
278
+ if (sendOutcome === 'unavailable') {
279
+ return this.createReadinessFailure('unavailable', startedAt);
280
+ }
281
+
282
+ return {
283
+ ready: true,
284
+ status: 'ready',
285
+ durationMs: performance.now() - startedAt,
286
+ };
287
+ }
288
+
289
+ /**
290
+ * Cancels active readiness and object operations before closing the owned S3 client.
291
+ */
292
+ public close(): Promise<void> {
293
+ if (this.storageClientMutationInProgress) {
294
+ throw new Error('Cannot close SmartBucket during a storageClient change.');
295
+ }
296
+ if (this.closePromise) {
297
+ return this.closePromise;
298
+ }
299
+
300
+ let resolveClose!: () => void;
301
+ let rejectClose!: (errorArg: unknown) => void;
302
+ const closePromise = new Promise<void>((resolve, reject) => {
303
+ resolveClose = resolve;
304
+ rejectClose = reject;
305
+ });
306
+ this.closePromise = closePromise;
307
+
308
+ if (!this.operationCloseStarted) {
309
+ this.lifecycleState = 'closing';
310
+ this.lifecycleEpoch++;
311
+ this.abortActiveReadinessProbes();
312
+ this.operationCloseSettlement = beginOperationLifecycleClose(this);
313
+ this.operationCloseStarted = true;
314
+ }
315
+
316
+ const finishClose = (): void => {
317
+ try {
318
+ this.ownedStorageClient.destroy();
319
+ completeOperationLifecycleClose(this);
320
+ this.lifecycleState = 'closed';
321
+ resolveClose();
322
+ } catch (error) {
323
+ rejectClose(error);
324
+ }
325
+ };
326
+ if (this.operationCloseSettlement) {
327
+ void this.operationCloseSettlement.then(finishClose);
328
+ } else {
329
+ finishClose();
330
+ }
331
+ void closePromise.catch(() => {
332
+ if (this.closePromise === closePromise) {
333
+ this.closePromise = undefined;
334
+ }
335
+ });
336
+
337
+ return closePromise;
338
+ }
339
+
340
+ private isStorageClient(storageClientArg: unknown): storageClientArg is plugins.s3.S3Client {
341
+ if (typeof storageClientArg !== 'object' || storageClientArg === null) {
342
+ return false;
343
+ }
344
+ const storageClientCandidate = storageClientArg as {
345
+ send?: unknown;
346
+ destroy?: unknown;
347
+ };
348
+ return (
349
+ typeof storageClientCandidate.send === 'function' &&
350
+ typeof storageClientCandidate.destroy === 'function'
351
+ );
352
+ }
353
+
354
+ private abortActiveReadinessProbes(): void {
355
+ for (const readinessController of [...this.activeReadinessControllers]) {
356
+ readinessController.abort();
357
+ }
358
+ }
359
+
360
+ private sendReadinessProbe(
361
+ storageClientArg: plugins.s3.S3Client,
362
+ bucketNameArg: string,
363
+ signalArg: AbortSignal,
364
+ ): Promise<TSmartBucketReadinessSendOutcome> {
365
+ return new Promise((resolve) => {
366
+ let settled = false;
367
+ const settle = (outcomeArg: TSmartBucketReadinessSendOutcome): void => {
368
+ if (settled) {
369
+ return;
370
+ }
371
+ settled = true;
372
+ signalArg.removeEventListener('abort', abortReadinessProbe);
373
+ resolve(outcomeArg);
374
+ };
375
+ const abortReadinessProbe = (): void => {
376
+ settle('aborted');
377
+ };
378
+
379
+ signalArg.addEventListener('abort', abortReadinessProbe, { once: true });
380
+ if (signalArg.aborted) {
381
+ abortReadinessProbe();
382
+ return;
383
+ }
384
+
385
+ try {
386
+ const providerPromise = storageClientArg.send(
387
+ new plugins.s3.HeadBucketCommand({
388
+ Bucket: bucketNameArg,
389
+ }),
390
+ {
391
+ abortSignal: signalArg,
392
+ },
393
+ );
394
+ void providerPromise.then(
395
+ () => settle('ready'),
396
+ () => settle('unavailable'),
397
+ );
398
+ } catch {
399
+ settle('unavailable');
400
+ }
401
+ });
402
+ }
403
+
404
+ private getReadinessLifecycleReason():
405
+ | Extract<TSmartBucketReadinessFailureReason, 'closing' | 'closed'>
406
+ | undefined {
407
+ switch (this.lifecycleState) {
408
+ case 'open':
409
+ return undefined;
410
+ case 'closing':
411
+ return 'closing';
412
+ case 'closed':
413
+ return 'closed';
414
+ }
415
+ }
416
+
417
+ private getStaleReadinessReason(
418
+ lifecycleEpochArg: number,
419
+ storageClientArg: plugins.s3.S3Client,
420
+ ): TSmartBucketReadinessFailureReason | undefined {
421
+ const lifecycleReason = this.getReadinessLifecycleReason();
422
+ if (lifecycleReason) {
423
+ return lifecycleReason;
424
+ }
425
+ if (
426
+ this.lifecycleEpoch !== lifecycleEpochArg ||
427
+ this.currentStorageClient !== storageClientArg
428
+ ) {
429
+ return 'unavailable';
430
+ }
431
+ return undefined;
432
+ }
433
+
434
+ private createReadinessFailure(
435
+ reasonArg: TSmartBucketReadinessFailureReason,
436
+ startedAtArg: number,
437
+ ): TSmartBucketReadinessResult {
438
+ return {
439
+ ready: false,
440
+ status: 'unavailable',
441
+ reason: reasonArg,
442
+ durationMs: performance.now() - startedAtArg,
443
+ };
444
+ }
445
+ }
@@ -0,0 +1,30 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as interfaces from './interfaces.js';
3
+ import * as helpers from './helpers.js';
4
+ import type { Bucket } from './classes.bucket.js';
5
+ import type { Directory } from './classes.directory.js';
6
+ import type { File } from './classes.file.js';
7
+
8
+
9
+ export class Trash {
10
+ public bucketRef: Bucket;
11
+
12
+ constructor(bucketRefArg: Bucket) {
13
+ this.bucketRef = bucketRefArg;
14
+ }
15
+
16
+ public async getTrashDir() {
17
+ return this.bucketRef.getDirectoryFromPath({ path: '.trash' });
18
+ }
19
+
20
+ public async getTrashedFileByOriginalName(pathDescriptor: interfaces.IPathDecriptor): Promise<File> {
21
+ const trashDir = await this.getTrashDir();
22
+ const originalPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
23
+ const trashKey = await this.getTrashKeyByOriginalBasePath(originalPath);
24
+ return trashDir.getFile({ path: trashKey });
25
+ }
26
+
27
+ public async getTrashKeyByOriginalBasePath (originalPath: string): Promise<string> {
28
+ return plugins.smartstring.base64.encode(originalPath);
29
+ }
30
+ }