@lossless.org/objectstorage 10.7.1 → 11.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 (51) hide show
  1. package/.smartconfig.json +30 -10
  2. package/dist_rust/ruststorage_linux_amd64 +0 -0
  3. package/dist_rust/ruststorage_linux_amd64.tsrust-build.json +5 -5
  4. package/dist_rust/ruststorage_linux_amd64_musl +0 -0
  5. package/dist_rust/ruststorage_linux_amd64_musl.tsrust-build.json +5 -5
  6. package/dist_rust/ruststorage_linux_arm64 +0 -0
  7. package/dist_rust/ruststorage_linux_arm64.tsrust-build.json +5 -5
  8. package/dist_rust/ruststorage_linux_arm64_musl +0 -0
  9. package/dist_rust/ruststorage_linux_arm64_musl.tsrust-build.json +5 -5
  10. package/dist_rust/ruststorage_macos_amd64 +0 -0
  11. package/dist_rust/ruststorage_macos_amd64.tsrust-build.json +5 -5
  12. package/dist_rust/ruststorage_macos_arm64 +0 -0
  13. package/dist_rust/ruststorage_macos_arm64.tsrust-build.json +5 -5
  14. package/dist_ts/00_commitinfo_data.js +1 -1
  15. package/dist_ts/classes.dashboard.d.ts +49 -0
  16. package/dist_ts/classes.dashboard.js +234 -0
  17. package/dist_ts/dashboard.bundled.d.ts +4 -0
  18. package/dist_ts/dashboard.bundled.js +20 -0
  19. package/dist_ts/dashboard.interfaces.d.ts +132 -0
  20. package/dist_ts/dashboard.interfaces.js +2 -0
  21. package/dist_ts/dashboard.plugins.d.ts +5 -0
  22. package/dist_ts/dashboard.plugins.js +10 -0
  23. package/dist_ts/index.d.ts +219 -1
  24. package/dist_ts/index.js +209 -8
  25. package/package.json +17 -16
  26. package/readme.md +711 -30
  27. package/third-party-notices.md +21 -5
  28. package/third_party_licenses/borsh-1.8.1-license.txt +23 -0
  29. package/third_party_licenses/borsh-derive-1.8.1-apache-2.0.txt +201 -0
  30. package/third_party_licenses/cargo-dependencies.html +420 -0
  31. package/third_party_licenses/dyn-clone-1.0.20-license.txt +23 -0
  32. package/third_party_licenses/equivalent-1.0.3-license.txt +25 -0
  33. package/third_party_licenses/hashbrown-0.17.1-license.txt +25 -0
  34. package/third_party_licenses/indexmap-2.14.2-license.txt +25 -0
  35. package/third_party_licenses/inventory.json +310 -8
  36. package/third_party_licenses/proc-macro-crate-3.5.0-license.txt +23 -0
  37. package/third_party_licenses/ref-cast-1.0.27-license.txt +23 -0
  38. package/third_party_licenses/ref-cast-impl-1.0.27-license.txt +23 -0
  39. package/third_party_licenses/schemars-1.2.3-license.txt +21 -0
  40. package/third_party_licenses/syn-3.0.9-license.txt +23 -0
  41. package/third_party_licenses/toml_datetime-1.1.2-license.txt +19 -0
  42. package/third_party_licenses/toml_edit-0.25.17-license.txt +19 -0
  43. package/third_party_licenses/toml_parser-1.1.5-license.txt +19 -0
  44. package/third_party_licenses/winnow-1.0.4-license.txt +18 -0
  45. package/ts/00_commitinfo_data.ts +1 -1
  46. package/ts/classes.dashboard.ts +280 -0
  47. package/ts/dashboard.bundled.ts.third-party-notices.json +1741 -0
  48. package/ts/dashboard.bundled.ts.third-party-notices.txt +5015 -0
  49. package/ts/dashboard.interfaces.ts +148 -0
  50. package/ts/dashboard.plugins.ts +13 -0
  51. package/ts/index.ts +473 -14
