swarm-deploy 0.1.0 → 0.3.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 (87) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +780 -50
  3. package/RELEASING.md +2 -2
  4. package/SECURITY.md +2 -3
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +182 -25
  7. package/dist/cli.js.map +1 -1
  8. package/dist/client.d.ts +32 -27
  9. package/dist/client.js +103 -54
  10. package/dist/client.js.map +1 -1
  11. package/dist/errors.d.ts +6 -0
  12. package/dist/errors.js +6 -0
  13. package/dist/errors.js.map +1 -1
  14. package/dist/files.d.ts +13 -28
  15. package/dist/files.js +13 -78
  16. package/dist/files.js.map +1 -1
  17. package/dist/hooks-module.d.ts +9 -0
  18. package/dist/hooks-module.js +118 -0
  19. package/dist/hooks-module.js.map +1 -0
  20. package/dist/hooks.d.ts +69 -0
  21. package/dist/hooks.js +88 -0
  22. package/dist/hooks.js.map +1 -0
  23. package/dist/index.d.ts +8 -4
  24. package/dist/index.js +3 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/release.d.ts +26 -0
  27. package/dist/release.js +419 -0
  28. package/dist/release.js.map +1 -0
  29. package/dist/server.d.ts +97 -0
  30. package/dist/server.js +527 -53
  31. package/dist/server.js.map +1 -1
  32. package/dist/storage/commit-journal.d.ts +39 -2
  33. package/dist/storage/commit-journal.js +140 -2
  34. package/dist/storage/commit-journal.js.map +1 -1
  35. package/dist/storage/commit-store.d.ts +69 -8
  36. package/dist/storage/commit-store.js +374 -22
  37. package/dist/storage/commit-store.js.map +1 -1
  38. package/dist/storage/layout.js +7 -1
  39. package/dist/storage/layout.js.map +1 -1
  40. package/dist/storage/link-store.d.ts +88 -0
  41. package/dist/storage/link-store.js +448 -0
  42. package/dist/storage/link-store.js.map +1 -0
  43. package/dist/storage/recovery.d.ts +2 -1
  44. package/dist/storage/recovery.js +8 -1
  45. package/dist/storage/recovery.js.map +1 -1
  46. package/dist/storage/retention.d.ts +41 -21
  47. package/dist/storage/retention.js +162 -8
  48. package/dist/storage/retention.js.map +1 -1
  49. package/dist/storage/tar-session-store.d.ts +36 -5
  50. package/dist/storage/tar-session-store.js +283 -55
  51. package/dist/storage/tar-session-store.js.map +1 -1
  52. package/dist/storage/tree-fs.d.ts +44 -0
  53. package/dist/storage/tree-fs.js +580 -0
  54. package/dist/storage/tree-fs.js.map +1 -0
  55. package/dist/storage/tree-staging.d.ts +9 -0
  56. package/dist/storage/tree-staging.js +64 -0
  57. package/dist/storage/tree-staging.js.map +1 -0
  58. package/dist/storage/types.d.ts +15 -0
  59. package/dist/symlinks.d.ts +44 -0
  60. package/dist/symlinks.js +153 -0
  61. package/dist/symlinks.js.map +1 -0
  62. package/dist/tar-protocol/controls.d.ts +52 -0
  63. package/dist/tar-protocol/controls.js +160 -2
  64. package/dist/tar-protocol/controls.js.map +1 -1
  65. package/dist/tar-protocol/direct-wire.d.ts +8 -3
  66. package/dist/tar-protocol/direct-wire.js +14 -3
  67. package/dist/tar-protocol/direct-wire.js.map +1 -1
  68. package/dist/tar-protocol/manifest.d.ts +13 -1
  69. package/dist/tar-protocol/manifest.js +26 -1
  70. package/dist/tar-protocol/manifest.js.map +1 -1
  71. package/dist/tar-protocol/tree-extract.d.ts +37 -0
  72. package/dist/tar-protocol/tree-extract.js +240 -0
  73. package/dist/tar-protocol/tree-extract.js.map +1 -0
  74. package/dist/tar-protocol/tree-manifest.d.ts +45 -0
  75. package/dist/tar-protocol/tree-manifest.js +277 -0
  76. package/dist/tar-protocol/tree-manifest.js.map +1 -0
  77. package/dist/tar-protocol/tree-path.d.ts +15 -0
  78. package/dist/tar-protocol/tree-path.js +68 -0
  79. package/dist/tar-protocol/tree-path.js.map +1 -0
  80. package/dist/tar-protocol/tree.d.ts +68 -0
  81. package/dist/tar-protocol/tree.js +269 -0
  82. package/dist/tar-protocol/tree.js.map +1 -0
  83. package/dist/tar-protocol/ustar.d.ts +14 -0
  84. package/dist/tar-protocol/ustar.js +81 -1
  85. package/dist/tar-protocol/ustar.js.map +1 -1
  86. package/dist/types.d.ts +3 -0
  87. package/package.json +3 -1
