swarm-deploy 0.0.0 → 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.
- package/CHANGELOG.md +32 -0
- package/LICENSE.md +201 -0
- package/NOTICE.md +13 -0
- package/README.md +652 -0
- package/RELEASING.md +71 -0
- package/SECURITY.md +41 -0
- package/dist/abort.d.ts +16 -0
- package/dist/abort.js +52 -0
- package/dist/abort.js.map +1 -0
- package/dist/allowlist.d.ts +2 -0
- package/dist/allowlist.js +21 -0
- package/dist/allowlist.js.map +1 -0
- package/dist/bin/swarm-deploy.d.ts +2 -0
- package/dist/bin/swarm-deploy.js +41 -0
- package/dist/bin/swarm-deploy.js.map +1 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.js +694 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +121 -0
- package/dist/client.js +285 -0
- package/dist/client.js.map +1 -0
- package/dist/direct-dht.d.ts +81 -0
- package/dist/direct-dht.js +254 -0
- package/dist/direct-dht.js.map +1 -0
- package/dist/error-code.d.ts +15 -0
- package/dist/error-code.js +30 -0
- package/dist/error-code.js.map +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/events-node.d.ts +2 -0
- package/dist/events-node.js +7 -0
- package/dist/events-node.js.map +1 -0
- package/dist/files.d.ts +47 -0
- package/dist/files.js +150 -0
- package/dist/files.js.map +1 -0
- package/dist/fs-node.d.ts +2 -0
- package/dist/fs-node.js +7 -0
- package/dist/fs-node.js.map +1 -0
- package/dist/identity.d.ts +7 -0
- package/dist/identity.js +50 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/os-node.d.ts +2 -0
- package/dist/os-node.js +7 -0
- package/dist/os-node.js.map +1 -0
- package/dist/path-node.d.ts +2 -0
- package/dist/path-node.js +7 -0
- package/dist/path-node.js.map +1 -0
- package/dist/process-node.d.ts +2 -0
- package/dist/process-node.js +7 -0
- package/dist/process-node.js.map +1 -0
- package/dist/server.d.ts +153 -0
- package/dist/server.js +576 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/atomic-file.d.ts +15 -0
- package/dist/storage/atomic-file.js +172 -0
- package/dist/storage/atomic-file.js.map +1 -0
- package/dist/storage/commit-journal.d.ts +83 -0
- package/dist/storage/commit-journal.js +279 -0
- package/dist/storage/commit-journal.js.map +1 -0
- package/dist/storage/commit-store.d.ts +246 -0
- package/dist/storage/commit-store.js +1339 -0
- package/dist/storage/commit-store.js.map +1 -0
- package/dist/storage/layout.d.ts +16 -0
- package/dist/storage/layout.js +403 -0
- package/dist/storage/layout.js.map +1 -0
- package/dist/storage/recovery.d.ts +99 -0
- package/dist/storage/recovery.js +253 -0
- package/dist/storage/recovery.js.map +1 -0
- package/dist/storage/retention.d.ts +163 -0
- package/dist/storage/retention.js +465 -0
- package/dist/storage/retention.js.map +1 -0
- package/dist/storage/root-coordinator.d.ts +7 -0
- package/dist/storage/root-coordinator.js +27 -0
- package/dist/storage/root-coordinator.js.map +1 -0
- package/dist/storage/session-store.d.ts +2 -0
- package/dist/storage/session-store.js +7 -0
- package/dist/storage/session-store.js.map +1 -0
- package/dist/storage/tar-session-store.d.ts +116 -0
- package/dist/storage/tar-session-store.js +816 -0
- package/dist/storage/tar-session-store.js.map +1 -0
- package/dist/storage/types.d.ts +62 -0
- package/dist/storage/types.js +3 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/tar-protocol/controls.d.ts +48 -0
- package/dist/tar-protocol/controls.js +185 -0
- package/dist/tar-protocol/controls.js.map +1 -0
- package/dist/tar-protocol/direct-wire.d.ts +43 -0
- package/dist/tar-protocol/direct-wire.js +194 -0
- package/dist/tar-protocol/direct-wire.js.map +1 -0
- package/dist/tar-protocol/extract.d.ts +18 -0
- package/dist/tar-protocol/extract.js +124 -0
- package/dist/tar-protocol/extract.js.map +1 -0
- package/dist/tar-protocol/hash.d.ts +10 -0
- package/dist/tar-protocol/hash.js +44 -0
- package/dist/tar-protocol/hash.js.map +1 -0
- package/dist/tar-protocol/lifecycle.d.ts +13 -0
- package/dist/tar-protocol/lifecycle.js +90 -0
- package/dist/tar-protocol/lifecycle.js.map +1 -0
- package/dist/tar-protocol/manifest.d.ts +46 -0
- package/dist/tar-protocol/manifest.js +287 -0
- package/dist/tar-protocol/manifest.js.map +1 -0
- package/dist/tar-protocol/ustar.d.ts +22 -0
- package/dist/tar-protocol/ustar.js +87 -0
- package/dist/tar-protocol/ustar.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +4 -0
- package/dist/validation.js +26 -0
- package/dist/validation.js.map +1 -0
- package/package.json +101 -1
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
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 { StorageAdapter, StorageLayout, StorageStat } from './types.js';
|
|
4
|
+
interface AbortSignalLike {
|
|
5
|
+
aborted: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface CommitSession {
|
|
8
|
+
id: string;
|
|
9
|
+
transferId: Uint8Array;
|
|
10
|
+
ownerKey: Uint8Array;
|
|
11
|
+
name: string;
|
|
12
|
+
size: number;
|
|
13
|
+
digest: Uint8Array;
|
|
14
|
+
/** Direct-TAR sessions carry these immutable archive fields. */
|
|
15
|
+
tarSize: number;
|
|
16
|
+
tarDigest: Uint8Array;
|
|
17
|
+
state: string;
|
|
18
|
+
}
|
|
19
|
+
interface CommitOffer {
|
|
20
|
+
name: string;
|
|
21
|
+
size: number;
|
|
22
|
+
digest: Uint8Array;
|
|
23
|
+
transferId: Uint8Array;
|
|
24
|
+
}
|
|
25
|
+
interface RetentionManager {
|
|
26
|
+
run(options?: {
|
|
27
|
+
trigger?: string;
|
|
28
|
+
}): Promise<unknown>;
|
|
29
|
+
afterCommit(): Promise<unknown>;
|
|
30
|
+
_runUnlocked(options: {
|
|
31
|
+
incomingBytes: number;
|
|
32
|
+
trigger: 'commit';
|
|
33
|
+
}): Promise<unknown>;
|
|
34
|
+
_afterCommitUnlocked(): Promise<unknown>;
|
|
35
|
+
}
|
|
36
|
+
interface SessionStore {
|
|
37
|
+
readVerified(transferId: Uint8Array): Promise<CommitSession>;
|
|
38
|
+
sessions?: Map<string, CommitSession>;
|
|
39
|
+
}
|
|
40
|
+
interface Logger {
|
|
41
|
+
warn?: (message: string, details: Record<string, unknown>) => void;
|
|
42
|
+
}
|
|
43
|
+
interface CommitStoreOptions {
|
|
44
|
+
layout: StorageLayout;
|
|
45
|
+
clock?: {
|
|
46
|
+
now(): number;
|
|
47
|
+
};
|
|
48
|
+
storage?: StorageAdapter;
|
|
49
|
+
logger?: Logger | null;
|
|
50
|
+
}
|
|
51
|
+
interface ReplacePolicy {
|
|
52
|
+
replaceNames?: Iterable<string>;
|
|
53
|
+
}
|
|
54
|
+
/** The visible state of one top-level path, without following symlinks. */
|
|
55
|
+
interface RootPathState {
|
|
56
|
+
present: boolean;
|
|
57
|
+
/** Set only for a regular file; an unmanaged non-regular path leaves it null. */
|
|
58
|
+
stat: StorageStat | null;
|
|
59
|
+
}
|
|
60
|
+
type ReplacementPlan = {
|
|
61
|
+
mode: 'create';
|
|
62
|
+
} | {
|
|
63
|
+
mode: 'idempotent';
|
|
64
|
+
record: CommitRecord;
|
|
65
|
+
} | {
|
|
66
|
+
mode: 'replace';
|
|
67
|
+
oldRecord: CommitRecord;
|
|
68
|
+
finalIdentity: FileIdentity;
|
|
69
|
+
};
|
|
70
|
+
declare class CommitStore {
|
|
71
|
+
layout: StorageLayout;
|
|
72
|
+
clock: {
|
|
73
|
+
now(): number;
|
|
74
|
+
};
|
|
75
|
+
storage: StorageAdapter;
|
|
76
|
+
logger: Logger | null;
|
|
77
|
+
journalAttempts: Map<string, string>;
|
|
78
|
+
constructor({ layout, clock, storage, logger }: CommitStoreOptions);
|
|
79
|
+
_stagingPath(id: string): string;
|
|
80
|
+
_tarStagingPath(id: string): string;
|
|
81
|
+
_sessionPath(id: string): string;
|
|
82
|
+
_journalPath(id: string): string;
|
|
83
|
+
_recordPath(id: string): string;
|
|
84
|
+
_finalPath(name: string): string;
|
|
85
|
+
_publicationPath(name: string): string;
|
|
86
|
+
_assertLayout(): Promise<void>;
|
|
87
|
+
/** Inspects one top-level path without following or trusting symlinks. */
|
|
88
|
+
_rootPathState(name: string): Promise<RootPathState>;
|
|
89
|
+
_syncRoot(): Promise<void>;
|
|
90
|
+
_safeFileOrAbsent(filePath: string, directory: string): Promise<StorageStat | null>;
|
|
91
|
+
_readRecordOrAbsent(recordPath: string): Promise<CommitRecord | null>;
|
|
92
|
+
_writeRecord(record: CommitRecord): Promise<boolean>;
|
|
93
|
+
/** Persists a sidecar transition over its own previous durable content. */
|
|
94
|
+
_rewriteRecord(record: CommitRecord): Promise<void>;
|
|
95
|
+
_removeFile(filePath: string, directory: string): Promise<boolean>;
|
|
96
|
+
_removeManagedFinalOrAbsent(record: CommitRecord): Promise<{
|
|
97
|
+
removed: boolean;
|
|
98
|
+
preservedPath: boolean;
|
|
99
|
+
}>;
|
|
100
|
+
_linkJournal(id: string, journal: AnyCommitJournal, attempt: string): Promise<void>;
|
|
101
|
+
_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>;
|
|
104
|
+
/**
|
|
105
|
+
* Records the boundary an attempt has already passed. The observable
|
|
106
|
+
* filesystem state stays authoritative during recovery; the phase is the
|
|
107
|
+
* durable intent trail the journal must carry.
|
|
108
|
+
*/
|
|
109
|
+
_setReplacementPhase(journal: ReplacementJournal, phase: ReplacementPhase): Promise<ReplacementJournal>;
|
|
110
|
+
retireCorruptJournal(id: string): Promise<boolean>;
|
|
111
|
+
retireCorruptAttempt(id: string): Promise<{
|
|
112
|
+
retired: boolean;
|
|
113
|
+
removedStaging: boolean;
|
|
114
|
+
}>;
|
|
115
|
+
_discardJournal(id: string, expectedAttemptId: string): Promise<boolean>;
|
|
116
|
+
_markAttemptAborting(id: string, expectedAttemptId: string): Promise<AnyCommitJournal>;
|
|
117
|
+
_linkStaging(stagingPath: string, finalPath: string, expectedIdentity: FileIdentity, signal: AbortSignalLike | null): Promise<void>;
|
|
118
|
+
_removeAbortedPublication(record: CommitRecord, expectedIdentity: FileIdentity): Promise<void>;
|
|
119
|
+
_reportCleanupPending(record: CommitRecord, err: unknown): void;
|
|
120
|
+
_abortAttempt(record: CommitRecord, expectedIdentity: FileIdentity, attemptId: string, aborted: unknown): Promise<never>;
|
|
121
|
+
_removeOwnedFile(filePath: string, directory: string, identity: FileIdentity): Promise<boolean>;
|
|
122
|
+
_matchesRecord(filePath: string, directory: string, record: CommitRecord, syncFirst?: boolean): Promise<boolean>;
|
|
123
|
+
_recordFromSession(session: CommitSession): CommitRecord;
|
|
124
|
+
inspect(name: string, offer: CommitOffer, { replaceNames }?: ReplacePolicy): Promise<{
|
|
125
|
+
status: 'AVAILABLE';
|
|
126
|
+
} | {
|
|
127
|
+
status: 'ALREADY_COMMITTED';
|
|
128
|
+
record: CommitRecord;
|
|
129
|
+
} | {
|
|
130
|
+
status: 'REPLACEABLE';
|
|
131
|
+
record: CommitRecord;
|
|
132
|
+
} | {
|
|
133
|
+
status: 'FILE_EXISTS';
|
|
134
|
+
}>;
|
|
135
|
+
_inspect(name: string, offer: CommitOffer, mutable: Set<string>): Promise<{
|
|
136
|
+
status: 'AVAILABLE';
|
|
137
|
+
} | {
|
|
138
|
+
status: 'ALREADY_COMMITTED';
|
|
139
|
+
record: CommitRecord;
|
|
140
|
+
} | {
|
|
141
|
+
status: 'REPLACEABLE';
|
|
142
|
+
record: CommitRecord;
|
|
143
|
+
} | {
|
|
144
|
+
status: 'FILE_EXISTS';
|
|
145
|
+
}>;
|
|
146
|
+
/** The managed record whose verified content currently owns a visible name. */
|
|
147
|
+
_managedCurrent(name: string): Promise<{
|
|
148
|
+
record: CommitRecord;
|
|
149
|
+
identity: FileIdentity;
|
|
150
|
+
} | null>;
|
|
151
|
+
_assertSessionMatchesRecord(session: CommitSession, record: CommitRecord, message: string): void;
|
|
152
|
+
_validateAttemptLeftovers(id: string, journal: CommitJournal, sessionStore: SessionStore): Promise<{
|
|
153
|
+
sessionFile: StorageStat | null;
|
|
154
|
+
staging: StorageStat | null;
|
|
155
|
+
}>;
|
|
156
|
+
commit(session: CommitSession, { retentionManager, signal, replaceNames }?: {
|
|
157
|
+
retentionManager?: RetentionManager | null;
|
|
158
|
+
signal?: AbortSignalLike | null;
|
|
159
|
+
replaceNames?: Iterable<string>;
|
|
160
|
+
}): Promise<CommitRecord>;
|
|
161
|
+
_commit(session: CommitSession, retentionManager: RetentionManager | null, signal: AbortSignalLike | null, mutable?: Set<string>): Promise<CommitRecord>;
|
|
162
|
+
/**
|
|
163
|
+
* Classifies a configured mutable name. Only an exact managed current record
|
|
164
|
+
* whose verified content owns the visible path may be replaced; every other
|
|
165
|
+
* occupied path is an existing-name conflict.
|
|
166
|
+
*/
|
|
167
|
+
_planReplacement(record: CommitRecord): Promise<ReplacementPlan>;
|
|
168
|
+
/**
|
|
169
|
+
* A repeated A→B→A sequence reuses a transfer ID that already owns a history
|
|
170
|
+
* artifact of identical content. The superseded duplicate is dropped inside
|
|
171
|
+
* the transaction so the returning content becomes the only copy.
|
|
172
|
+
*/
|
|
173
|
+
_dedupHistory(record: CommitRecord): Promise<{
|
|
174
|
+
name: string;
|
|
175
|
+
identity: FileIdentity | null;
|
|
176
|
+
} | null>;
|
|
177
|
+
_replace(record: CommitRecord, stagingIdentity: FileIdentity, plan: {
|
|
178
|
+
oldRecord: CommitRecord;
|
|
179
|
+
finalIdentity: FileIdentity;
|
|
180
|
+
}, retentionManager: RetentionManager | null, signal: AbortSignalLike | null): Promise<CommitRecord>;
|
|
181
|
+
/**
|
|
182
|
+
* Restores the exact pinned old inode at the mutable name and removes only
|
|
183
|
+
* transaction-owned history, publication, and sidecar paths. A foreign
|
|
184
|
+
* destination is never overwritten or removed.
|
|
185
|
+
*/
|
|
186
|
+
_rollbackReplacement(journal: ReplacementJournal): Promise<void>;
|
|
187
|
+
_readJournal(id: string): Promise<AnyCommitJournal | null>;
|
|
188
|
+
/** Every parsable v2 journal, used to explain transient duplicate names. */
|
|
189
|
+
_pendingReplacements(): Promise<ReplacementJournal[]>;
|
|
190
|
+
/**
|
|
191
|
+
* Finalizes or rolls back one v2 attempt. The durable new current sidecar is
|
|
192
|
+
* the linearization point: before it the old content is restored, after it
|
|
193
|
+
* the new content is preserved while history metadata and cleanup converge.
|
|
194
|
+
*/
|
|
195
|
+
_convergeReplacement(id: string, journal: ReplacementJournal, sessionStore: SessionStore | null, { forceAbort }?: {
|
|
196
|
+
forceAbort?: boolean;
|
|
197
|
+
}): Promise<{
|
|
198
|
+
status: 'COMMITTED' | 'ABORTED' | 'RESUMABLE';
|
|
199
|
+
record: CommitRecord;
|
|
200
|
+
}>;
|
|
201
|
+
/**
|
|
202
|
+
* Startup recovery for one v2 attempt. Revocation of a still-live session
|
|
203
|
+
* aborts the attempt first so the same rollback path converges.
|
|
204
|
+
*/
|
|
205
|
+
_recoverReplacementJournal(id: string, journal: ReplacementJournal, sessionStore: SessionStore, isAuthorized: ((ownerKey: Uint8Array) => boolean) | null): Promise<{
|
|
206
|
+
status: 'COMMITTED' | 'ABORTED' | 'RESUMABLE';
|
|
207
|
+
record: CommitRecord;
|
|
208
|
+
}>;
|
|
209
|
+
/** Writes or drops the history sidecar for an already linearized attempt. */
|
|
210
|
+
_repairHistorySidecar(journal: ReplacementJournal): Promise<void>;
|
|
211
|
+
_cleanupReplacementLeftovers(id: string, journal: ReplacementJournal, sessionStore: SessionStore | null): Promise<void>;
|
|
212
|
+
/** Proves the verified session and staging an aborted attempt must retain. */
|
|
213
|
+
_assertReplacementRetryable(id: string, journal: ReplacementJournal, sessionStore: SessionStore | null): Promise<boolean>;
|
|
214
|
+
recoverJournal(id: string, sessionStore: SessionStore, { isAuthorized }?: {
|
|
215
|
+
isAuthorized?: ((ownerKey: Uint8Array) => boolean) | null;
|
|
216
|
+
}): Promise<{
|
|
217
|
+
status: 'MISSING' | 'FILE_EXISTS' | 'COMMITTED' | 'ABORTED' | 'RESUMABLE';
|
|
218
|
+
record?: CommitRecord;
|
|
219
|
+
}>;
|
|
220
|
+
_scanRecords(): Promise<CommitRecord[]>;
|
|
221
|
+
scrubRecords(): Promise<{
|
|
222
|
+
records: CommitRecord[];
|
|
223
|
+
deleted: number;
|
|
224
|
+
}>;
|
|
225
|
+
_resolveRecords(records: CommitRecord[]): Promise<CommitRecord[]>;
|
|
226
|
+
/**
|
|
227
|
+
* A replacement makes the old sidecar the history record after its new
|
|
228
|
+
* current sidecar is durable, so one name can briefly carry two records.
|
|
229
|
+
* Only a journal-owned duplicate is tolerated, reported at the history name
|
|
230
|
+
* that recovery will persist; anything else fails closed.
|
|
231
|
+
*/
|
|
232
|
+
list(): Promise<CommitRecord[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Locates the durable record a caller is deleting. A pending replacement may
|
|
235
|
+
* still carry the mutable name on the sidecar the caller knows as history.
|
|
236
|
+
*/
|
|
237
|
+
_storedRecordFor(record: CommitRecord): Promise<CommitRecord | null>;
|
|
238
|
+
delete(record: CommitRecord): Promise<boolean>;
|
|
239
|
+
purge(record: CommitRecord, { preservePath }?: {
|
|
240
|
+
preservePath?: boolean;
|
|
241
|
+
}): Promise<false | {
|
|
242
|
+
purged: true;
|
|
243
|
+
preservedPath: boolean;
|
|
244
|
+
}>;
|
|
245
|
+
}
|
|
246
|
+
export { CommitStore, CorruptJournalError, COMMIT_VERSION, MAX_COMMIT_METADATA_BYTES };
|