@@ -0,0 +1,132 @@
1
+ import type { ITypedRequest, implementsTR } from '@api.global/typedrequest-interfaces';
2
+ import type { ITypedSocketEvent } from '@api.global/typedsocket';
3
+ /**
4
+ * Engine snapshot shapes, as `ObjectStorage.getClusterSnapshot()` returns
5
+ * them. The engine builds them from memory only: the drive states the last
6
+ * heartbeat probe left, runtime stats, healing state, S3 listener counters
7
+ * and a bounded ring of recent events. Times are milliseconds since the Unix
8
+ * epoch; absent values are `null`.
9
+ */
10
+ export interface IObjectStorageTelemetryEvent {
11
+ /** Numbered per node from 1; a gap means older events left the ring. */
12
+ seq: number;
13
+ at: number;
14
+ kind: 'engine' | 'peer' | 'drive' | 'healing';
15
+ severity: 'info' | 'warning' | 'error';
16
+ message: string;
17
+ }
18
+ /** S3 listener counters since the engine started; bytes include HTTP headers. */
19
+ export interface IObjectStorageTrafficCounters {
20
+ requestsTotal: number;
21
+ errorResponses: number;
22
+ bytesIn: number;
23
+ bytesOut: number;
24
+ }
25
+ export interface IObjectStorageStorageTotals {
26
+ bucketCount: number;
27
+ objectCount: number;
28
+ totalBytes: number;
29
+ }
30
+ export interface IObjectStorageDriveSnapshot {
31
+ index: number;
32
+ path: string;
33
+ status: 'online' | 'degraded' | 'offline' | 'healing';
34
+ totalBytes: number;
35
+ usedBytes: number;
36
+ availableBytes: number;
37
+ errorCount: number;
38
+ lastError: string | null;
39
+ lastCheck: number | null;
40
+ erasureSetId: number | null;
41
+ }
42
+ export interface IObjectStorageHealingSnapshot {
43
+ active: boolean;
44
+ scanIntervalMs: number;
45
+ lastRunStartedAt: number | null;
46
+ lastRunCompletedAt: number | null;
47
+ lastDurationMs: number | null;
48
+ shardsChecked: number | null;
49
+ shardsHealed: number | null;
50
+ shardsPending: number | null;
51
+ failed: number | null;
52
+ lastError: string | null;
53
+ }
54
+ /** What one node reports about itself; local and remote nodes share this shape. */
55
+ export interface IObjectStorageNodeSnapshot {
56
+ /** Absent in standalone mode. */
57
+ nodeId: string | null;
58
+ mode: 'standalone' | 'cluster';
59
+ startedAt: number;
60
+ capturedAt: number;
61
+ traffic: IObjectStorageTrafficCounters;
62
+ storage: IObjectStorageStorageTotals;
63
+ /** Local drives (cluster mode); empty in standalone mode. */
64
+ drives: IObjectStorageDriveSnapshot[];
65
+ healing: IObjectStorageHealingSnapshot | null;
66
+ /** Recent events, oldest first. */
67
+ events: IObjectStorageTelemetryEvent[];
68
+ }
69
+ export interface IObjectStoragePeerSnapshot {
70
+ nodeId: string;
71
+ status: 'online' | 'suspect' | 'offline';
72
+ quicAddress: string;
73
+ s3Address: string;
74
+ driveCount: number;
75
+ lastHeartbeat: number;
76
+ missedHeartbeats: number;
77
+ /** The peer's own snapshot, when it answered within a second. */
78
+ snapshot: IObjectStorageNodeSnapshot | null;
79
+ unavailableReason: string | null;
80
+ }
81
+ export interface IObjectStorageErasureSnapshot {
82
+ dataShards: number;
83
+ parityShards: number;
84
+ chunkSizeBytes: number;
85
+ totalShards: number;
86
+ readQuorum: number;
87
+ writeQuorum: number;
88
+ erasureSetCount: number;
89
+ }
90
+ export interface IObjectStorageClusterViewSnapshot {
91
+ nodeId: string;
92
+ quorumHealthy: boolean;
93
+ majorityHealthy: boolean;
94
+ erasure: IObjectStorageErasureSnapshot;
95
+ peers: IObjectStoragePeerSnapshot[];
96
+ }
97
+ export interface IObjectStorageClusterSnapshot {
98
+ capturedAt: number;
99
+ clusterEnabled: boolean;
100
+ local: IObjectStorageNodeSnapshot;
101
+ /** Absent in standalone mode. */
102
+ cluster: IObjectStorageClusterViewSnapshot | null;
103
+ }
104
+ /**
105
+ * Dashboard configuration. The dashboard is off unless `enabled` is true.
106
+ */
107
+ export interface IObjectStorageDashboardConfig {
108
+ enabled: boolean;
109
+ /** Interface the dashboard listens on. Default `127.0.0.1`. */
110
+ address?: string;
111
+ /** TCP port; `0` asks the OS for one. Default 3001; must differ from the S3 port. */
112
+ port?: number;
113
+ }
114
+ /** One dashboard sample, as pushed to every connected dashboard. */
115
+ export interface IObjectStorageDashboardSample {
116
+ sampledAt: number;
117
+ /** The snapshot, or `null` when the engine could not answer. */
118
+ snapshot: IObjectStorageClusterSnapshot | null;
119
+ error: string | null;
120
+ /** Events were left out of peer snapshots to keep the sample within the push limit. */
121
+ eventsTruncated: boolean;
122
+ }
123
+ /** Answers with the latest sample, taking one when none exists yet. */
124
+ export interface IReq_ObjectStorageDashboardGetSample extends implementsTR<ITypedRequest, IReq_ObjectStorageDashboardGetSample> {
125
+ method: 'objectStorageDashboardGetSample';
126
+ request: Record<string, never>;
127
+ response: IObjectStorageDashboardSample;
128
+ }
129
+ /** Pushed every two seconds while at least one dashboard is connected. */
130
+ export interface IEvent_ObjectStorageDashboardSample extends ITypedSocketEvent<IObjectStorageDashboardSample> {
131
+ name: 'objectStorageDashboardSample';
132
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLmludGVyZmFjZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9kYXNoYm9hcmQuaW50ZXJmYWNlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -0,0 +1,5 @@
1
+ import * as typedrequest from '@api.global/typedrequest';
2
+ import * as typedsocket from '@api.global/typedsocket';
3
+ export { typedrequest, typedsocket };
4
+ import * as smartserve from '@push.rocks/smartserve';
5
+ export { smartserve };
@@ -0,0 +1,10 @@
1
+ // Loaded only by the dashboard module, which `ObjectStorage` imports
2
+ // dynamically when the dashboard is enabled.
3
+ // @api.global scope
4
+ import * as typedrequest from '@api.global/typedrequest';
5
+ import * as typedsocket from '@api.global/typedsocket';
6
+ export { typedrequest, typedsocket };
7
+ // @push.rocks scope
8
+ import * as smartserve from '@push.rocks/smartserve';
9
+ export { smartserve };
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9kYXNoYm9hcmQucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxRUFBcUU7QUFDckUsNkNBQTZDO0FBRTdDLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUMifQ==
@@ -1,4 +1,6 @@
1
1
  import * as plugins from './plugins.js';
2
+ import type { IObjectStorageClusterSnapshot, IObjectStorageDashboardConfig } from './dashboard.interfaces.js';
3
+ export * from './dashboard.interfaces.js';
2
4
  /**
3
5
  * Authentication configuration
4
6
  */
@@ -54,6 +56,11 @@ export interface ILimitsConfig {
54
56
  export interface IMultipartConfig {
55
57
  expirationDays?: number;
56
58
  cleanupIntervalMinutes?: number;
59
+ /**
60
+ * Open multipart uploads that the prefix credentials of one scope (bucket
61
+ * and prefix) may hold together (default 100). Counted in memory.
62
+ */
63
+ maxUploadsPerPrefixScope?: number;
57
64
  }
58
65
  /**
59
66
  * Server configuration
@@ -100,6 +107,11 @@ export interface IStorageConfig {
100
107
  export interface IErasureConfig {
101
108
  dataShards?: number;
102
109
  parityShards?: number;
110
+ /**
111
+ * Bytes per erasure-coded chunk, between 1 and 64 MiB (67,108,864 bytes);
112
+ * startup refuses a value outside that range, because every manifest
113
+ * refuses a larger chunk. Default 4,194,304 (4 MiB).
114
+ */
103
115
  chunkSizeBytes?: number;
104
116
  }
105
117
  /**
@@ -107,12 +119,41 @@ export interface IErasureConfig {
107
119
  */
108
120
  export interface IDriveConfig {
109
121
  paths: string[];
122
+ /**
123
+ * Accept drive roots that share a device (`st_dev`). Each drive root counts
124
+ * as one failure domain, so by default startup refuses two drive roots on
125
+ * one device. Set this only for dev and test clusters whose drive roots are
126
+ * directories on one filesystem. Default false.
127
+ */
128
+ allowSharedDevice?: boolean;
129
+ }
130
+ /**
131
+ * Mutual TLS for the cluster transport. Every file is read once at startup and
132
+ * must lie outside the control and drive roots, at an absolute path without
133
+ * symbolic links; a restart reloads them.
134
+ */
135
+ export interface IClusterTlsConfig {
136
+ /** PEM file with one or two CA certificates (two only during a CA rotation). */
137
+ caFile: string;
138
+ /**
139
+ * PEM file with this node's certificate, optionally followed by intermediates. It has one DNS SAN,
140
+ * equal to nodeId, and is valid for server and client authentication: an extended key usage
141
+ * extension listing serverAuth and clientAuth, or no extended key usage extension.
142
+ */
143
+ certFile: string;
144
+ /** PEM private key of certFile; owned by the engine's user, mode 0600 or 0400. */
145
+ keyFile: string;
110
146
  }
111
147
  /**
112
148
  * Cluster configuration for distributed mode
113
149
  */
114
150
  export interface IClusterConfig {
115
151
  enabled: boolean;
152
+ /**
153
+ * This node's id. Generated and persisted when omitted, except with `tls`:
154
+ * then it is required and must be a lowercase DNS name equal to the node
155
+ * certificate's DNS subject alternative name.
156
+ */
116
157
  nodeId?: string;
117
158
  quicPort?: number;
118
159
  seedNodes?: string[];
@@ -120,11 +161,27 @@ export interface IClusterConfig {
120
161
  drives?: IDriveConfig;
121
162
  heartbeatIntervalMs?: number;
122
163
  heartbeatTimeoutMs?: number;
164
+ /**
165
+ * Longest a single GET may run, in milliseconds, from its start to its last
166
+ * byte, including the client's transfer time. A longer GET is aborted.
167
+ * Superseded and deleted object generations keep their shards for this
168
+ * deadline plus the smaller of the deadline and one hour, then cleanup frees
169
+ * them. Must be the same on every node: a mismatch can abort streams but
170
+ * never serves wrong bytes. Default 21,600,000 (6 hours); allowed from
171
+ * 60,000 (1 minute) to 604,800,000 (7 days).
172
+ */
173
+ getDeadlineMs?: number;
174
+ /**
175
+ * Mutual TLS for the cluster transport. Without it the transport is
176
+ * encrypted but authenticates no peer. Every node of a cluster sets it, or
177
+ * none does: enabling it is a full stop of every node, not a rolling change.
178
+ */
179
+ tls?: IClusterTlsConfig;
123
180
  }
124
181
  /**
125
182
  * Configuration as the engine receives it: every section resolved.
126
183
  */
127
- export type TObjectStorageResolvedConfig = Required<Omit<IObjectStorageConfig, 'binaryPath'>>;
184
+ export type TObjectStorageResolvedConfig = Required<Omit<IObjectStorageConfig, 'binaryPath' | 'dashboard'>>;
128
185
  /**
129
186
  * Complete objectstorage configuration
130
187
  */
@@ -144,6 +201,11 @@ export interface IObjectStorageConfig {
144
201
  limits?: ILimitsConfig;
145
202
  multipart?: IMultipartConfig;
146
203
  cluster?: IClusterConfig;
204
+ /**
205
+ * The read-only visibility dashboard, served by this process on its own
206
+ * port. Off unless `enabled` is true; never sent to the engine.
207
+ */
208
+ dashboard?: IObjectStorageDashboardConfig;
147
209
  }
148
210
  /**
149
211
  * Logical bucket stats maintained by the Rust runtime.
@@ -281,6 +343,32 @@ export interface IBucketTenantMetadata {
281
343
  region?: string;
282
344
  retention?: IBucketRetentionReceipt;
283
345
  }
346
+ export interface IPrefixCredentialInput {
347
+ bucketName: string;
348
+ /** Unreserved characters (RFC 3986) and `/`; ends with `/`, no leading `/`. */
349
+ prefix: string;
350
+ /** First node: lifetime in seconds, 1..43200. */
351
+ ttlSeconds?: number;
352
+ /** Fan-out to further nodes: the first node's expiresAt (epoch ms). */
353
+ expiresAt?: number;
354
+ /** Supply both together with expiresAt to install an existing credential on another node. */
355
+ accessKeyId?: string;
356
+ secretAccessKey?: string;
357
+ region?: string;
358
+ }
359
+ export interface IPrefixCredentialMetadata {
360
+ accessKeyId: string;
361
+ bucketName: string;
362
+ prefix: string;
363
+ region: string;
364
+ /** Epoch ms. */
365
+ createdAt: number;
366
+ /** Epoch ms; requests are refused from this instant and admitted ones end at it. */
367
+ expiresAt: number;
368
+ }
369
+ export interface IPrefixCredential extends IPrefixCredentialMetadata {
370
+ secretAccessKey: string;
371
+ }
284
372
  export interface IBucketRetentionPolicyInput {
285
373
  mode: 'compliance';
286
374
  policyId: string;
@@ -622,6 +710,10 @@ export interface IObjectStorageHealth {
622
710
  enabled: boolean;
623
711
  credentialCount: number;
624
712
  tenantCredentialCount: number;
713
+ prefixCredentialCount: number;
714
+ prefixCredentialTombstoneCount: number;
715
+ /** False when the prefix credential file is unreadable: every prefix credential is refused. */
716
+ prefixCredentialStoreAvailable: boolean;
625
717
  };
626
718
  bucketCount: number;
627
719
  objectCount: number;
@@ -641,6 +733,12 @@ export declare class ObjectStorageResourceFenceError extends Error {
641
733
  readonly code: TObjectStorageResourceFenceErrorCode;
642
734
  constructor(codeArg: TObjectStorageResourceFenceErrorCode, messageArg: string, causeArg?: unknown);
643
735
  }
736
+ export declare const objectStorageCredentialErrorCodes: readonly ['ECREDENTIAL_AUTH_DISABLED', 'ECREDENTIAL_INVALID_PREFIX', 'ECREDENTIAL_INVALID_TTL', 'ECREDENTIAL_INVALID_EXPIRY', 'ECREDENTIAL_INVALID_KEY', 'ECREDENTIAL_NO_SUCH_BUCKET', 'ECREDENTIAL_BUCKET_UNAVAILABLE', 'ECREDENTIAL_CONFLICT', 'ECREDENTIAL_REVOKED', 'ECREDENTIAL_NOT_PREFIX', 'ECREDENTIAL_LIMIT', 'ECREDENTIAL_PERSISTENCE', 'ECREDENTIAL_STORE_UNAVAILABLE'];
737
+ export type TObjectStorageCredentialErrorCode = (typeof objectStorageCredentialErrorCodes)[number];
738
+ export declare class ObjectStorageCredentialError extends Error {
739
+ readonly code: TObjectStorageCredentialErrorCode;
740
+ constructor(codeArg: TObjectStorageCredentialErrorCode, messageArg: string, causeArg?: unknown);
741
+ }
644
742
  export interface IObjectStorageMetrics {
645
743
  bucketCount: number;
646
744
  objectCount: number;
@@ -662,6 +760,33 @@ export interface IClusterPeerHealth {
662
760
  lastHeartbeat?: number;
663
761
  missedHeartbeats?: number;
664
762
  }
763
+ /**
764
+ * A drive's medium: `'rotational'` and `'flash'` (network volumes included),
765
+ * `'smr'` for drive-managed SMR, which reports itself as rotational and is
766
+ * never detected, and `'zoned'` for host-managed or host-aware SMR and ZNS.
767
+ */
768
+ export type TDriveMedia = 'rotational' | 'smr' | 'flash' | 'zoned';
769
+ /**
770
+ * A drive's media.
771
+ */
772
+ export interface IClusterDriveMedia {
773
+ /**
774
+ * The media the configuration declares for the drive. Not reported yet:
775
+ * drives cannot declare their media.
776
+ */
777
+ declared?: TDriveMedia;
778
+ /**
779
+ * What the engine detected once at startup, from the whole disk behind the
780
+ * drive root's filesystem (Linux sysfs `queue/zoned` and `queue/rotational`;
781
+ * a partition counts as its disk). `'unknown'` for filesystems without a
782
+ * block device of their own (tmpfs, overlay, network filesystems),
783
+ * device-mapper, md, loop and other virtual block devices, and on every
784
+ * platform but Linux. Virtual and network block devices report the
785
+ * rotational flag their driver or hypervisor sets (QEMU disks show
786
+ * `'rotational'` unless configured with `rotation_rate=1`).
787
+ */
788
+ detected: TDriveMedia | 'unknown';
789
+ }
665
790
  /**
666
791
  * Local drive health as measured by objectstorage's runtime probes.
667
792
  */
@@ -676,6 +801,7 @@ export interface IClusterDriveHealth {
676
801
  lastError?: string;
677
802
  lastCheck?: number;
678
803
  erasureSetId?: number;
804
+ media: IClusterDriveMedia;
679
805
  }
680
806
  export interface IClusterErasureHealth {
681
807
  dataShards: number;
@@ -694,9 +820,28 @@ export interface IClusterRepairHealth {
694
820
  lastDurationMs?: number;
695
821
  shardsChecked?: number;
696
822
  shardsHealed?: number;
823
+ /** Pending shards (writes that failed at publication) the last scan left pending. */
824
+ shardsPending?: number;
697
825
  failed?: number;
698
826
  lastError?: string;
699
827
  }
828
+ export interface IClusterTransportCertificate {
829
+ /** SHA-256 of the DER certificate, lowercase hex. */
830
+ sha256: string;
831
+ /** Milliseconds since the Unix epoch. */
832
+ notAfter: number;
833
+ }
834
+ /**
835
+ * How the cluster transport authenticates peers, and the certificates it
836
+ * loaded at startup.
837
+ */
838
+ export interface IClusterTransportHealth {
839
+ mode: 'mutualTls' | 'unauthenticated';
840
+ /** This node's certificate; only in mode 'mutualTls'. */
841
+ certificate?: IClusterTransportCertificate;
842
+ /** The loaded CA bundle in file order; only in mode 'mutualTls'. */
843
+ caCertificates?: IClusterTransportCertificate[];
844
+ }
700
845
  /**
701
846
  * Cluster runtime health from the Rust core.
702
847
  * When clustering is disabled, the response is `{ enabled: false }`.
@@ -712,6 +857,34 @@ export interface IClusterHealth {
712
857
  drives?: IClusterDriveHealth[];
713
858
  erasure?: IClusterErasureHealth;
714
859
  repairs?: IClusterRepairHealth;
860
+ transport?: IClusterTransportHealth;
861
+ }
862
+ /**
863
+ * The result of one cluster healing scan, as `ObjectStorage.runHealingScan()`
864
+ * returns it. Times are milliseconds since the Unix epoch.
865
+ */
866
+ export interface IClusterHealingScanResult {
867
+ /** When the scan started; always after the request arrived. */
868
+ startedAt: number;
869
+ completedAt: number;
870
+ durationMs: number;
871
+ /** Shard placements checked at their drives (placements on offline nodes are not). */
872
+ shardsChecked: number;
873
+ /** Shards written: missing placements rebuilt and pending shards completed. */
874
+ shardsHealed: number;
875
+ /** Pending shards (writes that failed at publication) this scan left pending. */
876
+ shardsPending: number;
877
+ /** Failed checks, rebuilds, writes and manifest stores. */
878
+ failed: number;
879
+ }
880
+ export interface IRunHealingScanOptions {
881
+ /**
882
+ * How long to wait for the scan, in milliseconds. Defaults to the bridge's
883
+ * request timeout (300,000). The engine cannot cancel a scan: one that
884
+ * outlasts this keeps running, its result is discarded, and a later call
885
+ * joins the next scan that starts after it.
886
+ */
887
+ timeoutMs?: number;
715
888
  }
716
889
  /**
717
890
  * Main ObjectStorage class - production-ready S3-compatible storage server
@@ -737,11 +910,15 @@ export declare class ObjectStorage {
737
910
  private bridgeOwned;
738
911
  private stopRequested;
739
912
  private stopCompleted;
913
+ private readonly dashboardConfig;
914
+ private dashboard;
740
915
  constructor(configArg?: IObjectStorageConfig);
741
916
  start(): Promise<void>;
742
917
  private startInternal;
743
918
  /** Actual TCP port while running; the requested config port before/afterward. */
744
919
  get port(): number;
920
+ /** The dashboard's bound TCP port while it runs; `undefined` otherwise. */
921
+ get dashboardPort(): number | undefined;
745
922
  getStorageDescriptor(optionsArg?: Partial<plugins.tsclass.storage.IS3Descriptor>): Promise<plugins.tsclass.storage.IS3Descriptor>;
746
923
  private getEndpoint;
747
924
  private buildBucketTenantDescriptor;
@@ -757,6 +934,27 @@ export declare class ObjectStorage {
757
934
  getBucketTenantDescriptor(optionsArg: {
758
935
  bucketName: string;
759
936
  }): Promise<IBucketTenantDescriptor>;
937
+ /**
938
+ * Creates a credential confined to one key prefix of one bucket until its
939
+ * expiry. The first node takes `ttlSeconds`; further nodes of a fan-out take
940
+ * the first result's `accessKeyId`, `secretAccessKey` and `expiresAt`. The
941
+ * secret is returned only here and never kept by this instance.
942
+ */
943
+ createPrefixCredential(inputArg: IPrefixCredentialInput): Promise<IPrefixCredential>;
944
+ /**
945
+ * Revokes a prefix credential on this node. An unknown ID is recorded as
946
+ * revoked too, so a later create for it is refused; `revoked` is true only
947
+ * when a live credential was removed.
948
+ */
949
+ revokePrefixCredential(optionsArg: {
950
+ accessKeyId: string;
951
+ }): Promise<{
952
+ revoked: boolean;
953
+ }>;
954
+ /** Lists this node's live prefix credentials, without secrets. */
955
+ listPrefixCredentials(optionsArg?: {
956
+ bucketName?: string;
957
+ }): Promise<IPrefixCredentialMetadata[]>;
760
958
  getBucketRetentionCapability(): Promise<IBucketRetentionCapability>;
761
959
  getBucketRetentionReceipt(optionsArg: {
762
960
  bucketName: string;
@@ -789,6 +987,26 @@ export declare class ObjectStorage {
789
987
  */
790
988
  replaceCredentials(credentials: IStorageCredential[]): Promise<void>;
791
989
  getClusterHealth(): Promise<IClusterHealth>;
990
+ /**
991
+ * The dashboard's snapshot, built by the engine from memory only: it never
992
+ * probes a drive, syncs or walks storage. A cluster node also asks each
993
+ * online peer for its own snapshot, waiting up to a second per peer, in
994
+ * parallel; a peer that does not answer is reported unavailable. One
995
+ * snapshot runs at a time: a call while another runs rejects.
996
+ */
997
+ getClusterSnapshot(): Promise<IObjectStorageClusterSnapshot>;
998
+ /**
999
+ * Runs a healing scan on this cluster node and resolves with its result.
1000
+ * The scan covers the manifests this node coordinated. The request joins
1001
+ * the next scan that starts after it arrives, never one already running,
1002
+ * and requests that arrive together share one scan. It rejects in
1003
+ * standalone mode, when the scan fails (for example without a majority of
1004
+ * the cluster, or when a bucket's manifests cannot be listed), when 16
1005
+ * requests already wait for a scan to start, and when the engine shuts down
1006
+ * before the scan completes. The engine answers other management calls
1007
+ * while the scan runs.
1008
+ */
1009
+ runHealingScan(optionsArg?: IRunHealingScanOptions): Promise<IClusterHealingScanResult>;
792
1010
  getHealth(): Promise<IObjectStorageHealth>;
793
1011
  getMetrics(): Promise<IObjectStorageMetrics>;
794
1012
  /**