@indigoai-us/hq-cloud 6.18.52 → 6.18.55-alpha.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.
Files changed (91) hide show
  1. package/dist/bin/sync-runner-audit.d.ts +26 -0
  2. package/dist/bin/sync-runner-audit.d.ts.map +1 -0
  3. package/dist/bin/sync-runner-audit.js +51 -0
  4. package/dist/bin/sync-runner-audit.js.map +1 -0
  5. package/dist/bin/sync-runner-company.d.ts +18 -0
  6. package/dist/bin/sync-runner-company.d.ts.map +1 -1
  7. package/dist/bin/sync-runner-company.js +186 -9
  8. package/dist/bin/sync-runner-company.js.map +1 -1
  9. package/dist/bin/sync-runner-watch-loop.d.ts +107 -5
  10. package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
  11. package/dist/bin/sync-runner-watch-loop.js +1382 -183
  12. package/dist/bin/sync-runner-watch-loop.js.map +1 -1
  13. package/dist/bin/sync-runner.d.ts +63 -11
  14. package/dist/bin/sync-runner.d.ts.map +1 -1
  15. package/dist/bin/sync-runner.js +348 -94
  16. package/dist/bin/sync-runner.js.map +1 -1
  17. package/dist/bin/watcher-catchup-skip-store.d.ts +60 -0
  18. package/dist/bin/watcher-catchup-skip-store.d.ts.map +1 -0
  19. package/dist/bin/watcher-catchup-skip-store.js +282 -0
  20. package/dist/bin/watcher-catchup-skip-store.js.map +1 -0
  21. package/dist/cli/conflict.d.ts +6 -0
  22. package/dist/cli/conflict.d.ts.map +1 -1
  23. package/dist/cli/conflict.js +3 -1
  24. package/dist/cli/conflict.js.map +1 -1
  25. package/dist/cli/share.d.ts +27 -0
  26. package/dist/cli/share.d.ts.map +1 -1
  27. package/dist/cli/share.js +119 -22
  28. package/dist/cli/share.js.map +1 -1
  29. package/dist/cli/sync.d.ts +18 -2
  30. package/dist/cli/sync.d.ts.map +1 -1
  31. package/dist/cli/sync.js +74 -14
  32. package/dist/cli/sync.js.map +1 -1
  33. package/dist/ignore.d.ts +1 -1
  34. package/dist/ignore.d.ts.map +1 -1
  35. package/dist/ignore.js +2 -2
  36. package/dist/ignore.js.map +1 -1
  37. package/dist/journal-snapshot-v4.d.ts.map +1 -1
  38. package/dist/journal-snapshot-v4.js +44 -38
  39. package/dist/journal-snapshot-v4.js.map +1 -1
  40. package/dist/journal.d.ts +15 -2
  41. package/dist/journal.d.ts.map +1 -1
  42. package/dist/journal.js +221 -16
  43. package/dist/journal.js.map +1 -1
  44. package/dist/lib/cloud-authoritative.d.ts +9 -2
  45. package/dist/lib/cloud-authoritative.d.ts.map +1 -1
  46. package/dist/lib/cloud-authoritative.js +34 -2
  47. package/dist/lib/cloud-authoritative.js.map +1 -1
  48. package/dist/lib/exit-codes.d.ts +2 -0
  49. package/dist/lib/exit-codes.d.ts.map +1 -1
  50. package/dist/lib/exit-codes.js +2 -0
  51. package/dist/lib/exit-codes.js.map +1 -1
  52. package/dist/personal-vault-exclusions.d.ts +2 -2
  53. package/dist/personal-vault-exclusions.d.ts.map +1 -1
  54. package/dist/personal-vault-exclusions.js +5 -3
  55. package/dist/personal-vault-exclusions.js.map +1 -1
  56. package/dist/personal-vault.d.ts +7 -0
  57. package/dist/personal-vault.d.ts.map +1 -1
  58. package/dist/personal-vault.js +10 -0
  59. package/dist/personal-vault.js.map +1 -1
  60. package/dist/qmd-runner-admission.d.ts +22 -0
  61. package/dist/qmd-runner-admission.d.ts.map +1 -0
  62. package/dist/qmd-runner-admission.js +107 -0
  63. package/dist/qmd-runner-admission.js.map +1 -0
  64. package/dist/s3.d.ts +2 -0
  65. package/dist/s3.d.ts.map +1 -1
  66. package/dist/s3.js +2 -0
  67. package/dist/s3.js.map +1 -1
  68. package/dist/symlink-target-policy.d.ts +11 -0
  69. package/dist/symlink-target-policy.d.ts.map +1 -1
  70. package/dist/symlink-target-policy.js +110 -0
  71. package/dist/symlink-target-policy.js.map +1 -1
  72. package/dist/sync/mutation-session.d.ts.map +1 -1
  73. package/dist/sync/mutation-session.js +4 -0
  74. package/dist/sync/mutation-session.js.map +1 -1
  75. package/dist/sync/parallel-sync-coordinator.d.ts +29 -0
  76. package/dist/sync/parallel-sync-coordinator.d.ts.map +1 -1
  77. package/dist/sync/parallel-sync-coordinator.js +229 -16
  78. package/dist/sync/parallel-sync-coordinator.js.map +1 -1
  79. package/dist/sync/push-receiver.d.ts +5 -0
  80. package/dist/sync/push-receiver.d.ts.map +1 -1
  81. package/dist/sync/push-receiver.js +32 -10
  82. package/dist/sync/push-receiver.js.map +1 -1
  83. package/dist/watch-owner-lease.d.ts +4 -0
  84. package/dist/watch-owner-lease.d.ts.map +1 -1
  85. package/dist/watch-owner-lease.js +40 -6
  86. package/dist/watch-owner-lease.js.map +1 -1
  87. package/dist/watcher.d.ts +16 -3
  88. package/dist/watcher.d.ts.map +1 -1
  89. package/dist/watcher.js +114 -21
  90. package/dist/watcher.js.map +1 -1
  91. package/package.json +1 -1
