@teambit/objects 0.0.0-88ab80613e4bb3e2fcd1d088ecb7db90e0268b8d → 0.0.0-88c3189444012c6c8a62e2bab7a1bff09db29f89

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.
@@ -738,8 +738,8 @@ export default class Component extends BitObject {
738
738
  else
739
739
  throw new Error(`unable to add a new version for "${this.id()}" on main.
740
740
  this version started from an older version (${previouslyUsedVersion}), and not from the head (${head}).
741
- if this is done intentionally, please re-run with --detach-head (or --override-head if available).
742
- otherwise, please run "bit checkout head" to be up to date, then snap/tag your changes.`);
741
+ please run "bit checkout head" to be up to date, then snap/tag your changes.
742
+ if this is done intentionally, you can use --detach-head (or --override-head if available), but make sure you understand the implications as this is an experimental feature that may not be fully stable.`);
743
743
  } else {
744
744
  this.setHead(version.hash());
745
745
  this.detachedHeads.clearCurrent();
@@ -1205,6 +1205,27 @@ consider using --ignore-missing-artifacts flag if you're sure the artifacts are
1205
1205
  await this.setDivergeData(repo, undefined, undefined, workspaceId);
1206
1206
  const divergeData = this.getDivergeData();
1207
1207
  const localHashes = divergeData.snapsOnSourceOnly;
1208
+
1209
+ // When there's a detached head, divergeData only includes the detached head lineage.
1210
+ // We also need to include unexported versions from the main head lineage.
1211
+ const hasDetachedHead = this.detachedHeads && this.detachedHeads.getAllHeads().length > 0;
1212
+ if (hasDetachedHead && this.head) {
1213
+ // Calculate divergence from the main head as well
1214
+ const mainHeadDivergeData = await getDivergeData({
1215
+ repo,
1216
+ modelComponent: this,
1217
+ targetHead: (this.laneId ? this.calculatedRemoteHeadWhenOnLane : this.remoteHead) || null,
1218
+ sourceHead: this.head,
1219
+ throws: false,
1220
+ });
1221
+ // Add main head local versions that aren't already in localHashes
1222
+ for (const hash of mainHeadDivergeData.snapsOnSourceOnly) {
1223
+ if (!localHashes.find((h) => h.isEqual(hash))) {
1224
+ localHashes.push(hash);
1225
+ }
1226
+ }
1227
+ }
1228
+
1208
1229
  if (!localHashes.length) return [];
1209
1230
  return localHashes.reverse(); // reverse to get the older first
1210
1231
  }
@@ -2,6 +2,7 @@ import tarStream from 'tar-stream';
2
2
  import { pMapPool } from '@teambit/toolbox.promise.map-pool';
3
3
  import { compact } from 'lodash';
4
4
  import { Readable, PassThrough, pipeline } from 'stream';
5
+ import crypto from 'crypto';
5
6
  import BitObject from './object';
6
7
  import { BitObjectList } from './bit-object-list';
7
8
  import Ref from './ref';
@@ -52,6 +53,19 @@ export class ObjectList {
52
53
  return this.objects.length;
53
54
  }
54
55
 
56
+ /**
57
+ * Generates a SHA1 hash from all object buffers.
58
+ * Used to identify duplicate export requests during retries.
59
+ * Performance wise, it's not too bad. ~98ms for 150 components on CircleCI.
60
+ */
61
+ getSha1Hash(): string {
62
+ const hash = crypto.createHash('sha1');
63
+ for (const obj of this.objects) {
64
+ hash.update(new Uint8Array(obj.buffer));
65
+ }
66
+ return hash.digest('hex');
67
+ }
68
+
55
69
  static mergeMultipleInstances(objectLists: ObjectList[]): ObjectList {
56
70
  const objectList = new ObjectList();
57
71
  objectLists.forEach((objList) => objectList.mergeObjectList(objList));
@@ -120,7 +134,10 @@ export class ObjectList {
120
134
  const extract = tarStream.extract();
121
135
  let startData: StartFile | undefined;
122
136
  let endData: EndFile | undefined;
137
+ let entriesReceived = 0;
138
+
123
139
  extract.on('entry', (header, stream, next) => {
140
+ entriesReceived += 1;
124
141
  const data: Buffer[] = [];
125
142
  stream.on('data', (chunk) => {
126
143
  data.push(chunk);
@@ -154,24 +171,40 @@ export class ObjectList {
154
171
  });
155
172
 
156
173
  // not sure if needed
157
- extract.on('error', (err) => {
158
- passThrough.emit('error', err);
174
+ extract.on('error', (err: any) => {
175
+ logger.error(`fromTarToObjectStream tar extraction error after receiving ${entriesReceived} entries`, err);
176
+
177
+ // Enhanced error message for tar corruption with entry count
178
+ if (err.message?.includes('invalid tar header') || err.message?.includes('Invalid tar header')) {
179
+ const enhancedError = new Error(
180
+ `Invalid tar header after receiving ${entriesReceived} entries. Possible causes: 1) Server aborted request mid-stream, 2) Network corruption during transfer. Original error: ${err.message}`
181
+ );
182
+ enhancedError.stack = err.stack;
183
+ passThrough.emit('error', enhancedError);
184
+ } else {
185
+ passThrough.emit('error', err);
186
+ }
159
187
  });
160
188
 
161
189
  extract.on('finish', () => {
162
190
  if (startData?.schema === OBJECT_LIST_CURRENT_SCHEMA && !endData) {
163
191
  // wasn't able to find a better way to indicate whether the server aborted the request
164
192
  // see https://github.com/node-fetch/node-fetch/issues/1117
193
+ logger.error(
194
+ `fromTarToObjectStream, server terminated the stream unexpectedly. Start: ${JSON.stringify(startData)}, entries received: ${entriesReceived}`
195
+ );
165
196
  passThrough.emit(
166
197
  'error',
167
- new Error(`server terminated the stream unexpectedly (metadata: ${JSON.stringify(startData)})`)
198
+ new Error(
199
+ `server terminated the stream unexpectedly (metadata: ${JSON.stringify(startData)}, entries received: ${entriesReceived})`
200
+ )
168
201
  );
169
202
  }
170
203
  passThrough.end();
171
204
  });
172
205
  pipeline(packStream, extract, (err) => {
173
206
  if (err) {
174
- logger.error('fromTarToObjectStream, pipeline', err);
207
+ logger.error(`fromTarToObjectStream, pipeline error after ${entriesReceived} entries`, err);
175
208
  passThrough.emit('error', err);
176
209
  } else {
177
210
  logger.debug('fromTarToObjectStream, pipeline is completed');
@@ -187,19 +220,34 @@ export class ObjectList {
187
220
  logger.debug('fromObjectStreamToTar, start sending data', startFile);
188
221
  pack.entry({ name: TAR_STREAM_START_FILENAME }, JSON.stringify(startFile));
189
222
  let numOfFiles = 0;
223
+ let isFinalized = false;
224
+
190
225
  readable.on('data', (obj: ObjectItem) => {
191
226
  numOfFiles += 1;
192
227
  pack.entry({ name: ObjectList.combineScopeAndHash(obj) }, obj.buffer);
193
228
  });
194
229
  readable.on('end', () => {
230
+ if (isFinalized) {
231
+ logger.warn(`fromObjectStreamToTar (${scopeName}), received 'end' event but pack already finalized`);
232
+ return;
233
+ }
234
+ isFinalized = true;
195
235
  const endFile: EndFile = { numOfFiles, scopeName };
196
236
  logger.debug('fromObjectStreamToTar, finished sending data', endFile);
197
237
  pack.entry({ name: TAR_STREAM_END_FILENAME }, JSON.stringify(endFile));
198
238
  pack.finalize();
199
239
  });
200
240
  readable.on('error', (err) => {
241
+ if (isFinalized) {
242
+ logger.error(
243
+ `ObjectList.fromObjectStreamToTar, received error but pack already finalized. Files sent: ${numOfFiles}`,
244
+ err
245
+ );
246
+ return;
247
+ }
248
+ isFinalized = true;
201
249
  const errorMessage = err.message || `unexpected error (${err.name})`;
202
- logger.error(`ObjectList.fromObjectStreamToTar, streaming an error as a file`, err);
250
+ logger.error(`ObjectList.fromObjectStreamToTar, streaming an error as a file after ${numOfFiles} files`, err);
203
251
  pack.entry({ name: TAR_STREAM_ERROR_FILENAME }, errorMessage);
204
252
  pack.finalize();
205
253
  });
@@ -10,7 +10,8 @@ import { pMapPool } from '@teambit/toolbox.promise.map-pool';
10
10
  import { OBJECTS_DIR } from '@teambit/legacy.constants';
11
11
  import { logger } from '@teambit/legacy.logger';
12
12
  import type { ChownOptions, PathOsBasedAbsolute } from '@teambit/legacy.utils';
13
- import { glob, writeFile } from '@teambit/legacy.utils';
13
+ import { writeFile } from '@teambit/legacy.utils';
14
+ import { glob } from 'glob';
14
15
  import { removeEmptyDir } from '@teambit/toolbox.fs.remove-empty-dir';
15
16
  import { concurrentIOLimit } from '@teambit/harmony.modules.concurrency';
16
17
  import type { Types, ScopeJson } from '@teambit/legacy.scope';
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@teambit/objects",
3
- "version": "0.0.0-88ab80613e4bb3e2fcd1d088ecb7db90e0268b8d",
3
+ "version": "0.0.0-88c3189444012c6c8a62e2bab7a1bff09db29f89",
4
4
  "homepage": "https://bit.cloud/teambit/scope/objects",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "teambit.scope",
8
8
  "name": "objects",
9
- "version": "88ab80613e4bb3e2fcd1d088ecb7db90e0268b8d"
9
+ "version": "88c3189444012c6c8a62e2bab7a1bff09db29f89"
10
10
  },
11
11
  "dependencies": {
12
- "@pnpm/dependency-path": "1001.1.2",
13
- "@pnpm/lockfile.types": "^1002.0.1",
12
+ "@pnpm/dependency-path": "1001.1.7",
13
+ "@pnpm/lockfile.types": "^1002.0.6",
14
14
  "semver": "7.7.1",
15
15
  "lodash": "4.17.21",
16
16
  "uuid": "8.3.2",
@@ -18,45 +18,46 @@
18
18
  "p-map-series": "2.1.0",
19
19
  "tar-stream": "2.2.0",
20
20
  "fs-extra": "10.0.0",
21
+ "glob": "13.0.0",
21
22
  "uid-number": "0.0.6",
22
23
  "@teambit/harmony": "0.4.7",
24
+ "@teambit/cli": "0.0.1291",
23
25
  "@teambit/component-id": "1.2.4",
24
- "@teambit/legacy.utils": "0.0.28",
26
+ "@teambit/legacy.utils": "0.0.31",
27
+ "@teambit/harmony.modules.get-basic-log": "0.0.92",
25
28
  "@teambit/bit-error": "0.0.404",
26
29
  "@teambit/component-version": "1.0.4",
30
+ "@teambit/component.snap-distance": "0.0.92",
31
+ "@teambit/config-store": "0.0.171",
27
32
  "@teambit/lane-id": "0.0.312",
28
- "@teambit/legacy.cli.error": "0.0.30",
29
- "@teambit/legacy.constants": "0.0.19",
30
- "@teambit/legacy.logger": "0.0.30",
31
- "@teambit/toolbox.crypto.sha1": "0.0.10",
33
+ "@teambit/legacy.cli.error": "0.0.32",
34
+ "@teambit/legacy.constants": "0.0.21",
35
+ "@teambit/legacy.logger": "0.0.32",
36
+ "@teambit/legacy.scope": "0.0.91",
37
+ "@teambit/toolbox.crypto.sha1": "0.0.12",
38
+ "@teambit/component.sources": "0.0.143",
32
39
  "@teambit/legacy-bit-id": "1.1.3",
33
- "@teambit/legacy-component-log": "0.0.412",
34
- "@teambit/pkg.modules.semver-helper": "0.0.17",
40
+ "@teambit/legacy-component-log": "0.0.414",
41
+ "@teambit/legacy.consumer-component": "0.0.92",
42
+ "@teambit/legacy.consumer-config": "0.0.91",
43
+ "@teambit/legacy.extension-data": "0.0.93",
44
+ "@teambit/pkg.modules.semver-helper": "0.0.19",
35
45
  "@teambit/toolbox.array.duplications-finder": "0.0.3",
36
46
  "@teambit/graph.cleargraph": "0.0.11",
37
- "@teambit/bit.get-bit-version": "0.0.10",
38
- "@teambit/harmony.modules.concurrency": "0.0.20",
39
- "@teambit/toolbox.promise.map-pool": "0.0.9",
40
- "@teambit/harmony.modules.in-memory-cache": "0.0.23",
41
- "@teambit/toolbox.fs.remove-empty-dir": "0.0.8",
42
- "@teambit/cli": "0.0.0-7d14187e4739b4945237e8906005a2bae28bcc9a",
43
- "@teambit/harmony.modules.get-basic-log": "0.0.0-9f6db8f335ec03fc66d341a96065c96b86d0a3d8",
44
- "@teambit/component.snap-distance": "0.0.0-82e6c51cb176c70c23cfb92f1cfbd6c6b547e994",
45
- "@teambit/config-store": "0.0.0-c4e05245954af17ed0c4162a9d6cbf34c42cb443",
46
- "@teambit/legacy.scope": "0.0.0-c32668839bcf4cb6a47ba02f7cd030b23d74bf05",
47
- "@teambit/component.sources": "0.0.0-a4971b5977d69d39b1792fee1e0db9b0c0cd706a",
48
- "@teambit/legacy.consumer-component": "0.0.0-14f43d8debcbec788902a51d60380f8d3621f02a",
49
- "@teambit/legacy.consumer-config": "0.0.0-34a420f64c17159bf165b41daa827ce38b6136d3",
50
- "@teambit/legacy.extension-data": "0.0.0-6b520eb3c957d51e9a5ddb0a128f4603247ea55c",
51
- "@teambit/semantics.doc-parser": "0.0.0-26fa0bb84695ee7ced06020217b1a33c5988223c",
52
- "@teambit/graph": "0.0.0-ae654f5a8955455c443956c1e9a29f7e164e95d8"
47
+ "@teambit/bit.get-bit-version": "0.0.12",
48
+ "@teambit/semantics.doc-parser": "0.0.99",
49
+ "@teambit/harmony.modules.concurrency": "0.0.22",
50
+ "@teambit/toolbox.promise.map-pool": "0.0.11",
51
+ "@teambit/harmony.modules.in-memory-cache": "0.0.25",
52
+ "@teambit/toolbox.fs.remove-empty-dir": "0.0.10",
53
+ "@teambit/graph": "0.0.0-026390d487bea07b6774b4c396cc309bca3e39f0"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@types/semver": "7.5.8",
56
57
  "@types/lodash": "4.14.165",
57
58
  "@types/uuid": "8.3.4",
58
59
  "@types/fs-extra": "9.0.7",
59
- "@teambit/harmony.envs.core-aspect-env": "0.0.79"
60
+ "@teambit/harmony.envs.core-aspect-env": "0.1.0"
60
61
  },
61
62
  "peerDependencies": {
62
63
  "chai": "5.2.1",