@ethersphere/bee-js 12.1.0 → 12.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.
@@ -12,10 +12,20 @@ export class TarStream {
12
12
  });
13
13
  }
14
14
  beginFile(path, size) {
15
- if (path.length > 100) {
16
- throw new Error(`File name too long: ${path}`);
15
+ const {
16
+ name,
17
+ prefix,
18
+ longLink
19
+ } = splitPath(path);
20
+ if (longLink) {
21
+ const encoder = new TextEncoder();
22
+ const pathData = encoder.encode(path + '\0');
23
+ this.pieces.push(createLongLinkHeader(pathData.length));
24
+ this.pieces.push(pathData);
25
+ const padding = pathData.length % 512 === 0 ? 0 : 512 - pathData.length % 512;
26
+ if (padding > 0) this.pieces.push(new Uint8Array(padding));
17
27
  }
18
- const header = createHeader(path, size);
28
+ const header = createHeader(name, prefix, size);
19
29
  this.pieces.push(header);
20
30
  this.currentFileSize = 0;
21
31
  }
@@ -33,7 +43,55 @@ export class TarStream {
33
43
  this.pieces.push(createEndOfArchive());
34
44
  }
35
45
  }
36
- function createHeader(path, size) {
46
+ function splitPath(path) {
47
+ if (path.length <= 100) return {
48
+ name: path,
49
+ prefix: '',
50
+ longLink: false
51
+ };
52
+ for (let i = path.length - 1; i >= 0; i--) {
53
+ if (path[i] === '/') {
54
+ const name = path.substring(i + 1);
55
+ const prefix = path.substring(0, i);
56
+ if (name.length <= 100 && prefix.length <= 155) return {
57
+ name,
58
+ prefix,
59
+ longLink: false
60
+ };
61
+ }
62
+ }
63
+ // Filename itself is > 100 chars or path > 255 chars — use GNU LongLink
64
+ const lastSlash = path.lastIndexOf('/');
65
+ const truncatedName = (lastSlash >= 0 ? path.substring(lastSlash + 1) : path).slice(0, 100);
66
+ return {
67
+ name: truncatedName,
68
+ prefix: '',
69
+ longLink: true
70
+ };
71
+ }
72
+ function createLongLinkHeader(size) {
73
+ const encoder = new TextEncoder();
74
+ function writeToBuffer(str, offset, length) {
75
+ const bytes = encoder.encode(str);
76
+ header.set(bytes.slice(0, length), offset);
77
+ }
78
+ const header = new Uint8Array(512);
79
+ header.fill(0);
80
+ writeToBuffer('././@LongLink', 0, 100);
81
+ writeToBuffer('0000644\0', 100, 8);
82
+ writeToBuffer('0000000\0', 108, 8);
83
+ writeToBuffer('0000000\0', 116, 8);
84
+ writeToBuffer(size.toString(8).padStart(11, '0') + '\0', 124, 12);
85
+ writeToBuffer('00000000000\0', 136, 12);
86
+ writeToBuffer(' ', 148, 8);
87
+ writeToBuffer('L', 156, 1);
88
+ writeToBuffer('ustar\0\0', 257, 8);
89
+ let checksum = 0;
90
+ for (let i = 0; i < 512; i++) checksum += header[i];
91
+ writeToBuffer(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
92
+ return header;
93
+ }
94
+ function createHeader(name, prefix, size) {
37
95
  const encoder = new TextEncoder();
38
96
  function writeToBuffer(str, offset, length) {
39
97
  const bytes = encoder.encode(str);
@@ -43,7 +101,7 @@ function createHeader(path, size) {
43
101
  const header = new Uint8Array(512);
44
102
  header.fill(0, 0, 512);
45
103
  // File name, truncated to 100 characters if necessary
46
- writeToBuffer(path.slice(0, 100).padEnd(100, '\0'), 0, 100);
104
+ writeToBuffer(name.slice(0, 100).padEnd(100, '\0'), 0, 100);
47
105
  // File mode (octal) and null-terminated
48
106
  writeToBuffer('0000777\0', 100, 8);
49
107
  // UID and GID (octal) and null-terminated
@@ -60,11 +118,11 @@ function createHeader(path, size) {
60
118
  writeToBuffer('0', 156, 1);
61
119
  // USTAR magic and version
62
120
  writeToBuffer('ustar\0\0', 257, 8);
121
+ // UStar prefix field (offset 345, 155 bytes) — used when path > 100 but fits split
122
+ if (prefix) writeToBuffer(prefix.slice(0, 155).padEnd(155, '\0'), 345, 155);
63
123
  // Calculate checksum
64
124
  let checksum = 0;
65
- for (let i = 0; i < 512; i++) {
66
- checksum += header[i];
67
- }
125
+ for (let i = 0; i < 512; i++) checksum += header[i];
68
126
  writeToBuffer(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
69
127
  return header;
70
128
  }
@@ -5,10 +5,19 @@ export class TarStream {
5
5
  this.currentFileSize = 0;
6
6
  }
7
7
  beginFile(path, size) {
8
- if (path.length > 100) {
9
- throw new Error(`File name too long: ${path}`);
8
+ const {
9
+ name,
10
+ prefix,
11
+ longLink
12
+ } = splitPath(path);
13
+ if (longLink) {
14
+ const pathData = Buffer.from(path + '\0');
15
+ this.output.write(createLongLinkHeader(pathData.length));
16
+ this.output.write(pathData);
17
+ const padding = pathData.length % 512 === 0 ? 0 : 512 - pathData.length % 512;
18
+ if (padding > 0) this.output.write(Buffer.alloc(padding, 0));
10
19
  }
11
- const header = createHeader(path, size);
20
+ const header = createHeader(name, prefix, size);
12
21
  this.output.write(header);
13
22
  this.currentFileSize = 0;
14
23
  }
@@ -39,11 +48,53 @@ export class TarStream {
39
48
  });
40
49
  }
41
50
  }
42
- function createHeader(path, size) {
51
+ function splitPath(path) {
52
+ if (path.length <= 100) return {
53
+ name: path,
54
+ prefix: '',
55
+ longLink: false
56
+ };
57
+ for (let i = path.length - 1; i >= 0; i--) {
58
+ if (path[i] === '/') {
59
+ const name = path.substring(i + 1);
60
+ const prefix = path.substring(0, i);
61
+ if (name.length <= 100 && prefix.length <= 155) return {
62
+ name,
63
+ prefix,
64
+ longLink: false
65
+ };
66
+ }
67
+ }
68
+ // Filename itself is > 100 chars or path > 255 chars — use GNU LongLink
69
+ const lastSlash = path.lastIndexOf('/');
70
+ const truncatedName = (lastSlash >= 0 ? path.substring(lastSlash + 1) : path).slice(0, 100);
71
+ return {
72
+ name: truncatedName,
73
+ prefix: '',
74
+ longLink: true
75
+ };
76
+ }
77
+ function createLongLinkHeader(size) {
78
+ const header = Buffer.alloc(512, 0);
79
+ header.write('././@LongLink', 0, 100);
80
+ header.write('0000644\0', 100, 8);
81
+ header.write('0000000\0', 108, 8);
82
+ header.write('0000000\0', 116, 8);
83
+ header.write(size.toString(8).padStart(11, '0') + '\0', 124, 12);
84
+ header.write('00000000000\0', 136, 12);
85
+ header.write(' ', 148, 8);
86
+ header.write('L', 156, 1);
87
+ header.write('ustar\0\0', 257, 8);
88
+ let checksum = 0;
89
+ for (let i = 0; i < 512; i++) checksum += header[i];
90
+ header.write(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
91
+ return header;
92
+ }
93
+ function createHeader(name, prefix, size) {
43
94
  // Initialize header with zeros
44
95
  const header = Buffer.alloc(512, 0);
45
96
  // File name, truncated to 100 characters if necessary
46
- header.write(path.slice(0, 100).padEnd(100, '\0'), 0, 100);
97
+ header.write(name.slice(0, 100).padEnd(100, '\0'), 0, 100);
47
98
  // File mode (octal) and null-terminated
48
99
  header.write('0000777\0', 100, 8);
49
100
  // UID and GID (octal) and null-terminated
@@ -60,11 +111,11 @@ function createHeader(path, size) {
60
111
  header.write('0', 156, 1);
61
112
  // USTAR magic and version
62
113
  header.write('ustar\0\0', 257, 8);
114
+ // UStar prefix field (offset 345, 155 bytes) — used when path > 100 but fits split
115
+ if (prefix) header.write(prefix.slice(0, 155).padEnd(155, '\0'), 345, 155);
63
116
  // Calculate checksum
64
117
  let checksum = 0;
65
- for (let i = 0; i < 512; i++) {
66
- checksum += header[i];
67
- }
118
+ for (let i = 0; i < 512; i++) checksum += header[i];
68
119
  header.write(checksum.toString(8).padStart(6, '0') + '\0 ', 148, 8);
69
120
  return header;
70
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethersphere/bee-js",
3
- "version": "12.1.0",
3
+ "version": "12.2.0",
4
4
  "description": "Javascript client for Bee",
5
5
  "keywords": [
6
6
  "bee",
@@ -44,7 +44,9 @@
44
44
  "./dist/cjs/utils/chunk-stream.js": "./dist/cjs/utils/chunk-stream.browser.js",
45
45
  "./dist/mjs/utils/chunk-stream.js": "./dist/mjs/utils/chunk-stream.browser.js",
46
46
  "./dist/cjs/utils/collection.node.js": "./dist/cjs/utils/collection.browser.js",
47
- "./dist/mjs/utils/collection.node.js": "./dist/mjs/utils/collection.browser.js"
47
+ "./dist/mjs/utils/collection.node.js": "./dist/mjs/utils/collection.browser.js",
48
+ "./dist/cjs/utils/tar.js": "./dist/cjs/utils/tar.browser.js",
49
+ "./dist/mjs/utils/tar.js": "./dist/mjs/utils/tar.browser.js"
48
50
  },
49
51
  "files": [
50
52
  "dist"
@@ -56,6 +58,7 @@
56
58
  "build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types",
57
59
  "build:browser": "webpack --progress",
58
60
  "test": "TS_NODE_PROJECT=tsconfig.test.json jest --runInBand --verbose --forceExit",
61
+ "test:browser": "TS_NODE_PROJECT=tsconfig.test.json jest --config jest.browser.config.js --runInBand --verbose --forceExit",
59
62
  "check": "tsc --project tsconfig.test.json",
60
63
  "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" && prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
61
64
  "depcheck": "depcheck ."
@@ -93,6 +96,7 @@
93
96
  "eslint-plugin-unused-imports": "^2.0.0",
94
97
  "husky": "^8.0.1",
95
98
  "jest": "^30.2.0",
99
+ "jest-environment-jsdom": "^30.4.1",
96
100
  "prettier": "^2.6.2",
97
101
  "rimraf": "^3.0.2",
98
102
  "terser-webpack-plugin": "^5.3.1",