isomorphic-jj 1.4.2 → 1.7.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.
@@ -15,16 +15,16 @@ import crypto from 'crypto';
15
15
 
16
16
  /**
17
17
  * Backend adapter for isomorphic-git
18
- *
18
+ *
19
19
  * @class IsomorphicGitBackend
20
20
  */
21
21
  export class IsomorphicGitBackend {
22
22
  /**
23
23
  * Create isomorphic-git backend
24
- *
24
+ *
25
25
  * @param {Object} options - Backend options
26
- * @param {Object} options.fs - Filesystem implementation (Node fs or LightningFS)
27
- * @param {Object} [options.http] - HTTP client for network operations
26
+ * @param {any} options.fs - Filesystem implementation (Node fs or LightningFS)
27
+ * @param {any} [options.http] - HTTP client for network operations
28
28
  * @param {string} options.dir - Repository directory path
29
29
  */
30
30
  constructor({ fs, http, dir }) {
@@ -36,11 +36,9 @@ export class IsomorphicGitBackend {
36
36
  );
37
37
  }
38
38
  if (!dir) {
39
- throw new JJError(
40
- 'INVALID_BACKEND_CONFIG',
41
- 'Repository directory (dir) is required',
42
- { suggestion: 'Provide dir option with repository path' }
43
- );
39
+ throw new JJError('INVALID_BACKEND_CONFIG', 'Repository directory (dir) is required', {
40
+ suggestion: 'Provide dir option with repository path',
41
+ });
44
42
  }
45
43
 
46
44
  this.fs = fs;
@@ -65,21 +63,19 @@ export class IsomorphicGitBackend {
65
63
 
66
64
  // Create .jj/repo structure for jj CLI compatibility
67
65
  await this._createJJRepoStructure();
68
-
69
66
  } catch (error) {
70
- throw new JJError(
71
- 'INIT_FAILED',
72
- `Failed to initialize Git repository: ${error.message}`,
73
- { dir: this.dir, originalError: error }
74
- );
67
+ throw new JJError('INIT_FAILED', `Failed to initialize Git repository: ${error.message}`, {
68
+ dir: this.dir,
69
+ originalError: error,
70
+ });
75
71
  }
76
72
  }
77
73
 
78
74
  /**
79
75
  * Read Git object from storage
80
- *
76
+ *
81
77
  * @param {string} oid - Git object SHA-1 hash (40-char hex)
82
- * @returns {Promise<{type: string, data: Uint8Array}>} Git object
78
+ * @returns {Promise<{type: string, data: any}>} Git object
83
79
  */
84
80
  async getObject(oid) {
85
81
  try {
@@ -91,23 +87,21 @@ export class IsomorphicGitBackend {
91
87
  return { type, data: object };
92
88
  } catch (error) {
93
89
  if (error.code === 'NotFoundError' || error.code === 'ReadObjectFail') {
94
- throw new JJError(
95
- 'NOT_FOUND',
96
- `Git object ${oid} not found`,
97
- { oid, suggestion: 'Ensure object exists in repository' }
98
- );
90
+ throw new JJError('NOT_FOUND', `Git object ${oid} not found`, {
91
+ oid,
92
+ suggestion: 'Ensure object exists in repository',
93
+ });
99
94
  }
100
- throw new JJError(
101
- 'STORAGE_READ_FAILED',
102
- `Failed to read Git object: ${error.message}`,
103
- { oid, originalError: error }
104
- );
95
+ throw new JJError('STORAGE_READ_FAILED', `Failed to read Git object: ${error.message}`, {
96
+ oid,
97
+ originalError: error,
98
+ });
105
99
  }
106
100
  }
107
101
 
108
102
  /**
109
103
  * Write Git object to storage
110
- *
104
+ *
111
105
  * @param {string} type - Object type ('blob', 'tree', 'commit', 'tag')
112
106
  * @param {Uint8Array} data - Object data
113
107
  * @returns {Promise<string>} Object SHA-1 hash
@@ -117,22 +111,22 @@ export class IsomorphicGitBackend {
117
111
  const oid = await git.writeObject({
118
112
  fs: this.fs,
119
113
  dir: this.dir,
120
- type,
114
+ type: /** @type {any} */ (type),
121
115
  object: data,
122
116
  });
123
117
  return oid;