@@ -1,5 +1,7 @@
1
+ import type { ReleaseCoordinates } from '../release.js';
1
2
  import { CorruptJournalError, COMMIT_VERSION, MAX_COMMIT_METADATA_BYTES } from './commit-journal.js';
2
- import type { AnyCommitJournal, CommitJournal, CommitRecord, FileIdentity, ReplacementJournal, ReplacementPhase } from './commit-journal.js';
3
+ import type { AnyCommitJournal, CommitJournal, CommitRecord, CommitRelease, FileIdentity, DirectoryCommitJournal, DirectoryPhase, ReplacementJournal, ReplacementPhase } from './commit-journal.js';
4
+ import { type TreePathState } from './tree-fs.js';
3
5
  import type { StorageAdapter, StorageLayout, StorageStat } from './types.js';
4
6
  interface AbortSignalLike {
5
7
  aborted: boolean;
@@ -8,9 +10,12 @@ interface CommitSession {
8
10
  id: string;
9
11
  transferId: Uint8Array;
10
12
  ownerKey: Uint8Array;
13
+ kind?: 'file' | 'directory';
11
14
  name: string;
15
+ sourceParent?: string;
12
16
  size: number;
13
17
  digest: Uint8Array;
18
+ entryCount?: number;
14
19
  /** Direct-TAR sessions carry these immutable archive fields. */
15
20
  tarSize: number;
16
21
  tarDigest: Uint8Array;
@@ -18,9 +23,13 @@ interface CommitSession {
18
23
  }
19
24
  interface CommitOffer {
20
25
  name: string;
26
+ kind?: 'file' | 'directory';
21
27
  size: number;
22
28
  digest: Uint8Array;
29
+ entryCount?: number;
23
30
  transferId: Uint8Array;
31
+ /** Matched release identity; transfer and release must agree for an idempotent result. */
32
+ release?: ReleaseCoordinates | null;
24
33
  }
25
34
  interface RetentionManager {
26
35
  run(options?: {
@@ -78,6 +87,10 @@ declare class CommitStore {
78
87
  constructor({ layout, clock, storage, logger }: CommitStoreOptions);
79
88
  _stagingPath(id: string): string;
80
89
  _tarStagingPath(id: string): string;
90
+ _treeStagingPath(id: string): string;
91
+ _trashTreePath(id: string): string;
92
+ /** The visible state of one top-level directory path, without following links. */
93
+ _rootTreeState(name: string): Promise<TreePathState>;
81
94
  _sessionPath(id: string): string;
82
95
  _journalPath(id: string): string;
83
96
  _recordPath(id: string): string;
@@ -99,8 +112,8 @@ declare class CommitStore {
99
112
  }>;
100
113
  _linkJournal(id: string, journal: AnyCommitJournal, attempt: string): Promise<void>;
101
114
  _writeJournal(record: CommitRecord, sourceStagingIdentity: FileIdentity): Promise<string>;
102
- /** A replacement always starts a fresh attempt; leftovers belong to recovery. */
103
- _writeReplacementJournal(journal: ReplacementJournal): Promise<void>;
115
+ /** A replacement or directory commit always starts a fresh attempt; leftovers belong to recovery. */
116
+ _writeFreshJournal(journal: ReplacementJournal | DirectoryCommitJournal): Promise<void>;
104
117
  /**
105
118
  * Records the boundary an attempt has already passed. The observable
106
119
  * filesystem state stays authoritative during recovery; the phase is the
@@ -120,7 +133,7 @@ declare class CommitStore {
120
133
  _abortAttempt(record: CommitRecord, expectedIdentity: FileIdentity, attemptId: string, aborted: unknown): Promise<never>;
121
134
  _removeOwnedFile(filePath: string, directory: string, identity: FileIdentity): Promise<boolean>;
122
135
  _matchesRecord(filePath: string, directory: string, record: CommitRecord, syncFirst?: boolean): Promise<boolean>;
123
- _recordFromSession(session: CommitSession): CommitRecord;
136
+ _recordFromSession(session: CommitSession, release?: CommitRelease): CommitRecord;
124
137
  inspect(name: string, offer: CommitOffer, { replaceNames }?: ReplacePolicy): Promise<{
125
138
  status: 'AVAILABLE';
126
139
  } | {
@@ -132,7 +145,7 @@ declare class CommitStore {
132
145
  } | {
133
146
  status: 'FILE_EXISTS';
134
147
  }>;
135
- _inspect(name: string, offer: CommitOffer, mutable: Set<string>): Promise<{
148
+ _inspect(name: string, offer: CommitOffer, mutable: Set<string>, release: CommitRelease | undefined): Promise<{
136
149
  status: 'AVAILABLE';
137
150
  } | {
138
151
  status: 'ALREADY_COMMITTED';
@@ -143,6 +156,14 @@ declare class CommitStore {
143
156
  } | {
144
157
  status: 'FILE_EXISTS';
145
158
  }>;
159
+ _inspectDirectory(name: string, offer: CommitOffer): Promise<{
160
+ status: 'AVAILABLE';
161
+ } | {
162
+ status: 'ALREADY_COMMITTED';
163
+ record: CommitRecord;
164
+ } | {
165
+ status: 'FILE_EXISTS';
166
+ }>;
146
167
  /** The managed record whose verified content currently owns a visible name. */
147
168
  _managedCurrent(name: string): Promise<{
148
169
  record: CommitRecord;
@@ -153,12 +174,28 @@ declare class CommitStore {
153
174
  sessionFile: StorageStat | null;
154
175
  staging: StorageStat | null;
155
176
  }>;
156
- commit(session: CommitSession, { retentionManager, signal, replaceNames }?: {
177
+ commit(session: CommitSession, { retentionManager, signal, replaceNames, release, deferPostCommitRetention }?: {
157
178
  retentionManager?: RetentionManager | null;
158
179
  signal?: AbortSignalLike | null;
159
180
  replaceNames?: Iterable<string>;
181
+ release?: ReleaseCoordinates | null;
182
+ /**
183
+ * Skips the post-commit retention pass so the caller can run it later
184
+ * (via the retention manager) once work that needs the committed files
185
+ * has finished. Pre-commit quota and age checks still run.
186
+ */
187
+ deferPostCommitRetention?: boolean;
160
188
  }): Promise<CommitRecord>;
161
- _commit(session: CommitSession, retentionManager: RetentionManager | null, signal: AbortSignalLike | null, mutable?: Set<string>): Promise<CommitRecord>;
189
+ _commit(session: CommitSession, retentionManager: RetentionManager | null, signal: AbortSignalLike | null, mutable?: Set<string>, release?: CommitRelease, deferPostCommitRetention?: boolean): Promise<CommitRecord>;
190
+ /**
191
+ * Publishes one verified staging tree by rename. Directory artifacts are
192
+ * create-only: a configured mutable name, an occupied destination, and a
193
+ * kind change are all existing-name conflicts.
194
+ */
195
+ _commitDirectory(record: CommitRecord, retentionManager: RetentionManager | null, signal: AbortSignalLike | null, mutable: Set<string>, deferPostCommitRetention?: boolean): Promise<CommitRecord>;
196
+ _setDirectoryPhase(journal: DirectoryCommitJournal, phase: DirectoryPhase): Promise<DirectoryCommitJournal>;
197
+ /** Returns a proven renamed tree to staging; a foreign destination is preserved. */
198
+ _rollbackDirectory(journal: DirectoryCommitJournal): Promise<void>;
162
199
  /**
163
200
  * Classifies a configured mutable name. Only an exact managed current record
164
201
  * whose verified content owns the visible path may be replaced; every other
@@ -177,7 +214,7 @@ declare class CommitStore {
177
214
  _replace(record: CommitRecord, stagingIdentity: FileIdentity, plan: {
178
215
  oldRecord: CommitRecord;
179
216
  finalIdentity: FileIdentity;
180
- }, retentionManager: RetentionManager | null, signal: AbortSignalLike | null): Promise<CommitRecord>;
217
+ }, retentionManager: RetentionManager | null, signal: AbortSignalLike | null, deferPostCommitRetention?: boolean): Promise<CommitRecord>;
181
218
  /**
182
219
  * Restores the exact pinned old inode at the mutable name and removes only
183
220
  * transaction-owned history, publication, and sidecar paths. A foreign
@@ -210,6 +247,16 @@ declare class CommitStore {
210
247
  _repairHistorySidecar(journal: ReplacementJournal): Promise<void>;
211
248
  _cleanupReplacementLeftovers(id: string, journal: ReplacementJournal, sessionStore: SessionStore | null): Promise<void>;
212
249
  /** Proves the verified session and staging an aborted attempt must retain. */
250
+ /**
251
+ * Converges one directory attempt. The durable sidecar is the linearization
252
+ * point: before it a proven renamed tree returns to staging, after it the
253
+ * published tree is kept and only residue is removed. A destination that
254
+ * cannot be proven is preserved and fails closed.
255
+ */
256
+ _recoverDirectoryJournal(id: string, journal: DirectoryCommitJournal, sessionStore: SessionStore, isAuthorized?: ((ownerKey: Uint8Array) => boolean) | null): Promise<{
257
+ status: 'COMMITTED' | 'RESUMABLE';
258
+ record: CommitRecord;
259
+ }>;
213
260
  _assertReplacementRetryable(id: string, journal: ReplacementJournal, sessionStore: SessionStore | null): Promise<boolean>;
214
261
  recoverJournal(id: string, sessionStore: SessionStore, { isAuthorized }?: {
215
262
  isAuthorized?: ((ownerKey: Uint8Array) => boolean) | null;
@@ -235,6 +282,20 @@ declare class CommitStore {
235
282
  * still carry the mutable name on the sidecar the caller knows as history.
236
283
  */
237
284
  _storedRecordFor(record: CommitRecord): Promise<CommitRecord | null>;
285
+ /**
286
+ * Removes proven private trash trees left by an interrupted deletion. Only a
287
+ * `<64-hex>.tree` entry is ours; anything else in the directory is left alone.
288
+ */
289
+ sweepTrash(): Promise<number>;
290
+ /**
291
+ * Removes a managed directory by renaming it into the private trash first, so
292
+ * the visible name disappears atomically, and only then removing the sidecar
293
+ * and recursively deleting the trash tree.
294
+ */
295
+ _removeManagedTree(record: CommitRecord): Promise<{
296
+ removed: boolean;
297
+ preservedPath: boolean;
298
+ }>;
238
299
  delete(record: CommitRecord): Promise<boolean>;
239
300
  purge(record: CommitRecord, { preservePath }?: {
240
301
  preservePath?: boolean;