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.
- package/CHANGELOG.md +76 -0
- package/LICENSE.md +201 -0
- package/NOTICE.md +13 -0
- package/README.md +1283 -0
- package/RELEASING.md +71 -0
- package/SECURITY.md +40 -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 +27 -0
- package/dist/cli.js +751 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +111 -0
- package/dist/client.js +276 -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 +31 -0
- package/dist/errors.js +37 -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 +32 -0
- package/dist/files.js +85 -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/hooks-module.d.ts +9 -0
- package/dist/hooks-module.js +118 -0
- package/dist/hooks-module.js.map +1 -0
- package/dist/hooks.d.ts +69 -0
- package/dist/hooks.js +88 -0
- package/dist/hooks.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 +12 -0
- package/dist/index.js +21 -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/release.d.ts +26 -0
- package/dist/release.js +419 -0
- package/dist/release.js.map +1 -0
- package/dist/server.d.ts +239 -0
- package/dist/server.js +928 -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 +120 -0
- package/dist/storage/commit-journal.js +417 -0
- package/dist/storage/commit-journal.js.map +1 -0
- package/dist/storage/commit-store.d.ts +307 -0
- package/dist/storage/commit-store.js +1691 -0
- package/dist/storage/commit-store.js.map +1 -0
- package/dist/storage/layout.d.ts +16 -0
- package/dist/storage/layout.js +409 -0
- package/dist/storage/layout.js.map +1 -0
- package/dist/storage/link-store.d.ts +70 -0
- package/dist/storage/link-store.js +363 -0
- package/dist/storage/link-store.js.map +1 -0
- package/dist/storage/recovery.d.ts +100 -0
- package/dist/storage/recovery.js +260 -0
- package/dist/storage/recovery.js.map +1 -0
- package/dist/storage/retention.d.ts +183 -0
- package/dist/storage/retention.js +619 -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 +147 -0
- package/dist/storage/tar-session-store.js +1044 -0
- package/dist/storage/tar-session-store.js.map +1 -0
- package/dist/storage/tree-fs.d.ts +44 -0
- package/dist/storage/tree-fs.js +580 -0
- package/dist/storage/tree-fs.js.map +1 -0
- package/dist/storage/tree-staging.d.ts +9 -0
- package/dist/storage/tree-staging.js +64 -0
- package/dist/storage/tree-staging.js.map +1 -0
- package/dist/storage/types.d.ts +77 -0
- package/dist/storage/types.js +3 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/symlinks.d.ts +36 -0
- package/dist/symlinks.js +128 -0
- package/dist/symlinks.js.map +1 -0
- package/dist/tar-protocol/controls.d.ts +73 -0
- package/dist/tar-protocol/controls.js +291 -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 +58 -0
- package/dist/tar-protocol/manifest.js +312 -0
- package/dist/tar-protocol/manifest.js.map +1 -0
- package/dist/tar-protocol/tree-extract.d.ts +37 -0
- package/dist/tar-protocol/tree-extract.js +240 -0
- package/dist/tar-protocol/tree-extract.js.map +1 -0
- package/dist/tar-protocol/tree-manifest.d.ts +45 -0
- package/dist/tar-protocol/tree-manifest.js +277 -0
- package/dist/tar-protocol/tree-manifest.js.map +1 -0
- package/dist/tar-protocol/tree-path.d.ts +15 -0
- package/dist/tar-protocol/tree-path.js +68 -0
- package/dist/tar-protocol/tree-path.js.map +1 -0
- package/dist/tar-protocol/tree.d.ts +68 -0
- package/dist/tar-protocol/tree.js +269 -0
- package/dist/tar-protocol/tree.js.map +1 -0
- package/dist/tar-protocol/ustar.d.ts +36 -0
- package/dist/tar-protocol/ustar.js +167 -0
- package/dist/tar-protocol/ustar.js.map +1 -0
- package/dist/types.d.ts +61 -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 +103 -1
|
@@ -0,0 +1,124 @@
|
|
|
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.validateAndExtractTar = validateAndExtractTar;
|
|
7
|
+
const b4a_1 = __importDefault(require("b4a"));
|
|
8
|
+
const abort_js_1 = require("../abort.js");
|
|
9
|
+
const errors_js_1 = require("../errors.js");
|
|
10
|
+
const controls_js_1 = require("./controls.js");
|
|
11
|
+
const hash_js_1 = require("./hash.js");
|
|
12
|
+
const ustar_js_1 = require("./ustar.js");
|
|
13
|
+
const EMPTY = b4a_1.default.alloc(0);
|
|
14
|
+
function invalid(message, cause = null) {
|
|
15
|
+
return new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.PROTOCOL_INVALID, message, cause);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validates a deterministic single-entry TAR stream and yields its payload.
|
|
19
|
+
*
|
|
20
|
+
* Because every byte outside the payload is fixed by the offered metadata, the
|
|
21
|
+
* whole stream can be checked by comparison: the header must equal the one
|
|
22
|
+
* canonical block, and everything after the payload must be zero. A stream that
|
|
23
|
+
* survives that is, by construction, one entry whose bytes are exactly
|
|
24
|
+
* `tar[512 .. 512 + fileSize)`, so no TAR parser is needed to extract it.
|
|
25
|
+
*/
|
|
26
|
+
class CanonicalTarReader {
|
|
27
|
+
metadata;
|
|
28
|
+
header;
|
|
29
|
+
position = 0;
|
|
30
|
+
constructor(metadata) {
|
|
31
|
+
this.metadata = metadata;
|
|
32
|
+
this.header = (0, ustar_js_1.canonicalUstarHeader)(metadata.name, metadata.fileSize);
|
|
33
|
+
}
|
|
34
|
+
/** Checks `chunk` in place and returns the slice of it that is file payload. */
|
|
35
|
+
write(chunk) {
|
|
36
|
+
const base = this.position;
|
|
37
|
+
if (base > this.metadata.tarSize - chunk.byteLength) {
|
|
38
|
+
throw invalid('Trailing TAR payload');
|
|
39
|
+
}
|
|
40
|
+
const contentEnd = ustar_js_1.TAR_BLOCK_BYTES + this.metadata.fileSize;
|
|
41
|
+
for (let index = 0; index < chunk.byteLength; index++) {
|
|
42
|
+
const absolute = base + index;
|
|
43
|
+
if (absolute < ustar_js_1.TAR_BLOCK_BYTES) {
|
|
44
|
+
if (chunk[index] !== this.header[absolute])
|
|
45
|
+
throw invalid('Noncanonical TAR header');
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (absolute >= contentEnd && chunk[index] !== 0) {
|
|
49
|
+
throw invalid('Nonzero TAR padding or terminator');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
this.position = base + chunk.byteLength;
|
|
53
|
+
// Payload occupies absolute offsets [512, 512 + fileSize); clip the chunk
|
|
54
|
+
// to that window and translate back to chunk-relative indices.
|
|
55
|
+
const start = Math.max(base, ustar_js_1.TAR_BLOCK_BYTES);
|
|
56
|
+
const end = Math.min(this.position, contentEnd);
|
|
57
|
+
return end <= start ? EMPTY : chunk.subarray(start - base, end - base);
|
|
58
|
+
}
|
|
59
|
+
finish() {
|
|
60
|
+
if (this.position !== this.metadata.tarSize)
|
|
61
|
+
throw invalid('Truncated TAR payload');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function assertStaging(staging) {
|
|
65
|
+
if (!staging ||
|
|
66
|
+
typeof staging !== 'object' ||
|
|
67
|
+
typeof staging.writeTar !== 'function' ||
|
|
68
|
+
typeof staging.writeFile !== 'function' ||
|
|
69
|
+
typeof staging.complete !== 'function' ||
|
|
70
|
+
typeof staging.abort !== 'function') {
|
|
71
|
+
throw invalid('Invalid TAR extraction staging interface');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function validateAndExtractTar(source, offeredMetadata, staging, { signal = null } = {}) {
|
|
75
|
+
assertStaging(staging);
|
|
76
|
+
const metadata = (0, controls_js_1.decodeMetadataRecord)((0, controls_js_1.encodeMetadataRecord)(offeredMetadata));
|
|
77
|
+
const expectedFileDigest = b4a_1.default.from(metadata.fileSha256, 'hex');
|
|
78
|
+
const expectedTarDigest = b4a_1.default.from(metadata.tarSha256, 'hex');
|
|
79
|
+
const reader = new CanonicalTarReader(metadata);
|
|
80
|
+
const fileHash = new hash_js_1.SodiumSha256();
|
|
81
|
+
const tarHash = new hash_js_1.SodiumSha256();
|
|
82
|
+
let extractedBytes = 0;
|
|
83
|
+
try {
|
|
84
|
+
(0, abort_js_1.throwIfAborted)(signal);
|
|
85
|
+
for await (const value of source) {
|
|
86
|
+
(0, abort_js_1.throwIfAborted)(signal);
|
|
87
|
+
if (!b4a_1.default.isBuffer(value))
|
|
88
|
+
throw invalid('Invalid TAR source bytes');
|
|
89
|
+
const payload = reader.write(value);
|
|
90
|
+
tarHash.update(value);
|
|
91
|
+
await staging.writeTar(value);
|
|
92
|
+
if (payload.byteLength > 0) {
|
|
93
|
+
extractedBytes += payload.byteLength;
|
|
94
|
+
fileHash.update(payload);
|
|
95
|
+
await staging.writeFile(payload);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
reader.finish();
|
|
99
|
+
if (extractedBytes !== metadata.fileSize)
|
|
100
|
+
throw invalid('Extracted file size mismatch');
|
|
101
|
+
const fileSha256 = fileHash.digest();
|
|
102
|
+
const tarSha256 = tarHash.digest();
|
|
103
|
+
if (!(0, hash_js_1.digestMatches)(fileSha256, expectedFileDigest)) {
|
|
104
|
+
throw new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.CHECKSUM_MISMATCH, 'Extracted file digest mismatch');
|
|
105
|
+
}
|
|
106
|
+
if (!(0, hash_js_1.digestMatches)(tarSha256, expectedTarDigest)) {
|
|
107
|
+
throw new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.CHECKSUM_MISMATCH, 'TAR digest mismatch');
|
|
108
|
+
}
|
|
109
|
+
await staging.complete();
|
|
110
|
+
return {
|
|
111
|
+
fileSize: extractedBytes,
|
|
112
|
+
fileSha256,
|
|
113
|
+
tarSize: metadata.tarSize,
|
|
114
|
+
tarSha256
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
await Promise.resolve(staging.abort(error)).catch(() => { });
|
|
119
|
+
if (error instanceof errors_js_1.SwarmDeployError)
|
|
120
|
+
throw error;
|
|
121
|
+
throw invalid('TAR extraction failed', error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/tar-protocol/extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const SHA256_BYTES = 32;
|
|
2
|
+
export declare class SodiumSha256 {
|
|
3
|
+
private readonly state;
|
|
4
|
+
private finished;
|
|
5
|
+
constructor();
|
|
6
|
+
update(bytes: Uint8Array): this;
|
|
7
|
+
digest(): Buffer;
|
|
8
|
+
}
|
|
9
|
+
export declare function sodiumSha256(bytes: Uint8Array): Buffer;
|
|
10
|
+
export declare function digestMatches(actual: Uint8Array, expected: Uint8Array): boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
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.SodiumSha256 = exports.SHA256_BYTES = void 0;
|
|
7
|
+
exports.sodiumSha256 = sodiumSha256;
|
|
8
|
+
exports.digestMatches = digestMatches;
|
|
9
|
+
const b4a_1 = __importDefault(require("b4a"));
|
|
10
|
+
const sodium_native_1 = __importDefault(require("sodium-native"));
|
|
11
|
+
exports.SHA256_BYTES = 32;
|
|
12
|
+
class SodiumSha256 {
|
|
13
|
+
state = b4a_1.default.alloc(sodium_native_1.default.crypto_hash_sha256_STATEBYTES);
|
|
14
|
+
finished = false;
|
|
15
|
+
constructor() {
|
|
16
|
+
sodium_native_1.default.crypto_hash_sha256_init(this.state);
|
|
17
|
+
}
|
|
18
|
+
update(bytes) {
|
|
19
|
+
if (this.finished)
|
|
20
|
+
throw new Error('SHA-256 state is finalized');
|
|
21
|
+
sodium_native_1.default.crypto_hash_sha256_update(this.state, bytes);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
digest() {
|
|
25
|
+
if (this.finished)
|
|
26
|
+
throw new Error('SHA-256 state is finalized');
|
|
27
|
+
this.finished = true;
|
|
28
|
+
const digest = b4a_1.default.alloc(exports.SHA256_BYTES);
|
|
29
|
+
sodium_native_1.default.crypto_hash_sha256_final(this.state, digest);
|
|
30
|
+
return digest;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.SodiumSha256 = SodiumSha256;
|
|
34
|
+
function sodiumSha256(bytes) {
|
|
35
|
+
const digest = b4a_1.default.alloc(exports.SHA256_BYTES);
|
|
36
|
+
sodium_native_1.default.crypto_hash_sha256(digest, bytes);
|
|
37
|
+
return digest;
|
|
38
|
+
}
|
|
39
|
+
function digestMatches(actual, expected) {
|
|
40
|
+
return (actual.byteLength === exports.SHA256_BYTES &&
|
|
41
|
+
expected.byteLength === exports.SHA256_BYTES &&
|
|
42
|
+
sodium_native_1.default.sodium_memcmp(actual, expected));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/tar-protocol/hash.ts"],"names":[],"mappings":";;;;;;;;AAAA,8CAAqB;AACrB,kEAAkC;AAErB,QAAA,YAAY,GAAG,EAAE,CAAA;AAE9B;IACmB,KAAK,GAAG,aAAG,CAAC,KAAK,CAAC,uBAAM,CAAC,6BAA6B,CAAC,CAAA;IAChE,QAAQ,GAAG,KAAK,CAAA;IAExB;QACE,uBAAM,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5C,CAAC;IAED,MAAM,CAAC,KAAiB;QACtB,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;QAChE,uBAAM,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QACnD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;QAChE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,MAAM,MAAM,GAAG,aAAG,CAAC,KAAK,CAAC,QAAA,YAAY,CAAC,CAAA;QACtC,uBAAM,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACnD,OAAO,MAAM,CAAA;IACf,CAAC;CACF;;AAED,sBAA6B,KAAiB;IAC5C,MAAM,MAAM,GAAG,aAAG,CAAC,KAAK,CAAC,QAAA,YAAY,CAAC,CAAA;IACtC,uBAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACxC,OAAO,MAAM,CAAA;AACf,CAAC;AAED,uBAA8B,MAAkB,EAAE,QAAoB;IACpE,OAAO,CACL,MAAM,CAAC,UAAU,KAAK,QAAA,YAAY;QAClC,QAAQ,CAAC,UAAU,KAAK,QAAA,YAAY;QACpC,uBAAM,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CACvC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AbortSignalLike } from '../abort.js';
|
|
2
|
+
export interface ProtocolWritable {
|
|
3
|
+
write(bytes: Uint8Array): boolean;
|
|
4
|
+
on(event: string, listener: (...args: unknown[]) => void): this;
|
|
5
|
+
removeListener(event: string, listener: (...args: unknown[]) => void): this;
|
|
6
|
+
destroy(error?: unknown): void;
|
|
7
|
+
}
|
|
8
|
+
export interface ProtocolWriteOptions {
|
|
9
|
+
signal?: AbortSignalLike | null;
|
|
10
|
+
timeout?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function writeProtocolBytes(stream: ProtocolWritable, bytes: Uint8Array, { signal, timeout }?: ProtocolWriteOptions): Promise<void>;
|
|
13
|
+
export declare function writeFramedProtocolRecord(stream: ProtocolWritable, record: Uint8Array, options?: ProtocolWriteOptions): Promise<void>;
|
|
@@ -0,0 +1,90 @@
|
|
|
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.writeProtocolBytes = writeProtocolBytes;
|
|
7
|
+
exports.writeFramedProtocolRecord = writeFramedProtocolRecord;
|
|
8
|
+
const b4a_1 = __importDefault(require("b4a"));
|
|
9
|
+
const abort_js_1 = require("../abort.js");
|
|
10
|
+
const errors_js_1 = require("../errors.js");
|
|
11
|
+
const controls_js_1 = require("./controls.js");
|
|
12
|
+
const DEFAULT_WRITE_TIMEOUT = 60_000;
|
|
13
|
+
const MAX_TIMEOUT = 0x7fffffff;
|
|
14
|
+
function invalid(message, cause = null) {
|
|
15
|
+
return new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.PROTOCOL_INVALID, message, cause);
|
|
16
|
+
}
|
|
17
|
+
function closedBeforeDrain() {
|
|
18
|
+
const error = invalid('Protocol stream closed before drain');
|
|
19
|
+
error.transport = true;
|
|
20
|
+
return error;
|
|
21
|
+
}
|
|
22
|
+
function assertTimeout(timeout) {
|
|
23
|
+
if (!Number.isSafeInteger(timeout) || timeout <= 0 || timeout > MAX_TIMEOUT) {
|
|
24
|
+
throw invalid('Invalid protocol write timeout');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function writeProtocolBytes(stream, bytes, { signal = null, timeout = DEFAULT_WRITE_TIMEOUT } = {}) {
|
|
28
|
+
if (!stream || typeof stream.write !== 'function' || typeof stream.destroy !== 'function') {
|
|
29
|
+
return Promise.reject(invalid('Invalid protocol stream'));
|
|
30
|
+
}
|
|
31
|
+
if (!b4a_1.default.isBuffer(bytes))
|
|
32
|
+
return Promise.reject(invalid('Invalid protocol bytes'));
|
|
33
|
+
try {
|
|
34
|
+
assertTimeout(timeout);
|
|
35
|
+
if (signal?.aborted)
|
|
36
|
+
throw (0, abort_js_1.abortError)();
|
|
37
|
+
if (stream.destroyed === true) {
|
|
38
|
+
throw closedBeforeDrain();
|
|
39
|
+
}
|
|
40
|
+
if (stream.write(bytes))
|
|
41
|
+
return Promise.resolve();
|
|
42
|
+
if (stream.destroyed === true) {
|
|
43
|
+
throw closedBeforeDrain();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
return Promise.reject(error);
|
|
48
|
+
}
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
let settled = false;
|
|
51
|
+
let removeAbort = () => { };
|
|
52
|
+
const timer = setTimeout(() => finish(new errors_js_1.SwarmDeployError(errors_js_1.ERRORS.UPLOAD_IDLE_TIMEOUT, 'Protocol write drain timed out')), timeout);
|
|
53
|
+
const cleanup = () => {
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
removeAbort();
|
|
56
|
+
stream.removeListener('drain', onDrain);
|
|
57
|
+
stream.removeListener('error', onError);
|
|
58
|
+
stream.removeListener('close', onClose);
|
|
59
|
+
};
|
|
60
|
+
const finish = (error = null) => {
|
|
61
|
+
if (settled)
|
|
62
|
+
return;
|
|
63
|
+
settled = true;
|
|
64
|
+
cleanup();
|
|
65
|
+
if (error === null) {
|
|
66
|
+
resolve();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
stream.destroy(error);
|
|
71
|
+
}
|
|
72
|
+
catch { }
|
|
73
|
+
reject(error);
|
|
74
|
+
};
|
|
75
|
+
const onDrain = () => finish();
|
|
76
|
+
const onError = (error) => finish(error instanceof Error ? error : invalid('Protocol stream failed', error));
|
|
77
|
+
const onClose = () => finish(closedBeforeDrain());
|
|
78
|
+
stream.on('drain', onDrain);
|
|
79
|
+
stream.on('error', onError);
|
|
80
|
+
stream.on('close', onClose);
|
|
81
|
+
removeAbort = (0, abort_js_1.onAbort)(signal, () => finish((0, abort_js_1.abortError)()));
|
|
82
|
+
if (stream.destroyed === true) {
|
|
83
|
+
finish(closedBeforeDrain());
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function writeFramedProtocolRecord(stream, record, options = {}) {
|
|
88
|
+
return writeProtocolBytes(stream, (0, controls_js_1.encodeControlFrame)(record), options);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/tar-protocol/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type AbortSignalLike } from '../abort.js';
|
|
2
|
+
import { type MetadataRecord } from './controls.js';
|
|
3
|
+
export { deterministicTarSize, TAR_BLOCK_BYTES, TAR_GID, TAR_GNAME, TAR_MODE, TAR_MTIME_MS, TAR_UID, TAR_UNAME } from './ustar.js';
|
|
4
|
+
export declare const TAR_TRANSFER_DOMAIN = "swarm-deploy/direct-tar/v1";
|
|
5
|
+
export interface TarSourceIdentity {
|
|
6
|
+
dev: number | bigint;
|
|
7
|
+
ino: number | bigint;
|
|
8
|
+
size: number;
|
|
9
|
+
mtimeMs: number;
|
|
10
|
+
}
|
|
11
|
+
export interface TarManifest {
|
|
12
|
+
path: string;
|
|
13
|
+
name: string;
|
|
14
|
+
sourceParent?: string;
|
|
15
|
+
fileSize: number;
|
|
16
|
+
fileSha256: Buffer;
|
|
17
|
+
tarSize: number;
|
|
18
|
+
tarSha256: Buffer;
|
|
19
|
+
transferId: Buffer;
|
|
20
|
+
source: TarSourceIdentity;
|
|
21
|
+
}
|
|
22
|
+
export interface TarOperationOptions {
|
|
23
|
+
signal?: AbortSignalLike | null;
|
|
24
|
+
}
|
|
25
|
+
export interface TarManifestOptions extends TarOperationOptions {
|
|
26
|
+
/** Set to `false` to keep the legacy identity that names no source parent. */
|
|
27
|
+
includeSourceParent?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface TarResumeOptions extends TarOperationOptions {
|
|
30
|
+
expectedPrefixSha256?: Uint8Array | null;
|
|
31
|
+
}
|
|
32
|
+
export type TarResumeResult = {
|
|
33
|
+
status: 'MATCH';
|
|
34
|
+
prefixSha256: Buffer;
|
|
35
|
+
bytesSent: number;
|
|
36
|
+
} | {
|
|
37
|
+
status: 'RESET_REQUIRED';
|
|
38
|
+
prefixSha256: Buffer;
|
|
39
|
+
bytesSent: 0;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The immediate parent directory name, only when it is a valid wire component.
|
|
43
|
+
* Unsafe or absent parents (spaces, dotfiles, filesystem root, overlong) are
|
|
44
|
+
* omitted so the upload keeps the legacy authenticated identity.
|
|
45
|
+
*/
|
|
46
|
+
export declare function deriveSourceParent(filePath: string): string | undefined;
|
|
47
|
+
export declare function computeTarTransferId(clientPublicKey: Uint8Array, immutable: {
|
|
48
|
+
name: string;
|
|
49
|
+
sourceParent?: string;
|
|
50
|
+
fileSize: number;
|
|
51
|
+
fileSha256: Uint8Array;
|
|
52
|
+
tarSize: number;
|
|
53
|
+
tarSha256: Uint8Array;
|
|
54
|
+
}): Buffer;
|
|
55
|
+
export declare function buildTarManifest(filePath: string, clientPublicKey: Uint8Array, { signal, includeSourceParent }?: TarManifestOptions): Promise<TarManifest>;
|
|
56
|
+
export declare function regenerateTarSuffix(manifest: TarManifest, offset: number, write: (chunk: Buffer) => void | Promise<void>, { signal, expectedPrefixSha256 }?: TarResumeOptions): Promise<TarResumeResult>;
|
|
57
|
+
export declare function metadataFromManifest(manifest: TarManifest, reset?: boolean): MetadataRecord;
|
|
58
|
+
export declare function assertMetadataTransferId(clientPublicKey: Uint8Array, offeredMetadata: MetadataRecord): void;
|