package/dist/journal.js CHANGED
@@ -20,6 +20,7 @@ import { spawn } from "node:child_process";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { JournalRowOverlay, JournalRowStore, journalEntryFingerprint, } from "./journal-row-store.js";
22
22
  import { createJournalRecordProxy, journalRecordRows } from "./journal-record-proxy.js";
23
+ import { fsyncWithCompatibility } from "./sync/fsync-compat.js";
23
24
  import { decodeJournalSnapshot, decodedJournalRows } from "./journal-snapshot-decoder.js";
24
25
  import { forgetSharedAreaJournalRows, } from "./journal-snapshot-rows.js";
25
26
  export { JOURNAL_CACHE_MAX_ROWS, JOURNAL_DECODE_WINDOW, dropJournalDecodeWindow, emitJournalCacheMetric, journalCacheMetric, journalFingerprintMatchesStat, resetJournalDecodeWindowForTest, } from "./journal-decode-window.js";
@@ -506,6 +507,39 @@ function sanitizeSlug(slug) {
506
507
  export function getJournalPath(slug) {
507
508
  return path.join(getStateDir(), `${JOURNAL_FILE_PREFIX}${sanitizeSlug(slug)}${JOURNAL_FILE_SUFFIX}`);
508
509
  }
510
+ /**
511
+ * Paths retained in the durable quarantine sidecars for this journal scope.
512
+ * A quarantined path remains unresolved until an operator removes or repairs
513
+ * its sidecar; sync must not infer a create, download, or delete for it.
514
+ */
515
+ export function readQuarantinedJournalPaths(slug) {
516
+ const scope = crypto.createHash("sha256").update(journalScopeId(slug)).digest("hex");
517
+ const directory = path.join(getStateDir(), "journal-quarantine", scope);
518
+ let names;
519
+ try {
520
+ names = fs.readdirSync(directory);
521
+ }
522
+ catch (error) {
523
+ if (error.code === "ENOENT")
524
+ return new Set();
525
+ throw error;
526
+ }
527
+ const paths = new Set();
528
+ for (const name of names) {
529
+ if (!name.endsWith(".json"))
530
+ continue;
531
+ const sidecar = JSON.parse(fs.readFileSync(path.join(directory, name), "utf8"));
532
+ if (sidecar.format !== "hq-journal-quarantine@1" || !Array.isArray(sidecar.invalidUpserts)) {
533
+ throw new Error("journal: invalid quarantine sidecar");
534
+ }
535
+ for (const invalid of sidecar.invalidUpserts) {
536
+ if (typeof invalid.key !== "string")
537
+ throw new Error("journal: invalid quarantined path");
538
+ paths.add(invalid.key);
539
+ }
540
+ }
541
+ return paths;
542
+ }
509
543
  /**
510
544
  * Reserved journal slug for the personal-vault fanout slot in the `--companies`
511
545
  * runner. The vault slot uploads the whole HQ overlay (`.claude/`, `core/`,
@@ -571,7 +605,7 @@ export function migratePersonalVaultJournal() {
571
605
  * When the file doesn't exist, we return a fresh v2 journal directly — new
572
606
  * installs never pass through v1 on disk.
573
607
  */
574
- export function readJournal(slug) {
608
+ export function readJournal(slug, companyUid) {
575
609
  const areaMigration = openAreaMigrationIfAuthoritative(slug);
576
610
  if (areaMigration) {
577
611
  // Area rows stay in their shared packed store. This record-compatible
@@ -583,7 +617,7 @@ export function readJournal(slug) {
583
617
  // same immutable packed rows. Each owns only its own overlay, so an
584
618
  // uncommitted full pass is never visible to a scoped reader (and a scoped
585
619
  // delta cannot dirty the full pass).
586
- return readStoreBackedJournal(readJournalAggregateWith(slug, areaMigration, true), { privateOverlay: true });
620
+ return readStoreBackedJournal(readJournalAggregateWith(slug, areaMigration, true, companyUid), { privateOverlay: true });
587
621
  }
588
622
  /**
589
623
  * Read the mutable outer shell required by a full pull without detaching every
@@ -599,10 +633,10 @@ export function readJournal(slug) {
599
633
  *
600
634
  * @internal Full-pull boundary; not a public journal record API.
601
635
  */
602
- export function readJournalForPass(slug) {
636
+ export function readJournalForPass(slug, companyUid) {
603
637
  const areaMigration = openAreaMigrationIfAuthoritative(slug);
604
638
  if (!areaMigration)
605
- return readJournal(slug);
639
+ return readJournal(slug, companyUid);
606
640
  // The overlay owns only keys this pass changes; it borrows all untouched
607
641
  // packed rows from the cached aggregate and keeps the public record facade.
608
642
  const journal = readStoreBackedJournal(areaMigration.readAreaJournalCached().journal, { privateOverlay: true });
@@ -631,12 +665,12 @@ export function readJournalForPass(slug) {
631
665
  function readJournalAggregate(slug) {
632
666
  return readJournalAggregateWith(slug, openAreaMigrationIfAuthoritative(slug));
633
667
  }
634
- function readJournalAggregateWith(slug, areaMigration, retainScopedProjection = false) {
668
+ function readJournalAggregateWith(slug, areaMigration, retainScopedProjection = false, companyUid) {
635
669
  if (areaMigration)
636
670
  return areaMigration.readAreaJournal();
637
671
  const store = StateStore.exists(getStateDir(), journalScopeId(slug))
638
- ? openJournalStore(slug, emptyJournal())
639
- : openJournalStore(slug, readLegacyJournal(slug));
672
+ ? openJournalStore(slug, emptyJournal(), companyUid)
673
+ : openJournalStore(slug, readLegacyJournal(slug), companyUid);
640
674
  if (retainScopedProjection) {
641
675
  // A full pass has already paid to recover this packed snapshot. Retain its
642
676
  // projection for the next scoped pass instead of making that pass decode
@@ -805,7 +839,7 @@ export function setJournalSnapshotDecoderForTest(decoder) {
805
839
  export function setJournalSnapshotEncoderForTest(encoder) {
806
840
  journalSnapshotEncoderForTest = encoder;
807
841
  }
808
- function journalStoreOptions(slug, initialJournal) {
842
+ function journalStoreOptions(slug, initialJournal, companyUid) {
809
843
  return {
810
844
  rootDir: getStateDir(),
811
845
  scopeId: journalScopeId(slug),
@@ -828,6 +862,7 @@ function journalStoreOptions(slug, initialJournal) {
828
862
  }
829
863
  if (record.type === JOURNAL_DELTA_RECORD_TYPE) {
830
864
  const delta = record.payload;
865
+ const replayDelta = quarantineIncompleteJournalUpserts(slug, companyUid, record, delta);
831
866
  const existingRows = journalRecordRows(state.journal.files) ?? decodedJournalRows(state.journal);
832
867
  if (existingRows) {
833
868
  // StateStore's aggregate is also the immutable source for any
@@ -835,14 +870,14 @@ function journalStoreOptions(slug, initialJournal) {
835
870
  // observed, put durable changes in a separate overlay rather than
836
871
  // mutating that shared packed row store.
837
872
  const rows = existingRows instanceof JournalRowOverlay
838
- ? existingRows.withCommittedDelta(delta.upserts, delta.deletes)
839
- : new JournalRowOverlay(existingRows).withCommittedDelta(delta.upserts, delta.deletes);
873
+ ? existingRows.withCommittedDelta(replayDelta.upserts, replayDelta.deletes)
874
+ : new JournalRowOverlay(existingRows).withCommittedDelta(replayDelta.upserts, replayDelta.deletes);
840
875
  state.journal.files = createJournalRecordProxy(rows);
841
876
  }
842
877
  else {
843
- for (const key of delta.deletes)
878
+ for (const key of replayDelta.deletes)
844
879
  delete state.journal.files[key];
845
- Object.assign(state.journal.files, delta.upserts);
880
+ Object.assign(state.journal.files, replayDelta.upserts);
846
881
  }
847
882
  state.journal.version = delta.version;
848
883
  state.journal.lastSync = delta.lastSync ?? state.journal.lastSync;
@@ -861,12 +896,14 @@ function validateJournalRecord(record) {
861
896
  }
862
897
  return;
863
898
  }
864
- if (record.type === JOURNAL_DELTA_RECORD_TYPE && isJournalDelta(record.payload))
899
+ if (record.type === JOURNAL_DELTA_RECORD_TYPE && isJournalDelta(record.payload)) {
900
+ assertCompleteJournalUpserts(record.payload);
865
901
  return;
902
+ }
866
903
  throw new Error(`journal: unexpected v3 WAL record type ${record.type}`);
867
904
  }
868
- function openJournalStore(slug, initialJournal) {
869
- return StateStore.open(journalStoreOptions(slug, initialJournal));
905
+ function openJournalStore(slug, initialJournal, companyUid) {
906
+ return StateStore.open(journalStoreOptions(slug, initialJournal, companyUid));
870
907
  }
871
908
  /**
872
909
  * A committed area manifest is an authority decision, not a hint. If its
@@ -1245,6 +1282,7 @@ export class JournalStore {
1245
1282
  upserts: structuredClone(delta.upserts ?? {}),
1246
1283
  deletes: [...(delta.deletes ?? [])],
1247
1284
  };
1285
+ assertCompleteJournalUpserts(payload);
1248
1286
  if (delta.metadata?.lastSync !== undefined)
1249
1287
  payload.lastSync = delta.metadata.lastSync;
1250
1288
  if (delta.metadata?.pulls !== undefined)
@@ -1275,6 +1313,7 @@ export class JournalStore {
1275
1313
  payload.lastSync = delta.metadata.lastSync;
1276
1314
  if (delta.metadata?.pulls !== undefined)
1277
1315
  payload.pulls = structuredClone(delta.metadata.pulls);
1316
+ assertCompleteJournalUpserts(payload);
1278
1317
  return payload;
1279
1318
  };
1280
1319
  if (this.areaMigration) {
@@ -1312,6 +1351,7 @@ export class JournalStore {
1312
1351
  upserts: structuredClone(delta.upserts ?? {}),
1313
1352
  deletes: [...(delta.deletes ?? [])],
1314
1353
  };
1354
+ assertCompleteJournalUpserts(payload);
1315
1355
  if (delta.metadata?.lastSync !== undefined)
1316
1356
  payload.lastSync = delta.metadata.lastSync;
1317
1357
  if (delta.metadata?.pulls !== undefined)
@@ -1591,6 +1631,171 @@ function isJournalDelta(value) {
1591
1631
  Array.isArray(delta.deletes) && delta.deletes.every((key) => typeof key === "string") &&
1592
1632
  (delta.pulls === undefined || Array.isArray(delta.pulls));
1593
1633
  }
1634
+ export class JournalIncompleteUpsertError extends Error {
1635
+ missingFields;
1636
+ errorClass = "JournalIncompleteUpsertError";
1637
+ constructor(missingFields) {
1638
+ super(`journal delta upsert is incomplete (${missingFields.join(",")})`);
1639
+ this.missingFields = missingFields;
1640
+ this.name = "JournalIncompleteUpsertError";
1641
+ }
1642
+ }
1643
+ function incompleteJournalEntryFields(value) {
1644
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
1645
+ return ["hash", "size", "syncedAt", "direction"];
1646
+ }
1647
+ const entry = value;
1648
+ const missing = [];
1649
+ if (typeof entry.hash !== "string")
1650
+ missing.push("hash");
1651
+ if (typeof entry.size !== "number" || !Number.isFinite(entry.size))
1652
+ missing.push("size");
1653
+ if (typeof entry.syncedAt !== "string")
1654
+ missing.push("syncedAt");
1655
+ if (entry.direction !== "up" && entry.direction !== "down")
1656
+ missing.push("direction");
1657
+ return missing;
1658
+ }
1659
+ function assertCompleteJournalUpserts(delta) {
1660
+ for (const entry of Object.values(delta.upserts)) {
1661
+ const missing = incompleteJournalEntryFields(entry);
1662
+ if (missing.length > 0)
1663
+ throw new JournalIncompleteUpsertError(missing);
1664
+ }
1665
+ }
1666
+ const loggedQuarantinedJournalRecords = new Set();
1667
+ function quarantineIncompleteJournalUpserts(slug, companyUid, record, delta) {
1668
+ const invalid = Object.entries(delta.upserts)
1669
+ .map(([key, value]) => ({ key, value, missingFields: incompleteJournalEntryFields(value) }))
1670
+ .filter((entry) => entry.missingFields.length > 0);
1671
+ if (invalid.length === 0)
1672
+ return delta;
1673
+ const content = JSON.stringify({
1674
+ format: "hq-journal-quarantine@1",
1675
+ slug,
1676
+ companyUid,
1677
+ sequence: record.sequence,
1678
+ recordType: record.type,
1679
+ invalidUpserts: invalid,
1680
+ });
1681
+ const digest = crypto.createHash("sha256").update(content).digest("hex");
1682
+ const quarantineDirectory = path.join(getStateDir(), "journal-quarantine", crypto.createHash("sha256").update(journalScopeId(slug)).digest("hex"));
1683
+ const finalPath = path.join(quarantineDirectory, `${record.sequence}-${digest}.json`);
1684
+ let linkAttempted = false;
1685
+ try {
1686
+ fs.mkdirSync(quarantineDirectory, { recursive: true, mode: 0o700 });
1687
+ const tempPath = path.join(quarantineDirectory, `${record.sequence}-${digest}-${crypto.randomBytes(8).toString("hex")}.json.tmp`);
1688
+ let descriptor;
1689
+ let operationError;
1690
+ let operationFailed = false;
1691
+ let cleanupError;
1692
+ let cleanupFailed = false;
1693
+ try {
1694
+ descriptor = fs.openSync(tempPath, "wx", 0o600);
1695
+ fs.writeFileSync(descriptor, `${content}\n`);
1696
+ fs.fsyncSync(descriptor);
1697
+ fs.closeSync(descriptor);
1698
+ descriptor = undefined;
1699
+ // A hard link publishes the fully synced inode atomically and fails if a
1700
+ // previous replay already installed this immutable record. Unlike rename,
1701
+ // link never overwrites an existing complete quarantine sidecar.
1702
+ linkAttempted = true;
1703
+ fs.linkSync(tempPath, finalPath);
1704
+ }
1705
+ catch (error) {
1706
+ operationError = error;
1707
+ operationFailed = true;
1708
+ }
1709
+ finally {
1710
+ if (descriptor !== undefined) {
1711
+ try {
1712
+ fs.closeSync(descriptor);
1713
+ }
1714
+ catch (error) {
1715
+ cleanupError = error;
1716
+ cleanupFailed = true;
1717
+ }
1718
+ }
1719
+ try {
1720
+ fs.unlinkSync(tempPath);
1721
+ }
1722
+ catch (error) {
1723
+ if (error.code !== "ENOENT" && !cleanupFailed) {
1724
+ cleanupError = error;
1725
+ cleanupFailed = true;
1726
+ }
1727
+ }
1728
+ }
1729
+ // Keep the operation's failure authoritative if cleanup also fails. The
1730
+ // cleanup error is surfaced only when publishing itself succeeded.
1731
+ if (operationFailed)
1732
+ throw operationError;
1733
+ if (cleanupFailed)
1734
+ throw cleanupError;
1735
+ const directoryDescriptor = fs.openSync(quarantineDirectory, "r");
1736
+ try {
1737
+ fsyncWithCompatibility(directoryDescriptor, {
1738
+ site: "journal quarantine directory",
1739
+ handleKind: "directory",
1740
+ });
1741
+ }
1742
+ finally {
1743
+ fs.closeSync(directoryDescriptor);
1744
+ }
1745
+ }
1746
+ catch (error) {
1747
+ // Replay may proceed without a write only when the same immutable sidecar
1748
+ // was already published. Other persistence failures must stop replay so a
1749
+ // later compaction cannot discard the only copy of this malformed record.
1750
+ if (linkAttempted &&
1751
+ isAlreadyExistsError(error) &&
1752
+ quarantineSidecarMatches(finalPath, `${content}\n`)) {
1753
+ // An earlier replay installed this exact record.
1754
+ }
1755
+ else {
1756
+ writeJournalRecoveryEvent("journal_quarantine_write_failed", "JournalQuarantineWriteError", companyUid);
1757
+ throw error;
1758
+ }
1759
+ }
1760
+ const eventKey = `${slug}:${record.sequence}:${digest}:${companyUid ?? ""}`;
1761
+ if (!loggedQuarantinedJournalRecords.has(eventKey)) {
1762
+ loggedQuarantinedJournalRecords.add(eventKey);
1763
+ writeJournalRecoveryEvent("journal_record_quarantined", "JournalIncompleteUpsertError", companyUid);
1764
+ }
1765
+ const invalidPaths = new Set(invalid.map((entry) => entry.key));
1766
+ const upserts = Object.fromEntries(Object.entries(delta.upserts).filter(([key]) => !invalidPaths.has(key)));
1767
+ // A malformed upsert never authorizes deletion. Preserve any base row for
1768
+ // that path, even if the same WAL record also listed it in `deletes`.
1769
+ const deletes = delta.deletes.filter((key) => !invalidPaths.has(key));
1770
+ return { ...delta, upserts, deletes };
1771
+ }
1772
+ function isAlreadyExistsError(error) {
1773
+ return typeof error === "object" && error !== null && "code" in error &&
1774
+ error.code === "EEXIST";
1775
+ }
1776
+ function quarantineSidecarMatches(filePath, expectedContent) {
1777
+ try {
1778
+ return fs.readFileSync(filePath, "utf8") === expectedContent;
1779
+ }
1780
+ catch {
1781
+ return false;
1782
+ }
1783
+ }
1784
+ function writeJournalRecoveryEvent(event, errorClass, companyUid) {
1785
+ try {
1786
+ process.stderr.write(`${JSON.stringify({
1787
+ type: "error",
1788
+ diagnostic: true,
1789
+ event,
1790
+ errorClass,
1791
+ ...(companyUid === undefined ? {} : { companyUid }),
1792
+ })}\n`);
1793
+ }
1794
+ catch {
1795
+ // A diagnostic event must not break recovery or sync.
1796
+ process.emitWarning(`journal recovery diagnostic could not be emitted (${errorClass})`);
1797
+ }
1798
+ }
1594
1799
  function isJournal(value) {
1595
1800
  return typeof value === "object" && value !== null &&
1596
1801
  (value.version === "1" || value.version === "2") &&
@@ -2237,7 +2442,7 @@ function ensureJournalLocator(slug) {
2237
2442
  */
2238
2443
  export function repairJournalStateIfNeeded(slug, options = {}) {
2239
2444
  const safeSlug = sanitizeSlug(slug);
2240
- const storeOptions = journalStoreOptions(safeSlug, emptyJournal());
2445
+ const storeOptions = journalStoreOptions(safeSlug, emptyJournal(), options.companyUid);
2241
2446
  if (options.maxWalBytesBeforeCompaction !== undefined) {
2242
2447
  storeOptions.maxWalBytesBeforeCompaction = options.maxWalBytesBeforeCompaction;
2243
2448
  }