124
118
  } catch (error) {
125
- throw new JJError(
126
- 'STORAGE_WRITE_FAILED',
127
- `Failed to write Git object: ${error.message}`,
128
- { type, dataSize: data.length, originalError: error }
129
- );
119
+ throw new JJError('STORAGE_WRITE_FAILED', `Failed to write Git object: ${error.message}`, {
120
+ type,
121
+ dataSize: data.length,
122
+ originalError: error,
123
+ });
130
124
  }
131
125
  }
132
126
 
133
127
  /**
134
128
  * Read Git reference
135
- *
129
+ *
136
130
  * @param {string} name - Full ref name (e.g., 'refs/heads/main')
137
131
  * @returns {Promise<string|null>} Commit SHA-1 or null if not found
138
132
  */
@@ -148,17 +142,16 @@ export class IsomorphicGitBackend {
148
142
  if (error.code === 'NotFoundError' || error.code === 'ResolveRefError') {
149
143
  return null;
150
144
  }
151
- throw new JJError(
152
- 'STORAGE_READ_FAILED',
153
- `Failed to read Git ref: ${error.message}`,
154
- { ref: name, originalError: error }
155
- );
145
+ throw new JJError('STORAGE_READ_FAILED', `Failed to read Git ref: ${error.message}`, {
146
+ ref: name,
147
+ originalError: error,
148
+ });
156
149
  }
157
150
  }
158
151
 
159
152
  /**
160
153
  * Create, update, or delete Git reference
161
- *
154
+ *
162
155
  * @param {string} name - Full ref name
163
156
  * @param {string|null} oid - Commit SHA-1 or null to delete
164
157
  * @returns {Promise<void>}
@@ -187,17 +180,17 @@ export class IsomorphicGitBackend {
187
180
  });
188
181
  }
189
182
  } catch (error) {
190
- throw new JJError(
191
- 'STORAGE_WRITE_FAILED',
192
- `Failed to update Git ref: ${error.message}`,
193
- { ref: name, oid, originalError: error }
194
- );
183
+ throw new JJError('STORAGE_WRITE_FAILED', `Failed to update Git ref: ${error.message}`, {
184
+ ref: name,
185
+ oid,
186
+ originalError: error,
187
+ });
195
188
  }
196
189
  }
197
190
 
198
191
  /**
199
192
  * List Git references
200
- *
193
+ *
201
194
  * @param {string} [prefix=''] - Ref prefix filter
202
195
  * @returns {Promise<Array<{name: string, oid: string}>>} List of refs
203
196
  */
