@teambit/objects 0.0.0-00042bc99514ea12d897f81bcd0181e2b034c615

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 (121) hide show
  1. package/dist/fixtures/version-model-extended.json +48 -0
  2. package/dist/fixtures/version-model-object.json +87 -0
  3. package/dist/index.d.ts +19 -0
  4. package/dist/index.js +371 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/models/dependencies-graph.d.ts +46 -0
  7. package/dist/models/dependencies-graph.js +105 -0
  8. package/dist/models/dependencies-graph.js.map +1 -0
  9. package/dist/models/detach-heads.d.ts +25 -0
  10. package/dist/models/detach-heads.js +84 -0
  11. package/dist/models/detach-heads.js.map +1 -0
  12. package/dist/models/export-metadata.d.ts +24 -0
  13. package/dist/models/export-metadata.js +74 -0
  14. package/dist/models/export-metadata.js.map +1 -0
  15. package/dist/models/index.d.ts +10 -0
  16. package/dist/models/index.js +125 -0
  17. package/dist/models/index.js.map +1 -0
  18. package/dist/models/lane-history.d.ts +43 -0
  19. package/dist/models/lane-history.js +131 -0
  20. package/dist/models/lane-history.js.map +1 -0
  21. package/dist/models/lane-history.spec.d.ts +1 -0
  22. package/dist/models/lane-history.spec.js +46 -0
  23. package/dist/models/lane-history.spec.js.map +1 -0
  24. package/dist/models/lane.d.ts +128 -0
  25. package/dist/models/lane.js +485 -0
  26. package/dist/models/lane.js.map +1 -0
  27. package/dist/models/model-component.d.ts +338 -0
  28. package/dist/models/model-component.js +1509 -0
  29. package/dist/models/model-component.js.map +1 -0
  30. package/dist/models/model-component.spec.d.ts +1 -0
  31. package/dist/models/model-component.spec.js +71 -0
  32. package/dist/models/model-component.spec.js.map +1 -0
  33. package/dist/models/scopeMeta.d.ts +20 -0
  34. package/dist/models/scopeMeta.js +68 -0
  35. package/dist/models/scopeMeta.js.map +1 -0
  36. package/dist/models/source.d.ts +10 -0
  37. package/dist/models/source.js +42 -0
  38. package/dist/models/source.js.map +1 -0
  39. package/dist/models/symlink.d.ts +30 -0
  40. package/dist/models/symlink.js +91 -0
  41. package/dist/models/symlink.js.map +1 -0
  42. package/dist/models/version-history.d.ts +59 -0
  43. package/dist/models/version-history.js +296 -0
  44. package/dist/models/version-history.js.map +1 -0
  45. package/dist/models/version.d.ts +288 -0
  46. package/dist/models/version.js +780 -0
  47. package/dist/models/version.js.map +1 -0
  48. package/dist/models/version.spec.d.ts +1 -0
  49. package/dist/models/version.spec.js +332 -0
  50. package/dist/models/version.spec.js.map +1 -0
  51. package/dist/objects/bit-object-list.d.ts +24 -0
  52. package/dist/objects/bit-object-list.js +65 -0
  53. package/dist/objects/bit-object-list.js.map +1 -0
  54. package/dist/objects/index.d.ts +5 -0
  55. package/dist/objects/index.js +60 -0
  56. package/dist/objects/index.js.map +1 -0
  57. package/dist/objects/object-list-to-graph.d.ts +13 -0
  58. package/dist/objects/object-list-to-graph.js +93 -0
  59. package/dist/objects/object-list-to-graph.js.map +1 -0
  60. package/dist/objects/object-list.d.ts +58 -0
  61. package/dist/objects/object-list.js +389 -0
  62. package/dist/objects/object-list.js.map +1 -0
  63. package/dist/objects/object.d.ts +35 -0
  64. package/dist/objects/object.js +189 -0
  65. package/dist/objects/object.js.map +1 -0
  66. package/dist/objects/objects-readable-generator.d.ts +31 -0
  67. package/dist/objects/objects-readable-generator.js +203 -0
  68. package/dist/objects/objects-readable-generator.js.map +1 -0
  69. package/dist/objects/raw-object.d.ts +23 -0
  70. package/dist/objects/raw-object.js +145 -0
  71. package/dist/objects/raw-object.js.map +1 -0
  72. package/dist/objects/ref.d.ts +14 -0
  73. package/dist/objects/ref.js +45 -0
  74. package/dist/objects/ref.js.map +1 -0
  75. package/dist/objects/repository.d.ts +165 -0
  76. package/dist/objects/repository.js +866 -0
  77. package/dist/objects/repository.js.map +1 -0
  78. package/dist/objects/scope-index.d.ts +74 -0
  79. package/dist/objects/scope-index.js +255 -0
  80. package/dist/objects/scope-index.js.map +1 -0
  81. package/dist/objects/scope-index.spec.d.ts +1 -0
  82. package/dist/objects/scope-index.spec.js +152 -0
  83. package/dist/objects/scope-index.spec.js.map +1 -0
  84. package/dist/objects.aspect.d.ts +2 -0
  85. package/dist/objects.aspect.js +18 -0
  86. package/dist/objects.aspect.js.map +1 -0
  87. package/dist/objects.main.runtime.d.ts +7 -0
  88. package/dist/objects.main.runtime.js +36 -0
  89. package/dist/objects.main.runtime.js.map +1 -0
  90. package/dist/preview-1781548568469.js +7 -0
  91. package/fixtures/version-model-extended.json +48 -0
  92. package/fixtures/version-model-object.json +87 -0
  93. package/models/dependencies-graph.ts +120 -0
  94. package/models/detach-heads.ts +79 -0
  95. package/models/export-metadata.ts +56 -0
  96. package/models/index.ts +11 -0
  97. package/models/lane-history.spec.ts +35 -0
  98. package/models/lane-history.ts +131 -0
  99. package/models/lane.ts +400 -0
  100. package/models/model-component.spec.ts +55 -0
  101. package/models/model-component.ts +1522 -0
  102. package/models/scopeMeta.ts +58 -0
  103. package/models/source.ts +31 -0
  104. package/models/symlink.ts +66 -0
  105. package/models/version-history.ts +283 -0
  106. package/models/version.spec.ts +280 -0
  107. package/models/version.ts +821 -0
  108. package/objects/bit-object-list.ts +59 -0
  109. package/objects/index.ts +6 -0
  110. package/objects/object-list-to-graph.ts +69 -0
  111. package/objects/object-list.ts +327 -0
  112. package/objects/object.ts +152 -0
  113. package/objects/objects-readable-generator.ts +174 -0
  114. package/objects/raw-object.ts +132 -0
  115. package/objects/ref.ts +45 -0
  116. package/objects/repository.ts +780 -0
  117. package/objects/scope-index.spec.ts +95 -0
  118. package/objects/scope-index.ts +197 -0
  119. package/package.json +97 -0
  120. package/types/asset.d.ts +41 -0
  121. package/types/style.d.ts +42 -0
