swarm-deploy 0.0.0 → 0.2.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 (148) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/LICENSE.md +201 -0
  3. package/NOTICE.md +13 -0
  4. package/README.md +1283 -0
  5. package/RELEASING.md +71 -0
  6. package/SECURITY.md +40 -0
  7. package/dist/abort.d.ts +16 -0
  8. package/dist/abort.js +52 -0
  9. package/dist/abort.js.map +1 -0
  10. package/dist/allowlist.d.ts +2 -0
  11. package/dist/allowlist.js +21 -0
  12. package/dist/allowlist.js.map +1 -0
  13. package/dist/bin/swarm-deploy.d.ts +2 -0
  14. package/dist/bin/swarm-deploy.js +41 -0
  15. package/dist/bin/swarm-deploy.js.map +1 -0
  16. package/dist/cli.d.ts +27 -0
  17. package/dist/cli.js +751 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/client.d.ts +111 -0
  20. package/dist/client.js +276 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/direct-dht.d.ts +81 -0
  23. package/dist/direct-dht.js +254 -0
  24. package/dist/direct-dht.js.map +1 -0
  25. package/dist/error-code.d.ts +15 -0
  26. package/dist/error-code.js +30 -0
  27. package/dist/error-code.js.map +1 -0
  28. package/dist/errors.d.ts +31 -0
  29. package/dist/errors.js +37 -0
  30. package/dist/errors.js.map +1 -0
  31. package/dist/events-node.d.ts +2 -0
  32. package/dist/events-node.js +7 -0
  33. package/dist/events-node.js.map +1 -0
  34. package/dist/files.d.ts +32 -0
  35. package/dist/files.js +85 -0
  36. package/dist/files.js.map +1 -0
  37. package/dist/fs-node.d.ts +2 -0
  38. package/dist/fs-node.js +7 -0
  39. package/dist/fs-node.js.map +1 -0
  40. package/dist/hooks-module.d.ts +9 -0
  41. package/dist/hooks-module.js +118 -0
  42. package/dist/hooks-module.js.map +1 -0
  43. package/dist/hooks.d.ts +69 -0
  44. package/dist/hooks.js +88 -0
  45. package/dist/hooks.js.map +1 -0
  46. package/dist/identity.d.ts +7 -0
  47. package/dist/identity.js +50 -0
  48. package/dist/identity.js.map +1 -0
  49. package/dist/index.d.ts +12 -0
  50. package/dist/index.js +21 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/os-node.d.ts +2 -0
  53. package/dist/os-node.js +7 -0
  54. package/dist/os-node.js.map +1 -0
  55. package/dist/path-node.d.ts +2 -0
  56. package/dist/path-node.js +7 -0
  57. package/dist/path-node.js.map +1 -0
  58. package/dist/process-node.d.ts +2 -0
  59. package/dist/process-node.js +7 -0
  60. package/dist/process-node.js.map +1 -0
  61. package/dist/release.d.ts +26 -0
  62. package/dist/release.js +419 -0
  63. package/dist/release.js.map +1 -0
  64. package/dist/server.d.ts +239 -0
  65. package/dist/server.js +928 -0
  66. package/dist/server.js.map +1 -0
  67. package/dist/storage/atomic-file.d.ts +15 -0
  68. package/dist/storage/atomic-file.js +172 -0
  69. package/dist/storage/atomic-file.js.map +1 -0
  70. package/dist/storage/commit-journal.d.ts +120 -0
  71. package/dist/storage/commit-journal.js +417 -0
  72. package/dist/storage/commit-journal.js.map +1 -0
  73. package/dist/storage/commit-store.d.ts +307 -0
  74. package/dist/storage/commit-store.js +1691 -0
  75. package/dist/storage/commit-store.js.map +1 -0
  76. package/dist/storage/layout.d.ts +16 -0
  77. package/dist/storage/layout.js +409 -0
  78. package/dist/storage/layout.js.map +1 -0
  79. package/dist/storage/link-store.d.ts +70 -0
  80. package/dist/storage/link-store.js +363 -0
  81. package/dist/storage/link-store.js.map +1 -0
  82. package/dist/storage/recovery.d.ts +100 -0
  83. package/dist/storage/recovery.js +260 -0
  84. package/dist/storage/recovery.js.map +1 -0
  85. package/dist/storage/retention.d.ts +183 -0
  86. package/dist/storage/retention.js +619 -0
  87. package/dist/storage/retention.js.map +1 -0
  88. package/dist/storage/root-coordinator.d.ts +7 -0
  89. package/dist/storage/root-coordinator.js +27 -0
  90. package/dist/storage/root-coordinator.js.map +1 -0
  91. package/dist/storage/session-store.d.ts +2 -0
  92. package/dist/storage/session-store.js +7 -0
  93. package/dist/storage/session-store.js.map +1 -0
  94. package/dist/storage/tar-session-store.d.ts +147 -0
  95. package/dist/storage/tar-session-store.js +1044 -0
  96. package/dist/storage/tar-session-store.js.map +1 -0
  97. package/dist/storage/tree-fs.d.ts +44 -0
  98. package/dist/storage/tree-fs.js +580 -0
  99. package/dist/storage/tree-fs.js.map +1 -0
  100. package/dist/storage/tree-staging.d.ts +9 -0
  101. package/dist/storage/tree-staging.js +64 -0
  102. package/dist/storage/tree-staging.js.map +1 -0
  103. package/dist/storage/types.d.ts +77 -0
  104. package/dist/storage/types.js +3 -0
  105. package/dist/storage/types.js.map +1 -0
  106. package/dist/symlinks.d.ts +36 -0
  107. package/dist/symlinks.js +128 -0
  108. package/dist/symlinks.js.map +1 -0
  109. package/dist/tar-protocol/controls.d.ts +73 -0
  110. package/dist/tar-protocol/controls.js +291 -0
  111. package/dist/tar-protocol/controls.js.map +1 -0
  112. package/dist/tar-protocol/direct-wire.d.ts +43 -0
  113. package/dist/tar-protocol/direct-wire.js +194 -0
  114. package/dist/tar-protocol/direct-wire.js.map +1 -0
  115. package/dist/tar-protocol/extract.d.ts +18 -0
  116. package/dist/tar-protocol/extract.js +124 -0
  117. package/dist/tar-protocol/extract.js.map +1 -0
  118. package/dist/tar-protocol/hash.d.ts +10 -0
  119. package/dist/tar-protocol/hash.js +44 -0
  120. package/dist/tar-protocol/hash.js.map +1 -0
  121. package/dist/tar-protocol/lifecycle.d.ts +13 -0
  122. package/dist/tar-protocol/lifecycle.js +90 -0
  123. package/dist/tar-protocol/lifecycle.js.map +1 -0
  124. package/dist/tar-protocol/manifest.d.ts +58 -0
  125. package/dist/tar-protocol/manifest.js +312 -0
  126. package/dist/tar-protocol/manifest.js.map +1 -0
  127. package/dist/tar-protocol/tree-extract.d.ts +37 -0
  128. package/dist/tar-protocol/tree-extract.js +240 -0
  129. package/dist/tar-protocol/tree-extract.js.map +1 -0
  130. package/dist/tar-protocol/tree-manifest.d.ts +45 -0
  131. package/dist/tar-protocol/tree-manifest.js +277 -0
  132. package/dist/tar-protocol/tree-manifest.js.map +1 -0
  133. package/dist/tar-protocol/tree-path.d.ts +15 -0
  134. package/dist/tar-protocol/tree-path.js +68 -0
  135. package/dist/tar-protocol/tree-path.js.map +1 -0
  136. package/dist/tar-protocol/tree.d.ts +68 -0
  137. package/dist/tar-protocol/tree.js +269 -0
  138. package/dist/tar-protocol/tree.js.map +1 -0
  139. package/dist/tar-protocol/ustar.d.ts +36 -0
  140. package/dist/tar-protocol/ustar.js +167 -0
  141. package/dist/tar-protocol/ustar.js.map +1 -0
  142. package/dist/types.d.ts +61 -0
  143. package/dist/types.js +3 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/validation.d.ts +4 -0
  146. package/dist/validation.js +26 -0
  147. package/dist/validation.js.map +1 -0
  148. package/package.json +103 -1
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.prepareStorageRecovery = prepareStorageRecovery;
7
+ exports.recoverStorage = recoverStorage;
8
+ const b4a_1 = __importDefault(require("b4a"));
9
+ const _fs_1 = __importDefault(require("#fs"));
10
+ const errors_js_1 = require("../errors.js");
11
+ const hash_js_1 = require("../tar-protocol/hash.js");
12
+ const layout_js_1 = require("./layout.js");
13
+ const commit_store_js_1 = require("./commit-store.js");
14
+ const retention_js_1 = require("./retention.js");
15
+ function storageError(message, cause = null) {
16
+ return new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.PROTOCOL_INVALID, message, cause);
17
+ }
18
+ function isJournalName(name) {
19
+ return typeof name === 'string' && /^[0-9a-f]{64}\.json$/.test(name);
20
+ }
21
+ function transferFingerprint(id) {
22
+ return b4a_1.default.toString((0, hash_js_1.sodiumSha256)(b4a_1.default.from(id, 'hex')), 'hex').slice(0, 12);
23
+ }
24
+ function pathFingerprint(name) {
25
+ return b4a_1.default.toString((0, hash_js_1.sodiumSha256)(b4a_1.default.from(name)), 'hex').slice(0, 12);
26
+ }
27
+ function report(logger, level, message, details) {
28
+ if (!logger || typeof logger[level] !== 'function')
29
+ return;
30
+ try {
31
+ logger[level]?.(message, details);
32
+ }
33
+ catch { }
34
+ }
35
+ function emit(onEvent, payload) {
36
+ if (!onEvent)
37
+ return;
38
+ try {
39
+ onEvent(payload);
40
+ }
41
+ catch { }
42
+ }
43
+ function failureReason(error) {
44
+ if (typeof error !== 'object' || error === null || !('code' in error)) {
45
+ return errors_js_1.ERRORS.PROTOCOL_INVALID;
46
+ }
47
+ return typeof error.code === 'string' && error.code.length > 0
48
+ ? error.code
49
+ : errors_js_1.ERRORS.PROTOCOL_INVALID;
50
+ }
51
+ async function assertRecoveryLayout(layout, storage) {
52
+ for (const directory of [
53
+ layout.root,
54
+ layout.internal,
55
+ layout.staging,
56
+ layout.sessions,
57
+ layout.commits,
58
+ layout.journals,
59
+ layout.links,
60
+ layout.trash
61
+ ]) {
62
+ await (0, layout_js_1.assertSafeDirectory)(directory, storage);
63
+ }
64
+ }
65
+ async function prepareStorageRecovery({ layout, commitStore, logger = null, onEvent = null }) {
66
+ if (!layout || typeof layout !== 'object')
67
+ throw storageError('Invalid storage layout');
68
+ if (!commitStore || typeof commitStore._readJournal !== 'function') {
69
+ throw storageError('Invalid commit store');
70
+ }
71
+ if (typeof commitStore.retireCorruptAttempt !== 'function') {
72
+ throw storageError('Commit store cannot retire corrupt attempts');
73
+ }
74
+ if (onEvent !== null && typeof onEvent !== 'function') {
75
+ throw storageError('Invalid recovery event callback');
76
+ }
77
+ const storage = commitStore.storage || _fs_1.default.promises;
78
+ let retired = 0;
79
+ let activeTransfer = null;
80
+ try {
81
+ await assertRecoveryLayout(layout, storage);
82
+ const names = await (0, layout_js_1.withSafeDirectoryIdentity)(layout.journals, storage, () => storage.readdir(layout.journals));
83
+ for (const name of names.sort()) {
84
+ if (!isJournalName(name))
85
+ continue;
86
+ const id = name.slice(0, -'.json'.length);
87
+ activeTransfer = transferFingerprint(id);
88
+ try {
89
+ await commitStore._readJournal(id);
90
+ }
91
+ catch (err) {
92
+ if (!(err instanceof commit_store_js_1.CorruptJournalError))
93
+ throw err;
94
+ const result = await commitStore.retireCorruptAttempt(id);
95
+ retired++;
96
+ report(logger, 'warn', 'Retired corrupt commit attempt before session recovery', {
97
+ transfer: activeTransfer
98
+ });
99
+ emit(onEvent, {
100
+ type: 'recovery',
101
+ status: 'CORRUPT',
102
+ phase: 'classification',
103
+ transfer: activeTransfer
104
+ });
105
+ if (result.removedStaging) {
106
+ emit(onEvent, {
107
+ type: 'cleanup',
108
+ transfer: activeTransfer,
109
+ name: null,
110
+ reason: 'corrupt-journal'
111
+ });
112
+ }
113
+ }
114
+ activeTransfer = null;
115
+ }
116
+ }
117
+ catch (err) {
118
+ emit(onEvent, {
119
+ type: 'recovery',
120
+ status: 'failed',
121
+ phase: 'classification',
122
+ ...(activeTransfer ? { transfer: activeTransfer } : {}),
123
+ reason: failureReason(err)
124
+ });
125
+ throw err;
126
+ }
127
+ return retired;
128
+ }
129
+ async function recoverStorage({ layout, sessionStore, commitStore, logger = null, isAuthorized = null, onEvent = null }) {
130
+ if (!layout || typeof layout !== 'object')
131
+ throw storageError('Invalid storage layout');
132
+ if (!sessionStore || typeof sessionStore !== 'object')
133
+ throw storageError('Invalid session store');
134
+ if (!commitStore || typeof commitStore.recoverJournal !== 'function') {
135
+ throw storageError('Invalid commit store');
136
+ }
137
+ if (onEvent !== null && typeof onEvent !== 'function') {
138
+ throw storageError('Invalid recovery event callback');
139
+ }
140
+ const storage = commitStore.storage || _fs_1.default.promises;
141
+ let names;
142
+ try {
143
+ await assertRecoveryLayout(layout, storage);
144
+ names = await (0, layout_js_1.withSafeDirectoryIdentity)(layout.journals, storage, () => storage.readdir(layout.journals));
145
+ }
146
+ catch (err) {
147
+ emit(onEvent, {
148
+ type: 'recovery',
149
+ status: 'failed',
150
+ phase: 'journal',
151
+ reason: failureReason(err)
152
+ });
153
+ throw err;
154
+ }
155
+ const results = [];
156
+ for (const name of names.sort()) {
157
+ if (!isJournalName(name)) {
158
+ report(logger, 'warn', 'Ignoring unknown journal path', {
159
+ fingerprint: pathFingerprint(name)
160
+ });
161
+ continue;
162
+ }
163
+ const id = name.slice(0, -'.json'.length);
164
+ let result;
165
+ try {
166
+ result = await commitStore.recoverJournal(id, sessionStore, { isAuthorized });
167
+ }
168
+ catch (err) {
169
+ if (!(err instanceof commit_store_js_1.CorruptJournalError)) {
170
+ emit(onEvent, {
171
+ type: 'recovery',
172
+ status: 'failed',
173
+ phase: 'journal',
174
+ transfer: transferFingerprint(id),
175
+ reason: failureReason(err)
176
+ });
177
+ throw err;
178
+ }
179
+ if (typeof commitStore.retireCorruptAttempt !== 'function') {
180
+ throw storageError('Commit store cannot retire corrupt attempts');
181
+ }
182
+ let retired;
183
+ try {
184
+ retired = await commitStore.retireCorruptAttempt(id);
185
+ }
186
+ catch (retireError) {
187
+ emit(onEvent, {
188
+ type: 'recovery',
189
+ status: 'failed',
190
+ phase: 'journal',
191
+ transfer: transferFingerprint(id),
192
+ reason: failureReason(retireError)
193
+ });
194
+ throw retireError;
195
+ }
196
+ result = { status: 'CORRUPT', reason: err.message };
197
+ report(logger, 'warn', 'Skipping corrupt commit journal', {
198
+ transfer: transferFingerprint(id),
199
+ reason: err.message
200
+ });
201
+ if (retired.removedStaging) {
202
+ emit(onEvent, {
203
+ type: 'cleanup',
204
+ transfer: transferFingerprint(id),
205
+ name: null,
206
+ reason: 'corrupt-journal'
207
+ });
208
+ }
209
+ }
210
+ results.push(result);
211
+ report(logger, 'info', 'Recovered commit journal', {
212
+ transfer: transferFingerprint(id),
213
+ status: result.status
214
+ });
215
+ emit(onEvent, {
216
+ type: 'recovery',
217
+ status: result.status,
218
+ transfer: transferFingerprint(id)
219
+ });
220
+ if ((result.status === 'COMMITTED' || result.status === 'ABORTED') &&
221
+ sessionStore.initialized &&
222
+ !sessionStore.closed &&
223
+ typeof sessionStore.delete === 'function') {
224
+ await sessionStore.delete(b4a_1.default.from(id, 'hex'));
225
+ }
226
+ }
227
+ const sweptTrash = await commitStore.sweepTrash();
228
+ if (sweptTrash > 0) {
229
+ report(logger, 'warn', 'Swept managed directory trash residue', { trees: sweptTrash });
230
+ emit(onEvent, { type: 'cleanup', transfer: 'trash', name: null, reason: 'trash-residue' });
231
+ }
232
+ const retention = new retention_js_1.RetentionManager({
233
+ layout,
234
+ sessionStore,
235
+ commitStore,
236
+ storage,
237
+ isSessionActive: () => false,
238
+ logger
239
+ });
240
+ emit(onEvent, { type: 'scrub', status: 'started' });
241
+ try {
242
+ const scrub = await retention.scrubCommitted();
243
+ emit(onEvent, {
244
+ type: 'scrub',
245
+ status: 'completed',
246
+ deleted: scrub.deleted,
247
+ unknownCount: scrub.unknown.length
248
+ });
249
+ }
250
+ catch (err) {
251
+ emit(onEvent, {
252
+ type: 'scrub',
253
+ status: 'failed',
254
+ reason: failureReason(err)
255
+ });
256
+ throw err;
257
+ }
258
+ return results;
259
+ }
260
+ //# sourceMappingURL=recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../src/storage/recovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,183 @@
1
+ import { type VersionGranularity } from '../release.js';
2
+ import { type CommitRecord } from './commit-journal.js';
3
+ import type { StorageAdapter, StorageLayout } from './types.js';
4
+ declare const DEFAULT_RESUME_TTL: number;
5
+ declare const DEFAULT_CLEANUP_INTERVAL: number;
6
+ declare const MAX_CLEANUP_INTERVAL = 2147483647;
7
+ interface Session {
8
+ state: string;
9
+ }
10
+ interface SessionStore {
11
+ sessions?: Map<string, Session>;
12
+ expire(ttl: number, shouldExpire: (session: Session) => boolean): Promise<number>;
13
+ }
14
+ interface CommitStore {
15
+ storage?: StorageAdapter;
16
+ list(): Promise<CommitRecord[]>;
17
+ scrubRecords(): Promise<{
18
+ records: CommitRecord[];
19
+ deleted: number;
20
+ }>;
21
+ delete(record: CommitRecord): Promise<boolean>;
22
+ purge(record: CommitRecord, options?: {
23
+ preservePath?: boolean;
24
+ }): Promise<false | {
25
+ purged: true;
26
+ preservedPath: boolean;
27
+ }>;
28
+ }
29
+ interface Logger {
30
+ info?: (message: string, details: Record<string, unknown>) => void;
31
+ warn?: (message: string, details: Record<string, unknown>) => void;
32
+ error?: (message: string, details: Record<string, unknown>) => void;
33
+ }
34
+ interface Clock {
35
+ now(): number;
36
+ }
37
+ interface Scheduler {
38
+ setInterval(callback: () => void, interval: number): unknown;
39
+ clearInterval(timer: unknown): void;
40
+ }
41
+ type RetentionEvent = {
42
+ type: 'retention';
43
+ trigger: string;
44
+ status: 'completed';
45
+ expiredSessions: number;
46
+ scrubbed: number;
47
+ ageDeleted: number;
48
+ countDeleted: number;
49
+ versionDeleted: number;
50
+ storageDeleted: number;
51
+ } | {
52
+ type: 'retention';
53
+ trigger: string;
54
+ status: 'failed';
55
+ reason: string;
56
+ } | {
57
+ type: 'retention';
58
+ trigger: 'scheduled';
59
+ status: 'deferred';
60
+ reason: 'ACTIVE_RECEIVE';
61
+ };
62
+ type RetentionEventPayload = {
63
+ trigger: string;
64
+ status: 'completed';
65
+ expiredSessions: number;
66
+ scrubbed: number;
67
+ ageDeleted: number;
68
+ countDeleted: number;
69
+ versionDeleted: number;
70
+ storageDeleted: number;
71
+ } | {
72
+ trigger: string;
73
+ status: 'failed';
74
+ reason: string;
75
+ } | {
76
+ trigger: 'scheduled';
77
+ status: 'deferred';
78
+ reason: 'ACTIVE_RECEIVE';
79
+ };
80
+ interface RetentionRunOptions {
81
+ incomingBytes?: number;
82
+ trigger?: string;
83
+ }
84
+ interface RetentionManagerOptions {
85
+ layout: StorageLayout;
86
+ sessionStore: SessionStore;
87
+ commitStore: CommitStore;
88
+ maxAge?: number;
89
+ maxCount?: number;
90
+ maxVersions?: number;
91
+ versionGranularity?: VersionGranularity;
92
+ maxStorageBytes?: number;
93
+ resumeTtl?: number;
94
+ cleanupInterval?: number;
95
+ clock?: Clock;
96
+ storage?: StorageAdapter;
97
+ isSessionActive: (session: Session) => boolean;
98
+ hasActiveUploads?: () => boolean;
99
+ isPinned?: (record: CommitRecord) => boolean;
100
+ /**
101
+ * Reconciles managed symlinks and returns the transfer IDs pinned by a rule.
102
+ * Called once per pass with the scrubbed record set, with the root lease
103
+ * already held; it must not acquire the root lease itself.
104
+ */
105
+ reconcileLinks?: (records: CommitRecord[]) => Promise<ReadonlySet<string>>;
106
+ /**
107
+ * When link reconciliation fails, returns transfer IDs that must stay pinned
108
+ * from desired links and durable ownership records.
109
+ */
110
+ linkPinsFallback?: (records: CommitRecord[]) => Promise<ReadonlySet<string>>;
111
+ /** Names in the storage root that are server-managed symlinks, not artifacts. */
112
+ managedLinkNames?: () => ReadonlySet<string>;
113
+ logger?: Logger | null;
114
+ scheduler?: Scheduler;
115
+ onEvent?: ((event: RetentionEvent) => void) | null;
116
+ }
117
+ interface RetentionResult {
118
+ expiredSessions: number;
119
+ scrubbed: number;
120
+ ageDeleted: number;
121
+ countDeleted: number;
122
+ versionDeleted: number;
123
+ storageDeleted: number;
124
+ }
125
+ declare class RetentionManager {
126
+ layout: StorageLayout;
127
+ sessionStore: SessionStore;
128
+ commitStore: CommitStore;
129
+ maxAge: number | undefined;
130
+ maxCount: number | undefined;
131
+ maxVersions: number | undefined;
132
+ versionGranularity: VersionGranularity | undefined;
133
+ maxStorageBytes: number | undefined;
134
+ resumeTtl: number;
135
+ cleanupInterval: number;
136
+ clock: Clock;
137
+ storage: StorageAdapter;
138
+ isSessionActive: (session: Session) => boolean;
139
+ hasActiveUploads: () => boolean;
140
+ isPinned: (record: CommitRecord) => boolean;
141
+ reconcileLinks: ((records: CommitRecord[]) => Promise<ReadonlySet<string>>) | undefined;
142
+ linkPinsFallback: ((records: CommitRecord[]) => Promise<ReadonlySet<string>>) | undefined;
143
+ managedLinkNames: (() => ReadonlySet<string>) | undefined;
144
+ logger: Logger | null;
145
+ timer: unknown | null;
146
+ cleanupFailure: unknown | null;
147
+ scheduler: Scheduler;
148
+ onEvent: ((event: RetentionEvent) => void) | null;
149
+ startPromise: Promise<void> | null;
150
+ tickPromise: Promise<void> | null;
151
+ tickQueued: boolean;
152
+ lifecycle: number;
153
+ constructor({ layout, sessionStore, commitStore, maxAge, maxCount, maxVersions, versionGranularity, maxStorageBytes, resumeTtl, cleanupInterval, clock, storage, isSessionActive, hasActiveUploads, isPinned, reconcileLinks, linkPinsFallback, managedLinkNames, logger, scheduler, onEvent }: RetentionManagerOptions);
154
+ _emit(payload: RetentionEventPayload): void;
155
+ _hasActiveReceivingUpload(): boolean;
156
+ expireSessions(): Promise<number>;
157
+ scrubCommitted({ hash }?: {
158
+ hash?: boolean;
159
+ }): Promise<{
160
+ records: CommitRecord[];
161
+ deleted: number;
162
+ unknown: string[];
163
+ }>;
164
+ _deleteRecord(record: CommitRecord, reason: 'MAX_AGE' | 'MAX_COUNT' | 'MAX_VERSIONS' | 'MAX_STORAGE'): Promise<void>;
165
+ /**
166
+ * Configured mutable current records survive age and quota eviction. Their
167
+ * size still counts toward the logical total so a replacement that cannot be
168
+ * afforded fails instead of silently exceeding the limit.
169
+ */
170
+ _isPinned(record: CommitRecord): boolean;
171
+ _totalSize(records: CommitRecord[]): number;
172
+ run(options?: RetentionRunOptions): Promise<RetentionResult>;
173
+ _runUnlocked(options?: RetentionRunOptions): Promise<RetentionResult>;
174
+ _run({ incomingBytes, trigger }?: RetentionRunOptions): Promise<RetentionResult>;
175
+ afterCommit(): Promise<boolean>;
176
+ _afterCommitUnlocked(): Promise<boolean>;
177
+ start(): Promise<void>;
178
+ _scheduleTick(lifecycle: number): void;
179
+ _drainTicks(lifecycle: number): Promise<void>;
180
+ stop(): Promise<void>;
181
+ close(): Promise<void>;
182
+ }
183
+ export { RetentionManager, DEFAULT_RESUME_TTL, DEFAULT_CLEANUP_INTERVAL, MAX_CLEANUP_INTERVAL };