@@ -206,22 +199,22 @@ export class IsomorphicGitBackend {
206
199
  // Use expandRef to get all possible refs
207
200
  const result = [];
208
201
  const refDirs = ['refs/heads', 'refs/tags', 'refs/remotes'];
209
-
202
+
210
203
  for (const refDir of refDirs) {
211
204
  if (prefix && !refDir.startsWith(prefix) && !prefix.startsWith(refDir)) {
212
205
  continue;
213
206
  }
214
-
207
+
215
208
  try {
216
209
  const dirPath = `${this.dir}/.git/${refDir}`;
217
210
  const entries = await this.fs.promises.readdir(dirPath, { recursive: true });
218
-
211
+
219
212
  for (const entry of entries) {
220
213
  const refName = `${refDir}/${entry}`;
221
214
  if (prefix && !refName.startsWith(prefix)) {
222
215
  continue;
223
216
  }
224
-
217
+
225
218
  try {
226
219
  const oid = await this.readRef(refName);
227
220
  if (oid) {
@@ -235,14 +228,13 @@ export class IsomorphicGitBackend {
235
228
  // Directory doesn't exist, skip
236
229
  }
237
230
  }
238
-
231
+
239
232
  return result.sort((a, b) => a.name.localeCompare(b.name));
240
233
  } catch (error) {
241
- throw new JJError(
242
- 'STORAGE_READ_FAILED',
243
- `Failed to list Git refs: ${error.message}`,
244
- { prefix, originalError: error }
245
- );
234
+ throw new JJError('STORAGE_READ_FAILED', `Failed to list Git refs: ${error.message}`, {
235
+ prefix,
236
+ originalError: error,
237
+ });
246
238
  }
247
239
  }
248
240
 
@@ -255,7 +247,7 @@ export class IsomorphicGitBackend {
255
247
  * @param {string} opts.author.name - Author name
256
248
  * @param {string} opts.author.email - Author email
257
249
  * @param {number} [opts.author.timestamp] - Author timestamp (milliseconds since epoch)
258
- * @param {Object} [opts.committer] - Committer info (defaults to author)
250
+ * @param {{name: string, email: string, timestamp?: number}} [opts.committer] - Committer info (defaults to author)
259
251
  * @param {string[]} [opts.parents=[]] - Parent commit SHAs
260
252
  * @returns {Promise<string>} Commit SHA
261
253
  */
@@ -264,16 +256,22 @@ export class IsomorphicGitBackend {
264
256
  const author = {
265
257
  name: opts.author.name,
266
258
  email: opts.author.email,
267
- timestamp: opts.author.timestamp ? Math.floor(opts.author.timestamp / 1000) : Math.floor(Date.now() / 1000),
259
+ timestamp: opts.author.timestamp
260
+ ? Math.floor(opts.author.timestamp / 1000)
261
+ : Math.floor(Date.now() / 1000),
268
262
  timezoneOffset: 0,
269
263
  };
270
264
 
271
- const committer = opts.committer ? {
272
- name: opts.committer.name,
273
- email: opts.committer.email,
274
- timestamp: opts.committer.timestamp ? Math.floor(opts.committer.timestamp / 1000) : author.timestamp,
275
- timezoneOffset: 0,
276
- } : author;
265
+ const committer = opts.committer
266
+ ? {
267
+ name: opts.committer.name,
268
+ email: opts.committer.email,
269
+ timestamp: opts.committer.timestamp
270
+ ? Math.floor(opts.committer.timestamp / 1000)
271
+ : author.timestamp,
272
+ timezoneOffset: 0,
273
+ }
274
+ : author;
277
275
 
278
276
  const commitSha = await git.commit({
279
277
  fs: this.fs,
@@ -286,34 +284,84 @@ export class IsomorphicGitBackend {
286
284
 
287
285
  return commitSha;
288
286
  } catch (error) {
289
- throw new JJError(
290
- 'COMMIT_FAILED',
291
- `Failed to create Git commit: ${error.message}`,
292
- { message: opts.message, originalError: error }
293
- );
287
+ throw new JJError('COMMIT_FAILED', `Failed to create Git commit: ${error.message}`, {
288
+ message: opts.message,
289
+ originalError: error,
290
+ });
294
291
  }
295
292
  }
296
293
 
297
294
  /**
298
- * Get the current tree SHA for the working directory
295
+ * Get the current tree SHA for the staging area (git index).
296
+ *
297
+ * `git.writeTree()` writes exactly the flat `TreeObject` array it's given —
298
+ * it does not build one from the working directory or index. To get "the
299
+ * tree that would be committed right now", walk the index (STAGE) to
300
+ * collect every staged blob's path/oid/mode, group them into a nested
301
+ * directory structure, and write each subtree bottom-up.
299
302
  *
300
303
  * @returns {Promise<string>} Tree SHA
301
304
  */
302
305
  async getCurrentTree() {
303
306
  try {
304
- // Get the current staging area tree
305
- // This will create tree objects from the current working directory
306
- const tree = await git.writeTree({
307
- fs: this.fs,
308
- dir: this.dir,
309
- });
310
- return tree;
307
+ /** @type {Array<{path: string, oid: string, mode: number}>} */
308
+ const flatEntries = (
309
+ await git.walk({
310
+ fs: this.fs,
311
+ dir: this.dir,
312
+ trees: [git.STAGE()],
313
+ map: async (filepath, [stage]) => {
314
+ if (!stage || filepath === '.') return undefined;
315
+ const type = await stage.type();
316
+ if (type !== 'blob') return undefined; // directory marker, not a leaf
317
+ return { path: filepath, oid: await stage.oid(), mode: await stage.mode() };
318
+ },
319
+ })
320
+ ).filter(Boolean);
321
+
322
+ // Group the flat, index-relative paths into a nested tree of
323
+ // directories, each holding its immediate file/subdirectory children.
324
+ /** @type {{dirs: Map<string, any>, files: Array<{name: string, oid: string, mode: string}>}} */
325
+ const root = { dirs: new Map(), files: [] };
326
+ for (const entry of flatEntries) {
327
+ const parts = entry.path.split('/');
328
+ let node = root;
329
+ for (let i = 0; i < parts.length - 1; i++) {
330
+ const segment = parts[i];
331
+ if (!node.dirs.has(segment)) {
332
+ node.dirs.set(segment, { dirs: new Map(), files: [] });
333
+ }
334
+ node = node.dirs.get(segment);
335
+ }
336
+ node.files.push({
337
+ name: parts[parts.length - 1],
338
+ oid: entry.oid,
339
+ // isomorphic-git expects an octal mode STRING (e.g. "100644"), but
340
+ // the walker returns the mode as a decimal number.
341
+ mode: entry.mode.toString(8),
342
+ });
343
+ }
344
+
345
+ const writeDir = async (/** @type {any} */ node) => {
346
+ /** @type {any[]} */
347
+ const treeEntries = [];
348
+ for (const [name, child] of node.dirs.entries()) {
349
+ const oid = await writeDir(child);
350
+ treeEntries.push({ mode: '040000', path: name, oid, type: 'tree' });
351
+ }
352
+ for (const file of node.files) {
353
+ treeEntries.push({ mode: file.mode, path: file.name, oid: file.oid, type: 'blob' });
354
+ }
355
+ return await git.writeTree(
356
+ /** @type {any} */ ({ fs: this.fs, dir: this.dir, tree: treeEntries })
357
+ );
358
+ };
359
+
360
+ return await writeDir(root);
311
361
  } catch (error) {
312
- throw new JJError(
313
- 'TREE_READ_FAILED',
314
- `Failed to get current tree: ${error.message}`,
315
- { originalError: error }
316
- );
362
+ throw new JJError('TREE_READ_FAILED', `Failed to get current tree: ${error.message}`, {
363
+ originalError: error,
364
+ });
317
365
  }
318
366
  }
319
367
 
@@ -347,11 +395,16 @@ export class IsomorphicGitBackend {
347
395
  }
348
396
  }
349
397
  } catch (error) {
350
- throw new JJError(
351
- 'STAGE_FAILED',
352
- `Failed to stage files: ${error.message}`,
353
- { originalError: error }
354
- );
398
+ // A per-file STAGE_FILE_FAILED (thrown above) is already categorized —
399
+ // re-throw it as-is instead of losing its specific code by re-wrapping
400
+ // it in the more generic STAGE_FAILED (which is reserved for failures
401
+ // in _getAllFiles() itself, e.g. an unreadable directory).
402
+ if (error instanceof JJError) {
403
+ throw error;
404
+ }
405
+ throw new JJError('STAGE_FAILED', `Failed to stage files: ${error.message}`, {
406
+ originalError: error,
407
+ });
355
408
  }
356
409
  }
357
410
 
@@ -414,9 +467,9 @@ export class IsomorphicGitBackend {
414
467
  * @param {boolean} [opts.relative] - Depth measured from current shallow depth (v0.4)
415
468
  * @param {boolean} [opts.singleBranch] - Only fetch single branch (v0.4)
416
469
  * @param {boolean} [opts.noTags] - Don't fetch tags (v0.4)
417
- * @param {Function} [opts.onProgress] - Progress callback
418
- * @param {Function} [opts.onAuth] - Authentication callback
419
- * @returns {Promise<{fetchedRefs: Array, updatedRefs: Array}>} Fetch result
470
+ * @param {any} [opts.onProgress] - Progress callback
471
+ * @param {any} [opts.onAuth] - Authentication callback
472
+ * @returns {Promise<{fetchedRefs: Array<any>, updatedRefs: Array<any>}>} Fetch result
420
473
  */
421
474
  async fetch(opts) {
422
475
  if (!this.http) {
@@ -440,8 +493,8 @@ export class IsomorphicGitBackend {
440
493
  dir: this.dir,
441
494
  remote: opts.remote,
442
495
  ref,
443
- depth: opts.depth, // v0.4: Shallow clone support
444
- relative: opts.relative, // v0.4: Relative depth
496
+ depth: opts.depth, // v0.4: Shallow clone support
497
+ relative: opts.relative, // v0.4: Relative depth
445
498
  singleBranch: opts.singleBranch, // v0.4: Single branch only
446
499
  tags: opts.noTags === true ? false : undefined, // v0.4: Skip tags
447
500
  onProgress: opts.onProgress,
@@ -460,37 +513,34 @@ export class IsomorphicGitBackend {
460
513
  return { fetchedRefs, updatedRefs };
461
514
  } catch (error) {
462
515
  if (error.code === 'HttpError' || error.code === 'NetworkError') {
463
- throw new JJError(
464
- 'NETWORK_ERROR',
465
- `Network error during fetch: ${error.message}`,
466
- { remote: opts.remote, originalError: error }
467
- );
516
+ throw new JJError('NETWORK_ERROR', `Network error during fetch: ${error.message}`, {
517
+ remote: opts.remote,
518
+ originalError: error,
519
+ });
468
520
  }
469
521
  if (error.code === 'AuthError') {
470
- throw new JJError(
471
- 'AUTH_FAILED',
472
- `Authentication failed: ${error.message}`,
473
- { remote: opts.remote, originalError: error }
474
- );
522
+ throw new JJError('AUTH_FAILED', `Authentication failed: ${error.message}`, {
523
+ remote: opts.remote,
524
+ originalError: error,
525
+ });
475
526
  }
476
- throw new JJError(
477
- 'FETCH_FAILED',
478
- `Fetch failed: ${error.message}`,
479
- { remote: opts.remote, originalError: error }
480
- );
527
+ throw new JJError('FETCH_FAILED', `Fetch failed: ${error.message}`, {
528
+ remote: opts.remote,
529
+ originalError: error,
530
+ });
481
531
  }
482
532
  }
483
533
 
484
534
  /**
485
535
  * Push objects and refs to remote repository
486
- *
536
+ *
487
537
  * @param {Object} opts - Push options
488
538
  * @param {string} opts.remote - Remote name or URL
489
539
  * @param {string[]} [opts.refs] - Ref specs to push
490
540
  * @param {boolean} [opts.force] - Allow non-fast-forward
491
- * @param {Function} [opts.onProgress] - Progress callback
492
- * @param {Function} [opts.onAuth] - Authentication callback
493
- * @returns {Promise<{pushedRefs: Array, rejectedRefs: Array}>} Push result
541
+ * @param {any} [opts.onProgress] - Progress callback
542
+ * @param {any} [opts.onAuth] - Authentication callback
543
+ * @returns {Promise<{pushedRefs: Array<any>, rejectedRefs: Array<any>}>} Push result
494
544
  */
495
545
  async push(opts) {
496
546
  if (!this.http) {
@@ -534,31 +584,28 @@ export class IsomorphicGitBackend {
534
584
  return { pushedRefs, rejectedRefs };
535
585
  } catch (error) {
536
586
  if (error.code === 'HttpError' || error.code === 'NetworkError') {
537
- throw new JJError(
538
- 'NETWORK_ERROR',
539
- `Network error during push: ${error.message}`,
540
- { remote: opts.remote, originalError: error }
541
- );
587
+ throw new JJError('NETWORK_ERROR', `Network error during push: ${error.message}`, {
588
+ remote: opts.remote,
589
+ originalError: error,
590
+ });
542
591
  }
543
592
  if (error.code === 'AuthError') {
544
- throw new JJError(
545
- 'AUTH_FAILED',
546
- `Authentication failed: ${error.message}`,
547
- { remote: opts.remote, originalError: error }
548
- );
593
+ throw new JJError('AUTH_FAILED', `Authentication failed: ${error.message}`, {
594
+ remote: opts.remote,
595
+ originalError: error,
596
+ });
549
597
  }
550
598
  if (error.code === 'PushRejectedError') {
551
- throw new JJError(
552
- 'PUSH_REJECTED',
553
- `Push rejected (non-fast-forward): ${error.message}`,
554
- { remote: opts.remote, suggestion: 'Use force option or pull first', originalError: error }
555
- );
599
+ throw new JJError('PUSH_REJECTED', `Push rejected (non-fast-forward): ${error.message}`, {
600
+ remote: opts.remote,
601
+ suggestion: 'Use force option or pull first',
602
+ originalError: error,
603
+ });
556
604
  }
557
- throw new JJError(
558
- 'PUSH_FAILED',
559
- `Push failed: ${error.message}`,
560
- { remote: opts.remote, originalError: error }
561
- );
605
+ throw new JJError('PUSH_FAILED', `Push failed: ${error.message}`, {
606
+ remote: opts.remote,
607
+ originalError: error,
608
+ });
562
609
  }
563
610
  }
564
611
 
@@ -637,17 +684,17 @@ export class IsomorphicGitBackend {
637
684
  const metadata = {
638
685
  start_time: {
639
686
  millis_since_epoch: Date.now(),
640
- tz_offset: new Date().getTimezoneOffset()
687
+ tz_offset: new Date().getTimezoneOffset(),
641
688
  },
642
689
  end_time: {
643
690
  millis_since_epoch: Date.now(),
644
- tz_offset: new Date().getTimezoneOffset()
691
+ tz_offset: new Date().getTimezoneOffset(),
645
692
  },
646
693
  description: 'initialize repo',
647
694
  hostname: 'localhost',
648
695
  username: 'user',
649
696
  is_snapshot: false,
650
- tags: {}
697
+ tags: {},
651
698
  };
652
699
  await opStore.writeOperation(operationId, viewId, [], metadata);
653
700
 
@@ -676,7 +723,7 @@ export class IsomorphicGitBackend {
676
723
 
677
724
  // Check if .jj is already in .gitignore
678
725
  const lines = content.split('\n');
679
- const hasJJ = lines.some(line => line.trim() === '.jj' || line.trim() === '.jj/');
726
+ const hasJJ = lines.some((line) => line.trim() === '.jj' || line.trim() === '.jj/');
680
727
 
681
728
  if (!hasJJ) {
682
729
  // Add .jj to .gitignore
@@ -44,11 +44,7 @@ export class LazyGitBackend extends IsomorphicGitBackend {
44
44
  async readBlob(oid) {
45
45
  // Validate OID format
46
46
  if (!/^[0-9a-f]{40}$/.test(oid)) {
47
- throw new JJError(
48
- 'INVALID_OID',
49
- `Invalid object ID format: ${oid}`,
50
- { oid }
51
- );
47
+ throw new JJError('INVALID_OID', `Invalid object ID format: ${oid}`, { oid });
52
48
  }
53
49
 
54
50
  try {
@@ -60,19 +56,15 @@ export class LazyGitBackend extends IsomorphicGitBackend {
60
56
  // Track as missing BEFORE attempting fetch
61
57
  this.missingObjects.add(oid);
62
58
 
63
- // Only fetch if we haven't already tried
59
+ // Only fetch if we haven't already tried. If the fetch (or the retry
60
+ // read) fails, the error propagates directly — the object is already
61
+ // tracked as missing above.
64
62
  if (!this.fetchedObjects.has(oid)) {
65
- try {
66
- await this._fetchObject(oid);
67
- this.fetchedObjects.add(oid);
63
+ await this._fetchObject(oid);
64
+ this.fetchedObjects.add(oid);
68
65
 
69
- // Try reading again after fetch
70
- return await this._gitReadBlob(oid);
71
- } catch (fetchError) {
72
- // Fetch failed, but we still track as missing
73
- // Re-throw the fetch error
74
- throw fetchError;
75
- }
66
+ // Try reading again after fetch
67
+ return await this._gitReadBlob(oid);
76
68
  }
77
69
  }
78
70
 
@@ -164,9 +156,10 @@ export class LazyGitBackend extends IsomorphicGitBackend {
164
156
  lazyLoad: this.lazyLoad,
165
157
  missingObjects: this.missingObjects.size,
166
158
  fetchedObjects: this.fetchedObjects.size,
167
- hitRate: this.fetchedObjects.size > 0
168
- ? (this.fetchedObjects.size - this.missingObjects.size) / this.fetchedObjects.size
169
- : 0,
159
+ hitRate:
160
+ this.fetchedObjects.size > 0
161
+ ? (this.fetchedObjects.size - this.missingObjects.size) / this.fetchedObjects.size
162
+ : 0,
170
163
  };
171
164
  }
172
165
 
@@ -51,7 +51,8 @@ export function createBrowserFS(opts = {}) {
51
51
  } catch (error) {
52
52
  throw new Error(
53
53
  'LightningFS not found. Install it with: npm install @isomorphic-git/lightning-fs\n' +
54
- 'Original error: ' + error.message
54
+ 'Original error: ' +
55
+ error.message
55
56
  );
56
57
  }
57
58
  }
@@ -182,7 +183,10 @@ export function detectCapabilities() {
182
183
  environment: 'browser',
183
184
  indexedDB: typeof indexedDB !== 'undefined',
184
185
  serviceWorker: typeof navigator !== 'undefined' && 'serviceWorker' in navigator,
185
- persistentStorage: typeof navigator !== 'undefined' && navigator.storage && typeof navigator.storage.persist === 'function',
186
+ persistentStorage:
187
+ typeof navigator !== 'undefined' &&
188
+ navigator.storage &&
189
+ typeof navigator.storage.persist === 'function',
186
190
  sharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',
187
191
  webWorker: typeof Worker !== 'undefined',
188
192
  };