@@ -0,0 +1,866 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ function _fsExtra() {
8
+ const data = _interopRequireDefault(require("fs-extra"));
9
+ _fsExtra = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _uidNumber() {
15
+ const data = _interopRequireDefault(require("uid-number"));
16
+ _uidNumber = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _asyncMutex() {
22
+ const data = require("async-mutex");
23
+ _asyncMutex = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _lodash() {
29
+ const data = require("lodash");
30
+ _lodash = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _bitError() {
36
+ const data = require("@teambit/bit-error");
37
+ _bitError = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
42
+ function _componentVersion() {
43
+ const data = require("@teambit/component-version");
44
+ _componentVersion = function () {
45
+ return data;
46
+ };
47
+ return data;
48
+ }
49
+ function path() {
50
+ const data = _interopRequireWildcard(require("path"));
51
+ path = function () {
52
+ return data;
53
+ };
54
+ return data;
55
+ }
56
+ function _toolboxPromise() {
57
+ const data = require("@teambit/toolbox.promise.map-pool");
58
+ _toolboxPromise = function () {
59
+ return data;
60
+ };
61
+ return data;
62
+ }
63
+ function _legacy() {
64
+ const data = require("@teambit/legacy.constants");
65
+ _legacy = function () {
66
+ return data;
67
+ };
68
+ return data;
69
+ }
70
+ function _legacy2() {
71
+ const data = require("@teambit/legacy.logger");
72
+ _legacy2 = function () {
73
+ return data;
74
+ };
75
+ return data;
76
+ }
77
+ function _legacy3() {
78
+ const data = require("@teambit/legacy.utils");
79
+ _legacy3 = function () {
80
+ return data;
81
+ };
82
+ return data;
83
+ }
84
+ function _glob() {
85
+ const data = require("glob");
86
+ _glob = function () {
87
+ return data;
88
+ };
89
+ return data;
90
+ }
91
+ function _toolboxFs() {
92
+ const data = require("@teambit/toolbox.fs.remove-empty-dir");
93
+ _toolboxFs = function () {
94
+ return data;
95
+ };
96
+ return data;
97
+ }
98
+ function _harmonyModules() {
99
+ const data = require("@teambit/harmony.modules.concurrency");
100
+ _harmonyModules = function () {
101
+ return data;
102
+ };
103
+ return data;
104
+ }
105
+ function _legacy4() {
106
+ const data = require("@teambit/legacy.scope");
107
+ _legacy4 = function () {
108
+ return data;
109
+ };
110
+ return data;
111
+ }
112
+ function _scopeIndex() {
113
+ const data = require("./scope-index");
114
+ _scopeIndex = function () {
115
+ return data;
116
+ };
117
+ return data;
118
+ }
119
+ function _object() {
120
+ const data = _interopRequireDefault(require("./object"));
121
+ _object = function () {
122
+ return data;
123
+ };
124
+ return data;
125
+ }
126
+ function _objectList() {
127
+ const data = require("./object-list");
128
+ _objectList = function () {
129
+ return data;
130
+ };
131
+ return data;
132
+ }
133
+ function _rawObject() {
134
+ const data = _interopRequireDefault(require("./raw-object"));
135
+ _rawObject = function () {
136
+ return data;
137
+ };
138
+ return data;
139
+ }
140
+ function _ref() {
141
+ const data = _interopRequireDefault(require("./ref"));
142
+ _ref = function () {
143
+ return data;
144
+ };
145
+ return data;
146
+ }
147
+ function _harmonyModules2() {
148
+ const data = require("@teambit/harmony.modules.in-memory-cache");
149
+ _harmonyModules2 = function () {
150
+ return data;
151
+ };
152
+ return data;
153
+ }
154
+ function _models() {
155
+ const data = require("../models");
156
+ _models = function () {
157
+ return data;
158
+ };
159
+ return data;
160
+ }
161
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
162
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
163
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
164
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
165
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
166
+ const OBJECTS_BACKUP_DIR = `${_legacy().OBJECTS_DIR}.bak`;
167
+ const TRASH_DIR = 'trash';
168
+ class Repository {
169
+ constructor(scopePath, scopeJson) {
170
+ _defineProperty(this, "objects", {});
171
+ _defineProperty(this, "objectsToRemove", []);
172
+ _defineProperty(this, "scopeJson", void 0);
173
+ _defineProperty(this, "onRead", void 0);
174
+ _defineProperty(this, "onPersist", void 0);
175
+ _defineProperty(this, "scopePath", void 0);
176
+ _defineProperty(this, "scopeIndex", void 0);
177
+ _defineProperty(this, "cache", void 0);
178
+ _defineProperty(this, "remoteLanes", void 0);
179
+ _defineProperty(this, "unmergedComponents", void 0);
180
+ _defineProperty(this, "_persistMutex", void 0);
181
+ this.scopePath = scopePath;
182
+ this.scopeJson = scopeJson;
183
+ this.onRead = content => Repository.onPostObjectRead?.(content) || content;
184
+ this.onPersist = content => Repository.onPreObjectPersist?.(content) || content;
185
+ this.cache = (0, _harmonyModules2().createInMemoryCache)({
186
+ maxSize: (0, _harmonyModules2().getMaxSizeForObjects)()
187
+ });
188
+ }
189
+ get persistMutex() {
190
+ if (!this._persistMutex) {
191
+ this._persistMutex = new (_asyncMutex().Mutex)();
192
+ }
193
+ return this._persistMutex;
194
+ }
195
+ static async load({
196
+ scopePath,
197
+ scopeJson
198
+ }) {
199
+ const repository = new Repository(scopePath, scopeJson);
200
+ await repository.init();
201
+ return repository;
202
+ }
203
+ async init() {
204
+ const scopeIndex = await this.loadOptionallyCreateScopeIndex();
205
+ this.scopeIndex = scopeIndex;
206
+ this.remoteLanes = new (_legacy4().RemoteLanes)(this.scopePath);
207
+ this.unmergedComponents = await _legacy4().UnmergedComponents.load(this.scopePath);
208
+ }
209
+ static async create({
210
+ scopePath,
211
+ scopeJson
212
+ }) {
213
+ const repository = new Repository(scopePath, scopeJson);
214
+ const scopeIndex = _scopeIndex().ScopeIndex.create(scopePath);
215
+ repository.scopeIndex = scopeIndex;
216
+ repository.unmergedComponents = await _legacy4().UnmergedComponents.load(scopePath);
217
+ repository.remoteLanes = new (_legacy4().RemoteLanes)(scopePath);
218
+ return repository;
219
+ }
220
+ static reset(scopePath) {
221
+ return _scopeIndex().ScopeIndex.reset(scopePath);
222
+ }
223
+ static getPathByScopePath(scopePath) {
224
+ return path().join(scopePath, _legacy().OBJECTS_DIR);
225
+ }
226
+ async reLoadScopeIndex() {
227
+ this.scopeIndex = await this.loadOptionallyCreateScopeIndex();
228
+ }
229
+
230
+ /**
231
+ * current scope index difference with <scope_folder>/index.json content, reload it
232
+ * @deprecated use Scope aspect `watchSystemFiles` instead, it's way more efficient.
233
+ */
234
+ async reloadScopeIndexIfNeed(force = false) {
235
+ const latestScopeIndex = await this.loadOptionallyCreateScopeIndex();
236
+ if (force) {
237
+ this.scopeIndex = latestScopeIndex;
238
+ return;
239
+ }
240
+ const currentAllScopeIndexItems = this.scopeIndex.getAll();
241
+ const latestAllScopeIndexItems = latestScopeIndex.getAll();
242
+ if (currentAllScopeIndexItems.length !== latestAllScopeIndexItems.length) {
243
+ this.scopeIndex = latestScopeIndex;
244
+ return;
245
+ }
246
+ if ((0, _lodash().differenceWith)(currentAllScopeIndexItems, latestAllScopeIndexItems, _lodash().isEqual).length) {
247
+ this.scopeIndex = latestScopeIndex;
248
+ }
249
+ }
250
+ ensureDir() {
251
+ return _fsExtra().default.ensureDir(this.getPath());
252
+ }
253
+ getPath() {
254
+ return Repository.getPathByScopePath(this.scopePath);
255
+ }
256
+ getBackupPath(dirName) {
257
+ const backupPath = path().join(this.scopePath, OBJECTS_BACKUP_DIR);
258
+ return dirName ? path().join(backupPath, dirName) : backupPath;
259
+ }
260
+ getTrashDir() {
261
+ return path().join(this.scopePath, TRASH_DIR);
262
+ }
263
+ getLicense() {
264
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
265
+ return this.scopeJson.getPopulatedLicense();
266
+ }
267
+ async getScopeMetaObject() {
268
+ const license = await this.getLicense();
269
+ const object = _models().ScopeMeta.fromObject({
270
+ license,
271
+ name: this.scopeJson.name
272
+ });
273
+ return {
274
+ ref: object.hash(),
275
+ buffer: await object.compress()
276
+ };
277
+ }
278
+ objectPath(ref) {
279
+ return path().join(this.getPath(), this.hashPath(ref));
280
+ }
281
+ async has(ref) {
282
+ const objectPath = this.objectPath(ref);
283
+ return _fsExtra().default.pathExists(objectPath);
284
+ }
285
+ async hasMultiple(refs) {
286
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
287
+ const existingRefs = await (0, _toolboxPromise().pMapPool)(refs, async ref => {
288
+ const pathExists = await this.has(ref);
289
+ return pathExists ? ref : null;
290
+ }, {
291
+ concurrency
292
+ });
293
+ return (0, _lodash().compact)(existingRefs);
294
+ }
295
+ async load(ref, throws = false) {
296
+ // during tag, the updated objects are in `this.objects`.
297
+ // `this.cache` is less reliable, because if it reaches its max, then it loads from the filesystem, which may not
298
+ // be there yet (in case of "version" object), or may be out-of-date (in case of "component" object).
299
+ const inMemoryObjects = this.objects[ref.hash.toString()];
300
+ if (inMemoryObjects) return inMemoryObjects;
301
+ if (ref.hash.length < _componentVersion().HASH_SIZE) {
302
+ ref = await this.getFullRefFromShortHash(ref);
303
+ }
304
+ const cached = this.getCache(ref);
305
+ if (cached) {
306
+ return cached;
307
+ }
308
+ let fileContentsRaw;
309
+ const objectPath = this.objectPath(ref);
310
+ try {
311
+ fileContentsRaw = await _fsExtra().default.readFile(objectPath);
312
+ } catch (err) {
313
+ if (err.code !== 'ENOENT') {
314
+ _legacy2().logger.error(`Failed reading a ref file ${objectPath}. Error: ${err.message}`);
315
+ throw err;
316
+ }
317
+ _legacy2().logger.trace(`Failed finding a ref file ${objectPath}.`);
318
+ if (throws) {
319
+ // if we just `throw err` we loose the stack trace.
320
+ // see https://stackoverflow.com/questions/68022123/no-stack-in-fs-promises-readfile-enoent-error
321
+ const msg = `fatal: failed finding an object file ${objectPath} in the filesystem at ${err.path}`;
322
+ throw Object.assign(err, {
323
+ stack: new Error(msg).stack
324
+ });
325
+ }
326
+ // @ts-ignore @todo: fix! it should return BitObject | null.
327
+ return null;
328
+ }
329
+ const size = fileContentsRaw.byteLength;
330
+ const fileContents = this.onRead(fileContentsRaw);
331
+ // uncomment to debug the transformed objects by onRead
332
+ // console.log('transformedContent load', ref.toString(), BitObject.parseSync(fileContents).getType());
333
+ const parsedObject = await _object().default.parseObject(fileContents, objectPath);
334
+ const maxSizeToCache = 100 * 1024; // 100KB
335
+ if (size < maxSizeToCache) {
336
+ // don't cache big files (mainly artifacts) to prevent out-of-memory
337
+ this.setCache(parsedObject);
338
+ }
339
+ return parsedObject;
340
+ }
341
+
342
+ /**
343
+ * this is restricted to provide objects according to the given types. Otherwise, big scopes (>1GB) could crush.
344
+ * example usage: `this.list([ModelComponent, Symlink, Lane])`
345
+ */
346
+ async list(types) {
347
+ const refs = await this.listRefs();
348
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
349
+ _legacy2().logger.debug(`Repository.list, ${refs.length} refs are going to be loaded, searching for types: ${types.map(t => t.name).join(', ')}`);
350
+ const objects = [];
351
+ const loadGracefully = process.argv.includes('--never-exported');
352
+ const isTypeIncluded = obj => types.some(type => type.name === obj.constructor.name); // avoid using "obj instanceof type" for Harmony to call this function successfully
353
+ await (0, _toolboxPromise().pMapPool)(refs, async ref => {
354
+ const object = loadGracefully ? await this.loadRefDeleteIfInvalid(ref) : await this.loadRefOnlyIfType(ref, types);
355
+ if (!object) return;
356
+ if (loadGracefully && !isTypeIncluded(object)) return;
357
+ objects.push(object);
358
+ }, {
359
+ concurrency,
360
+ onCompletedChunk: completed => {
361
+ if (completed % 1000 === 0) _legacy2().logger.debug(`Repository.list, completed ${completed} out of ${refs.length}`);
362
+ }
363
+ });
364
+ return objects;
365
+ }
366
+ async loadRefDeleteIfInvalid(ref) {
367
+ try {
368
+ return await this.load(ref, true);
369
+ } catch (err) {
370
+ // this is needed temporarily to allow `bit reset --never-exported` to fix the bit-id-comp-id error.
371
+ // in a few months, we can remove this condition (around min 2024)
372
+ if (err.constructor.name === 'BitIdCompIdError' || err.constructor.name === 'MissingScope') {
373
+ _legacy2().logger.debug(`bit-id-comp-id error, moving an object to trash ${ref.toString()}`);
374
+ await this.moveOneObjectToTrash(ref);
375
+ return undefined;
376
+ }
377
+ throw err;
378
+ }
379
+ }
380
+ async loadRefOnlyIfType(ref, types) {
381
+ const objectPath = this.objectPath(ref);
382
+ const fileContentsRaw = await _fsExtra().default.readFile(objectPath);
383
+ const fileContents = this.onRead(fileContentsRaw);
384
+ const typeNames = types.map(type => type.name);
385
+ const parsedObject = await _object().default.parseObjectOnlyIfType(fileContents, typeNames, objectPath);
386
+ return parsedObject;
387
+ }
388
+ async listRefs(cwd = this.getPath()) {
389
+ const matches = await (0, _glob().glob)(path().join('*', '*'), {
390
+ cwd
391
+ });
392
+ const refs = matches.map(str => {
393
+ const hash = str.replace(path().sep, '');
394
+ if (!(0, _componentVersion().isSnap)(hash)) {
395
+ _legacy2().logger.error(`fatal: the file "${str}" is not a valid bit object path`);
396
+ return null;
397
+ }
398
+ return new (_ref().default)(hash);
399
+ });
400
+ return (0, _lodash().compact)(refs);
401
+ }
402
+ async listRefsStartWith(shortHash) {
403
+ const pathPrefix = this.hashPath(shortHash);
404
+ const matches = await (0, _glob().glob)(`${pathPrefix}*`, {
405
+ cwd: this.getPath()
406
+ });
407
+ const refs = matches.map(str => {
408
+ const hash = str.replace(path().sep, '');
409
+ if (!(0, _componentVersion().isSnap)(hash)) {
410
+ _legacy2().logger.error(`fatal: the file "${str}" is not a valid bit object path`);
411
+ return null;
412
+ }
413
+ return new (_ref().default)(hash);
414
+ });
415
+ return (0, _lodash().compact)(refs);
416
+ }
417
+ async listRawObjects() {
418
+ const refs = await this.listRefs();
419
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
420
+ return (0, _toolboxPromise().pMapPool)(refs, async ref => {
421
+ try {
422
+ const buffer = await this.loadRaw(ref);
423
+ const bitRawObject = await _rawObject().default.fromDeflatedBuffer(buffer, ref.hash);
424
+ return bitRawObject;
425
+ } catch {
426
+ _legacy2().logger.error(`Couldn't load the ref ${ref} this object is probably corrupted and should be delete`);
427
+ return null;
428
+ }
429
+ }, {
430
+ concurrency
431
+ });
432
+ }
433
+ async listObjectsFromIndex(indexType, filter) {
434
+ const hashes = filter ? this.scopeIndex.getHashesByQuery(indexType, filter) : this.scopeIndex.getHashes(indexType);
435
+ return this._getBitObjectsByHashes(hashes);
436
+ }
437
+ getHashFromIndex(indexType, filter) {
438
+ const hashes = this.scopeIndex.getHashesByQuery(indexType, filter);
439
+ if (hashes.length > 2) throw new Error('getHashFromIndex expect to get zero or one result');
440
+ return hashes.length ? hashes[0] : null;
441
+ }
442
+ async _getBitObjectsByHashes(hashes) {
443
+ const missingIndexItems = [];
444
+ const bitObjects = await Promise.all(hashes.map(async hash => {
445
+ const bitObject = await this.load(new (_ref().default)(hash));
446
+ if (!bitObject) {
447
+ const indexItem = this.scopeIndex.find(hash);
448
+ if (!indexItem) throw new Error(`_getBitObjectsByHashes failed finding ${hash}`);
449
+ missingIndexItems.push(indexItem);
450
+ return;
451
+ }
452
+ return bitObject;
453
+ }));
454
+ if (missingIndexItems.length) {
455
+ this.scopeIndex.removeMany(missingIndexItems.map(item => new (_ref().default)(item.hash)));
456
+ await this.scopeIndex.write();
457
+ const missingStringified = missingIndexItems.map(item => item.toIdentifierString());
458
+ throw new (_legacy4().OutdatedIndexJson)(missingStringified);
459
+ }
460
+ return (0, _lodash().compact)(bitObjects);
461
+ }
462
+ async loadOptionallyCreateScopeIndex() {
463
+ try {
464
+ const scopeIndex = await _scopeIndex().ScopeIndex.load(this.scopePath);
465
+ return scopeIndex;
466
+ } catch (err) {
467
+ if (err.code === 'ENOENT') {
468
+ const bitObjects = await this.list([_models().ModelComponent, _models().Lane]);
469
+ const scopeIndex = _scopeIndex().ScopeIndex.create(this.scopePath);
470
+ const added = scopeIndex.addMany(bitObjects);
471
+ if (added) await scopeIndex.write();
472
+ return scopeIndex;
473
+ }
474
+ throw err;
475
+ }
476
+ }
477
+ async loadRaw(ref) {
478
+ if (ref.hash.length < _componentVersion().HASH_SIZE) {
479
+ ref = await this.getFullRefFromShortHash(ref);
480
+ }
481
+ const raw = await _fsExtra().default.readFile(this.objectPath(ref));
482
+ // Run hook to transform content pre reading
483
+ const transformedContent = this.onRead(raw);
484
+ // uncomment to debug the transformed objects by onRead
485
+ // console.log('transformedContent loadRaw', ref.toString(), BitObject.parseSync(transformedContent).getType());
486
+ return transformedContent;
487
+ }
488
+ async getFullRefFromShortHash(ref) {
489
+ const refs = await this.listRefsStartWith(ref);
490
+ if (refs.length > 1) {
491
+ throw new Error(`found ${refs.length} objects with the same short hash ${ref.toString()}, please use longer hash`);
492
+ }
493
+ if (refs.length === 0) {
494
+ throw new Error(`failed finding an object with the short hash ${ref.toString()}`);
495
+ }
496
+ return refs[0];
497
+ }
498
+ async loadManyRaw(refs) {
499
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
500
+ const uniqRefs = (0, _lodash().uniqBy)(refs, 'hash');
501
+ return (0, _toolboxPromise().pMapPool)(uniqRefs, async ref => ({
502
+ ref,
503
+ buffer: await this.loadRaw(ref)
504
+ }), {
505
+ concurrency
506
+ });
507
+ }
508
+ async loadManyRawIgnoreMissing(refs) {
509
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
510
+ const results = await (0, _toolboxPromise().pMapPool)(refs, async ref => {
511
+ try {
512
+ const buffer = await this.loadRaw(ref);
513
+ return {
514
+ ref,
515
+ buffer
516
+ };
517
+ } catch (err) {
518
+ if (err.code === 'ENOENT') return null;
519
+ throw err;
520
+ }
521
+ }, {
522
+ concurrency
523
+ });
524
+ return (0, _lodash().compact)(results);
525
+ }
526
+ async loadRawObject(ref) {
527
+ const buffer = await this.loadRaw(ref);
528
+ const bitRawObject = await _rawObject().default.fromDeflatedBuffer(buffer, ref.hash);
529
+ return bitRawObject;
530
+ }
531
+
532
+ /**
533
+ * prefer using `this.load()` for an async version, which also writes to the cache
534
+ */
535
+ loadSync(ref, throws = true) {
536
+ try {
537
+ const objectFile = _fsExtra().default.readFileSync(this.objectPath(ref));
538
+ // Run hook to transform content pre reading
539
+ const transformedContent = this.onRead(objectFile);
540
+ return _object().default.parseSync(transformedContent);
541
+ } catch {
542
+ if (throws) {
543
+ throw new (_legacy4().HashNotFound)(ref.toString());
544
+ }
545
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
546
+ return null;
547
+ }
548
+ }
549
+ setCache(object) {
550
+ this.cache.set(object.hash().toString(), object);
551
+ return this;
552
+ }
553
+ getCache(ref) {
554
+ return this.cache.get(ref.toString());
555
+ }
556
+ removeFromCache(ref) {
557
+ this.cache.delete(ref.toString());
558
+ }
559
+ async clearCache() {
560
+ _legacy2().logger.debug('repository.clearCache');
561
+ this.cache.deleteAll();
562
+ await this.init();
563
+ }
564
+ clearObjectsFromCache() {
565
+ _legacy2().logger.debug('repository.clearObjectsFromCache');
566
+ this.cache.deleteAll();
567
+ }
568
+ backup(dirName) {
569
+ const backupDir = this.getBackupPath(dirName);
570
+ const objectsDir = this.getPath();
571
+ _legacy2().logger.debug(`making a backup of all objects from ${objectsDir} to ${backupDir}`);
572
+ _fsExtra().default.emptyDirSync(backupDir);
573
+ _fsExtra().default.copySync(objectsDir, backupDir);
574
+ }
575
+ add(object) {
576
+ // console.trace(`repository: adding object ${object?.hash().toString()}`);
577
+ if (!object) return this;
578
+ // leave the following commented log message, it is very useful for debugging but too verbose when not needed.
579
+ // logger.debug(`repository: adding object ${object.hash().toString()} which consist of the following id: ${object.id()}`);
580
+ this.objects[object.hash().toString()] = object;
581
+ this.setCache(object);
582
+ return this;
583
+ }
584
+ addMany(objects) {
585
+ if (!objects || !objects.length) return this;
586
+ objects.forEach(obj => this.add(obj));
587
+ return this;
588
+ }
589
+ removeObject(ref) {
590
+ this.objectsToRemove.push(ref);
591
+ }
592
+ removeManyObjects(refs) {
593
+ if (!refs || !refs.length) return;
594
+ refs.forEach(ref => this.removeObject(ref));
595
+ }
596
+ findMany(refs) {
597
+ return Promise.all(refs.map(ref => this.load(ref)));
598
+ }
599
+
600
+ /**
601
+ * important! use this method only for commands that are non running on an http server.
602
+ *
603
+ * it's better to remove/delete objects directly and not using the `objects` member.
604
+ * it helps to avoid multiple processes running concurrently on an http server.
605
+ *
606
+ * persist objects changes (added and removed) into the filesystem
607
+ * do not call this function multiple times in parallel, otherwise, it'll damage the index.json file.
608
+ * call this function only once after you added and removed all applicable objects.
609
+ */
610
+ async persist(validate = true) {
611
+ // do not let two requests enter this critical area, otherwise, refs/index.json/objects could
612
+ // be corrupted
613
+ _legacy2().logger.debug(`Repository.persist, going to acquire a lock`);
614
+ await this.persistMutex.runExclusive(async () => {
615
+ _legacy2().logger.debug(`Repository.persist, validate = ${validate.toString()}, a lock has been acquired`);
616
+ await this.deleteObjectsFromFS(this.objectsToRemove);
617
+ this.validateObjects(validate, Object.values(this.objects));
618
+ await this.writeObjectsToTheFS(Object.values(this.objects));
619
+ await this.writeRemoteLanes();
620
+ await this.unmergedComponents.write();
621
+ });
622
+ _legacy2().logger.debug(`Repository.persist, completed. the lock has been released`);
623
+ this.clearObjects();
624
+ if (Repository.onPostObjectsPersist) {
625
+ Repository.onPostObjectsPersist().catch(err => {
626
+ _legacy2().logger.error('fatal: onPostObjectsPersist encountered an error (this error does not stop the process)', err);
627
+ });
628
+ }
629
+ }
630
+ async writeRemoteLanes() {
631
+ await this.remoteLanes.write();
632
+ }
633
+
634
+ /**
635
+ * this is especially critical for http server, where one process lives long and serves multiple
636
+ * exports. without this, the objects get accumulated over time and being rewritten over and over
637
+ * again.
638
+ */
639
+ clearObjects() {
640
+ this.objects = {};
641
+ this.objectsToRemove = [];
642
+ }
643
+
644
+ /**
645
+ * normally, the validation step takes place just before the acutal writing of the file.
646
+ * however, this can be an issue where a component has an invalid version. the component could
647
+ * be saved before validating the version (see #1727). that's why we validate here before writing
648
+ * anything to the filesystem.
649
+ * the open question here is whether should we validate again before the actual writing or it
650
+ * should be enough to validate here?
651
+ * for now, it does validate again before saving, only to be 100% sure nothing happens in a few
652
+ * lines of code until the actual writing. however, if the performance penalty is noticeable, we
653
+ * can easily revert it by changing `bitObject.validateBeforePersist = false` line run regardless
654
+ * the `validate` argument.
655
+ */
656
+ validateObjects(validate, objects) {
657
+ objects.forEach(bitObject => {
658
+ // @ts-ignore some BitObject classes have validate() method
659
+ if (validate && bitObject.validate) {
660
+ // @ts-ignore
661
+ bitObject.validate();
662
+ }
663
+ if (!validate) {
664
+ bitObject.validateBeforePersist = false;
665
+ }
666
+ });
667
+ }
668
+ async deleteObjectsFromFS(refs) {
669
+ if (!refs.length) return;
670
+ const uniqRefs = (0, _lodash().uniqBy)(refs, 'hash');
671
+ _legacy2().logger.debug(`Repository._deleteMany: deleting ${uniqRefs.length} objects`);
672
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
673
+ await (0, _toolboxPromise().pMapPool)(uniqRefs, ref => this._deleteOne(ref), {
674
+ concurrency
675
+ });
676
+ const removed = this.scopeIndex.removeMany(uniqRefs);
677
+ if (removed) await this.scopeIndex.write();
678
+ }
679
+ async moveObjectsToDir(refs, dir) {
680
+ if (!refs.length) return;
681
+ const uniqRefs = (0, _lodash().uniqBy)(refs, 'hash');
682
+ _legacy2().logger.debug(`Repository.moveObjectsToDir: ${uniqRefs.length} objects`);
683
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
684
+ await (0, _toolboxPromise().pMapPool)(uniqRefs, ref => this.moveOneObjectToDir(ref, dir), {
685
+ concurrency
686
+ });
687
+ const removed = this.scopeIndex.removeMany(uniqRefs);
688
+ if (removed) await this.scopeIndex.write();
689
+ }
690
+ async moveObjectsToTrash(refs) {
691
+ await this.moveObjectsToDir(refs, TRASH_DIR);
692
+ }
693
+ async listTrash() {
694
+ return this.listRefs(this.getTrashDir());
695
+ }
696
+ async getFromTrash(refs) {
697
+ const objectsFromTrash = await Promise.all(refs.map(async ref => {
698
+ const trashObjPath = path().join(this.getTrashDir(), this.hashPath(ref));
699
+ let buffer;
700
+ try {
701
+ buffer = await _fsExtra().default.readFile(trashObjPath);
702
+ } catch (err) {
703
+ if (err.code === 'ENOENT') {
704
+ throw new (_bitError().BitError)(`unable to find the object ${ref.toString()} in the trash`);
705
+ }
706
+ throw err;
707
+ }
708
+ return _object().default.parseObject(buffer, trashObjPath);
709
+ }));
710
+ return objectsFromTrash;
711
+ }
712
+ async restoreFromTrash(refs) {
713
+ _legacy2().logger.debug(`Repository.restoreFromTrash: ${refs.length} objects`);
714
+ const objectsFromTrash = await this.getFromTrash(refs);
715
+ await this.writeObjectsToTheFS(objectsFromTrash);
716
+ }
717
+ async restoreFromDir(dir, overwrite = false) {
718
+ await _fsExtra().default.copy(path().join(this.scopePath, dir), this.getPath(), {
719
+ overwrite
720
+ });
721
+ }
722
+ async moveOneObjectToDir(ref, dir) {
723
+ const currentPath = this.objectPath(ref);
724
+ const absDir = path().join(this.scopePath, dir);
725
+ const fullPath = path().join(absDir, this.hashPath(ref));
726
+ await _fsExtra().default.move(currentPath, fullPath, {
727
+ overwrite: true
728
+ });
729
+ this.removeFromCache(ref);
730
+ }
731
+ async moveOneObjectToTrash(ref) {
732
+ await this.moveOneObjectToDir(ref, TRASH_DIR);
733
+ }
734
+ async deleteRecordsFromUnmergedComponents(compIds) {
735
+ this.unmergedComponents.removeMultipleComponents(compIds);
736
+ await this.unmergedComponents.write();
737
+ }
738
+
739
+ /**
740
+ * write all objects to the FS and index the components/lanes/symlink objects
741
+ */
742
+ async writeObjectsToTheFS(objects) {
743
+ const count = objects.length;
744
+ if (!count) return;
745
+ _legacy2().logger.trace(`Repository.writeObjectsToTheFS: started writing ${count} objects`);
746
+ const concurrency = (0, _harmonyModules().concurrentIOLimit)();
747
+ await (0, _toolboxPromise().pMapPool)(objects, obj => this._writeOne(obj), {
748
+ concurrency
749
+ });
750
+ _legacy2().logger.trace(`Repository.writeObjectsToTheFS: completed writing ${count} objects`);
751
+ const added = this.scopeIndex.addMany(objects);
752
+ if (added) await this.scopeIndex.write();
753
+ }
754
+
755
+ /**
756
+ * do not call this method directly. always call this.removeObject() and once done with all objects,
757
+ * call this.persist()
758
+ */
759
+ _deleteOne(ref) {
760
+ this.removeFromCache(ref);
761
+ const pathToDelete = this.objectPath(ref);
762
+ _legacy2().logger.trace(`repository._deleteOne: deleting ${pathToDelete}`);
763
+ return removeFile(pathToDelete, true);
764
+ }
765
+
766
+ /**
767
+ * always prefer this.persist() or this.writeObjectsToTheFS()
768
+ * this method doesn't write to scopeIndex. so using this method for ModelComponent or
769
+ * Symlink makes the index outdated.
770
+ */
771
+ async _writeOne(object) {
772
+ const contents = await object.compress();
773
+ const options = {};
774
+ if (this.scopeJson.groupName) options.gid = await resolveGroupId(this.scopeJson.groupName);
775
+ const hash = object.hash();
776
+ if (this.cache.has(hash.toString())) this.cache.set(hash.toString(), object); // update the cache
777
+ const objectPath = this.objectPath(hash);
778
+ _legacy2().logger.trace(`repository._writeOne: ${objectPath}`);
779
+ // Run hook to transform content pre persisting
780
+ const transformedContent = this.onPersist(contents);
781
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
782
+ return (0, _legacy3().writeFile)(objectPath, transformedContent, options);
783
+ }
784
+ async writeObjectsToPendingDir(objectList, pendingDir) {
785
+ // Refs come from client-supplied tar entry names. Validate the whole batch
786
+ // before any writes so a crafted ref can't escape pendingDir AND so we
787
+ // don't leave orphan files in pendingDir when one entry is rejected mid-batch.
788
+ // Mirrors the isSnap check listRefs already applies on the read path.
789
+ for (const object of objectList.objects) {
790
+ const ref = object.ref.toString();
791
+ if (!(0, _componentVersion().isSnap)(ref)) throw new (_bitError().BitError)(`invalid object ref: ${JSON.stringify(ref)}`);
792
+ }
793
+ const options = {};
794
+ if (this.scopeJson.groupName) options.gid = await resolveGroupId(this.scopeJson.groupName);
795
+ await Promise.all(objectList.objects.map(async object => {
796
+ const objPath = path().join(pendingDir, this.hashPath(object.ref));
797
+ await (0, _legacy3().writeFile)(objPath, object.buffer, options);
798
+ }));
799
+ }
800
+ async readObjectsFromPendingDir(pendingDir) {
801
+ const refs = await this.listRefs(pendingDir);
802
+ const objects = await Promise.all(refs.map(async ref => {
803
+ const buffer = await _fsExtra().default.readFile(path().join(pendingDir, this.hashPath(ref)));
804
+ return {
805
+ ref,
806
+ buffer
807
+ };
808
+ }));
809
+ return new (_objectList().ObjectList)(objects);
810
+ }
811
+ hashPath(ref) {
812
+ const hash = ref.toString();
813
+ return path().join(hash.slice(0, 2), hash.slice(2));
814
+ }
815
+ }
816
+ exports.default = Repository;
817
+ _defineProperty(Repository, "onPostObjectsPersist", void 0);
818
+ /**
819
+ * Hook for transforming content before objects are persisted to the filesystem.
820
+ * Note: This function cannot be async because it's used by the synchronous `loadSync` method
821
+ * which needs to maintain sync behavior for compatibility with existing code.
822
+ */
823
+ _defineProperty(Repository, "onPreObjectPersist", void 0);
824
+ /**
825
+ * Hook for transforming content after objects are read from the filesystem.
826
+ * Note: This function cannot be async because it's used by the synchronous `loadSync` method
827
+ * which needs to maintain sync behavior for compatibility with existing code.
828
+ */
829
+ _defineProperty(Repository, "onPostObjectRead", void 0);
830
+ async function removeFile(filePath, propagateDirs = false) {
831
+ try {
832
+ await _fsExtra().default.unlink(filePath);
833
+ } catch (err) {
834
+ if (err.code === 'ENOENT') {
835
+ // the file doesn't exist, that's fine, no need to do anything
836
+ return false;
837
+ }
838
+ throw err;
839
+ }
840
+ if (!propagateDirs) return true;
841
+ const {
842
+ dir
843
+ } = path().parse(filePath);
844
+ await (0, _toolboxFs().removeEmptyDir)(dir);
845
+ return true;
846
+ }
847
+ function resolveGroupId(groupName) {
848
+ return new Promise((resolve, reject) => {
849
+ (0, _uidNumber().default)(null, groupName, (err, uid, gid) => {
850
+ if (err) {
851
+ _legacy2().logger.error('resolveGroupId', err);
852
+ if (err.message.includes('EPERM')) {
853
+ return reject(new (_bitError().BitError)(`unable to resolve group id of "${groupName}", current user does not have sufficient permissions`));
854
+ }
855
+ if (err.message.includes('group id does not exist')) {
856
+ return reject(new (_bitError().BitError)(`unable to resolve group id of "${groupName}", the group does not exist`));
857
+ }
858
+ return reject(new (_bitError().BitError)(`unable to resolve group id of "${groupName}", got an error ${err.message}`));
859
+ }
860
+ // on Windows it'll always be null
861
+ return resolve(gid);
862
+ });
863
+ });
864
+ }
865
+
866
+ //# sourceMappingURL=repository.js.map