@deepagents/text2sql 7.1.2 → 7.1.3

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.
package/dist/index.js CHANGED
@@ -1545,6 +1545,7 @@ function hashConfig(config) {
1545
1545
  }
1546
1546
 
1547
1547
  // packages/text2sql/src/lib/fs/sqlite/sqlite-fs.ts
1548
+ import { transaction } from "@zukhruf/sqlite-transaction";
1548
1549
  import * as path2 from "node:path";
1549
1550
  import { DatabaseSync } from "node:sqlite";
1550
1551
  import z6 from "zod";
@@ -1583,7 +1584,7 @@ var chunkRow = z6.object({
1583
1584
  var dataRow = chunkRow.pick({ data: true });
1584
1585
  var SqliteFs = class {
1585
1586
  #db;
1586
- #statements = /* @__PURE__ */ new Map();
1587
+ #sql;
1587
1588
  #chunkSize;
1588
1589
  #root;
1589
1590
  constructor(options) {
@@ -1592,25 +1593,18 @@ var SqliteFs = class {
1592
1593
  this.#root = normalizedRoot === "/" ? "" : normalizedRoot;
1593
1594
  this.#db = new DatabaseSync(options.dbPath);
1594
1595
  this.#db.exec(ddl_sqlite_fs_default);
1595
- const rootSlashExists = this.#stmt(
1596
- "SELECT 1 FROM fs_entries WHERE path = ?"
1597
- ).get("/");
1596
+ this.#sql = this.#db.createTagStore();
1597
+ const rootSlashExists = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = '/'`;
1598
1598
  if (!rootSlashExists) {
1599
- this.#stmt(
1600
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1601
- VALUES ('/', 'directory', 493, 0, ?)`
1602
- ).run(Date.now());
1599
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1600
+ VALUES ('/', 'directory', 493, 0, ${Date.now()})`;
1603
1601
  }
1604
1602
  if (this.#root) {
1605
1603
  this.#createParentDirs(this.#root);
1606
- const rootExists = this.#stmt(
1607
- "SELECT 1 FROM fs_entries WHERE path = ?"
1608
- ).get(this.#root);
1604
+ const rootExists = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${this.#root}`;
1609
1605
  if (!rootExists) {
1610
- this.#stmt(
1611
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1612
- VALUES (?, 'directory', 493, 0, ?)`
1613
- ).run(this.#root, Date.now());
1606
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1607
+ VALUES (${this.#root}, 'directory', 493, 0, ${Date.now()})`;
1614
1608
  }
1615
1609
  }
1616
1610
  }
@@ -1623,25 +1617,13 @@ var SqliteFs = class {
1623
1617
  let currentPath = "/";
1624
1618
  for (let i = 0; i < segments.length - 1; i++) {
1625
1619
  currentPath = path2.posix.join(currentPath, segments[i]);
1626
- const exists = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
1627
- currentPath
1628
- );
1620
+ const exists = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${currentPath}`;
1629
1621
  if (!exists) {
1630
- this.#stmt(
1631
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1632
- VALUES (?, 'directory', 493, 0, ?)`
1633
- ).run(currentPath, Date.now());
1622
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1623
+ VALUES (${currentPath}, 'directory', 493, 0, ${Date.now()})`;
1634
1624
  }
1635
1625
  }
1636
1626
  }
1637
- #stmt(sql) {
1638
- let stmt = this.#statements.get(sql);
1639
- if (!stmt) {
1640
- stmt = this.#db.prepare(sql);
1641
- this.#statements.set(sql, stmt);
1642
- }
1643
- return stmt;
1644
- }
1645
1627
  #normalizeRoot(root) {
1646
1628
  return path2.posix.resolve("/", root.trim());
1647
1629
  }
@@ -1666,20 +1648,6 @@ var SqliteFs = class {
1666
1648
  }
1667
1649
  return p;
1668
1650
  }
1669
- #useTransaction(fn) {
1670
- this.#db.exec("BEGIN TRANSACTION");
1671
- try {
1672
- const result = fn();
1673
- this.#db.exec("COMMIT");
1674
- return result;
1675
- } catch (error) {
1676
- try {
1677
- this.#db.exec("ROLLBACK");
1678
- } catch {
1679
- }
1680
- throw error;
1681
- }
1682
- }
1683
1651
  #normalizePath(p) {
1684
1652
  return path2.posix.resolve("/", p);
1685
1653
  }
@@ -1691,43 +1659,33 @@ var SqliteFs = class {
1691
1659
  const parent = this.#dirname(filePath);
1692
1660
  const rootPath = this.#root || "/";
1693
1661
  if (parent === rootPath || parent === "/") return;
1694
- const entry = typeRow.optional().parse(
1695
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(parent)
1696
- );
1662
+ const entry = typeRow.optional().parse(this.#sql.get`SELECT type FROM fs_entries WHERE path = ${parent}`);
1697
1663
  if (!entry) {
1698
1664
  this.#ensureParentExists(parent);
1699
- this.#stmt(
1700
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1701
- VALUES (?, 'directory', 493, 0, ?)`
1702
- ).run(parent, Date.now());
1665
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1666
+ VALUES (${parent}, 'directory', 493, 0, ${Date.now()})`;
1703
1667
  } else if (entry.type !== "directory") {
1704
1668
  throw new Error(`mkdir: parent is not a directory: ${parent}`);
1705
1669
  }
1706
1670
  }
1707
1671
  #writeChunks(filePath, content) {
1708
- this.#stmt("DELETE FROM fs_chunks WHERE path = ?").run(filePath);
1672
+ this.#sql.run`DELETE FROM fs_chunks WHERE path = ${filePath}`;
1709
1673
  for (let i = 0; i < content.length; i += this.#chunkSize) {
1710
1674
  const chunk = content.slice(
1711
1675
  i,
1712
1676
  Math.min(i + this.#chunkSize, content.length)
1713
1677
  );
1714
- this.#stmt(
1715
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
1716
- ).run(filePath, Math.floor(i / this.#chunkSize), chunk);
1678
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${filePath}, ${Math.floor(i / this.#chunkSize)}, ${chunk})`;
1717
1679
  }
1718
1680
  }
1719
1681
  #chunks(filePath) {
1720
1682
  return z6.array(chunkRow).parse(
1721
- this.#stmt("SELECT chunkIndex, data FROM fs_chunks WHERE path = ?").all(
1722
- filePath
1723
- )
1683
+ this.#sql.all`SELECT chunkIndex, data FROM fs_chunks WHERE path = ${filePath}`
1724
1684
  );
1725
1685
  }
1726
1686
  #readChunks(filePath) {
1727
1687
  const rows = z6.array(dataRow).parse(
1728
- this.#stmt(
1729
- "SELECT data FROM fs_chunks WHERE path = ? ORDER BY chunkIndex"
1730
- ).all(filePath)
1688
+ this.#sql.all`SELECT data FROM fs_chunks WHERE path = ${filePath} ORDER BY chunkIndex`
1731
1689
  );
1732
1690
  if (rows.length === 0) {
1733
1691
  return new Uint8Array(0);
@@ -1746,9 +1704,7 @@ var SqliteFs = class {
1746
1704
  throw new Error(`readFile: circular symlink: ${p}`);
1747
1705
  }
1748
1706
  const entry = linkRow.optional().parse(
1749
- this.#stmt(
1750
- "SELECT type, symlinkTarget FROM fs_entries WHERE path = ?"
1751
- ).get(p)
1707
+ this.#sql.get`SELECT type, symlinkTarget FROM fs_entries WHERE path = ${p}`
1752
1708
  );
1753
1709
  if (!entry) {
1754
1710
  throw new Error(`ENOENT: no such file or directory: ${p}`);
@@ -1776,7 +1732,7 @@ var SqliteFs = class {
1776
1732
  const prefixed = this.#prefixPath(normalized);
1777
1733
  const resolved = this.#resolveSymlink(prefixed);
1778
1734
  const entry = typeRow.optional().parse(
1779
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(resolved)
1735
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${resolved}`
1780
1736
  );
1781
1737
  if (!entry) {
1782
1738
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
@@ -1793,7 +1749,7 @@ var SqliteFs = class {
1793
1749
  const prefixed = this.#prefixPath(normalized);
1794
1750
  const resolved = this.#resolveSymlink(prefixed);
1795
1751
  const entry = typeRow.optional().parse(
1796
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(resolved)
1752
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${resolved}`
1797
1753
  );
1798
1754
  if (!entry) {
1799
1755
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
@@ -1808,63 +1764,61 @@ var SqliteFs = class {
1808
1764
  const prefixed = this.#prefixPath(normalized);
1809
1765
  const encoding = typeof options === "string" ? options : options?.encoding;
1810
1766
  const data = this.#toUint8Array(content, encoding);
1811
- this.#useTransaction(() => {
1812
- this.#ensureParentExists(prefixed);
1813
- this.#stmt(
1814
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1815
- VALUES (?, 'file', 420, ?, ?)
1767
+ transaction(
1768
+ this.#db,
1769
+ () => {
1770
+ this.#ensureParentExists(prefixed);
1771
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1772
+ VALUES (${prefixed}, 'file', 420, ${data.length}, ${Date.now()})
1816
1773
  ON CONFLICT(path) DO UPDATE SET
1817
1774
  type = 'file',
1818
1775
  size = excluded.size,
1819
- mtime = excluded.mtime`
1820
- ).run(prefixed, data.length, Date.now());
1821
- this.#writeChunks(prefixed, data);
1822
- });
1776
+ mtime = excluded.mtime`;
1777
+ this.#writeChunks(prefixed, data);
1778
+ },
1779
+ { mode: "deferred" }
1780
+ );
1823
1781
  }
1824
1782
  async appendFile(filePath, content, options) {
1825
1783
  const normalized = this.#normalizePath(filePath);
1826
1784
  const prefixed = this.#prefixPath(normalized);
1827
1785
  const encoding = typeof options === "string" ? options : options?.encoding;
1828
1786
  const newData = this.#toUint8Array(content, encoding);
1829
- this.#useTransaction(() => {
1830
- this.#ensureParentExists(prefixed);
1831
- const entry = typeRow.optional().parse(
1832
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(
1833
- prefixed
1834
- )
1835
- );
1836
- if (entry && entry.type !== "file") {
1837
- throw new Error(`appendFile: not a file: ${filePath}`);
1838
- }
1839
- const existing = entry ? this.#readChunks(prefixed) : new Uint8Array(0);
1840
- const combined = new Uint8Array(existing.length + newData.length);
1841
- combined.set(existing, 0);
1842
- combined.set(newData, existing.length);
1843
- this.#stmt(
1844
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1845
- VALUES (?, 'file', 420, ?, ?)
1787
+ transaction(
1788
+ this.#db,
1789
+ () => {
1790
+ this.#ensureParentExists(prefixed);
1791
+ const entry = typeRow.optional().parse(
1792
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${prefixed}`
1793
+ );
1794
+ if (entry && entry.type !== "file") {
1795
+ throw new Error(`appendFile: not a file: ${filePath}`);
1796
+ }
1797
+ const existing = entry ? this.#readChunks(prefixed) : new Uint8Array(0);
1798
+ const combined = new Uint8Array(existing.length + newData.length);
1799
+ combined.set(existing, 0);
1800
+ combined.set(newData, existing.length);
1801
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1802
+ VALUES (${prefixed}, 'file', 420, ${combined.length}, ${Date.now()})
1846
1803
  ON CONFLICT(path) DO UPDATE SET
1847
1804
  size = excluded.size,
1848
- mtime = excluded.mtime`
1849
- ).run(prefixed, combined.length, Date.now());
1850
- this.#writeChunks(prefixed, combined);
1851
- });
1805
+ mtime = excluded.mtime`;
1806
+ this.#writeChunks(prefixed, combined);
1807
+ },
1808
+ { mode: "deferred" }
1809
+ );
1852
1810
  }
1853
1811
  async exists(filePath) {
1854
1812
  const normalized = this.#normalizePath(filePath);
1855
1813
  const prefixed = this.#prefixPath(normalized);
1856
- const row = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
1857
- prefixed
1858
- );
1814
+ const row = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${prefixed}`;
1859
1815
  return row !== void 0;
1860
1816
  }
1861
1817
  async stat(filePath) {
1862
1818
  const normalized = this.#normalizePath(filePath);
1863
1819
  const prefixed = this.#prefixPath(normalized);
1864
1820
  const resolved = this.#resolveSymlink(prefixed);
1865
- const entry = entryRow.optional().parse(
1866
- this.#stmt("SELECT * FROM fs_entries WHERE path = ?").get(resolved)
1867
- );
1821
+ const entry = entryRow.optional().parse(this.#sql.get`SELECT * FROM fs_entries WHERE path = ${resolved}`);
1868
1822
  if (!entry) {
1869
1823
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
1870
1824
  }
@@ -1881,9 +1835,7 @@ var SqliteFs = class {
1881
1835
  async lstat(filePath) {
1882
1836
  const normalized = this.#normalizePath(filePath);
1883
1837
  const prefixed = this.#prefixPath(normalized);
1884
- const entry = entryRow.optional().parse(
1885
- this.#stmt("SELECT * FROM fs_entries WHERE path = ?").get(prefixed)
1886
- );
1838
+ const entry = entryRow.optional().parse(this.#sql.get`SELECT * FROM fs_entries WHERE path = ${prefixed}`);
1887
1839
  if (!entry) {
1888
1840
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
1889
1841
  }
@@ -1900,7 +1852,7 @@ var SqliteFs = class {
1900
1852
  const normalized = this.#normalizePath(dirPath);
1901
1853
  const prefixed = this.#prefixPath(normalized);
1902
1854
  const existing = typeRow.optional().parse(
1903
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(prefixed)
1855
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${prefixed}`
1904
1856
  );
1905
1857
  if (existing) {
1906
1858
  if (options?.recursive) {
@@ -1908,54 +1860,50 @@ var SqliteFs = class {
1908
1860
  }
1909
1861
  throw new Error(`EEXIST: file already exists: ${dirPath}`);
1910
1862
  }
1911
- this.#useTransaction(() => {
1912
- if (options?.recursive) {
1913
- const rootPath = this.#root || "/";
1914
- const relativePath = path2.posix.relative(rootPath, prefixed);
1915
- const segments = relativePath.split("/").filter(Boolean);
1916
- let currentPath = rootPath;
1917
- for (const segment of segments) {
1918
- currentPath = path2.posix.join(currentPath, segment);
1919
- const exists = typeRow.optional().parse(
1920
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(
1921
- currentPath
1922
- )
1863
+ transaction(
1864
+ this.#db,
1865
+ () => {
1866
+ if (options?.recursive) {
1867
+ const rootPath = this.#root || "/";
1868
+ const relativePath = path2.posix.relative(rootPath, prefixed);
1869
+ const segments = relativePath.split("/").filter(Boolean);
1870
+ let currentPath = rootPath;
1871
+ for (const segment of segments) {
1872
+ currentPath = path2.posix.join(currentPath, segment);
1873
+ const exists = typeRow.optional().parse(
1874
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${currentPath}`
1875
+ );
1876
+ if (!exists) {
1877
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1878
+ VALUES (${currentPath}, 'directory', 493, 0, ${Date.now()})`;
1879
+ } else if (exists.type !== "directory") {
1880
+ throw new Error(`mkdir: not a directory: ${currentPath}`);
1881
+ }
1882
+ }
1883
+ } else {
1884
+ const parent = this.#dirname(prefixed);
1885
+ const parentEntry = typeRow.optional().parse(
1886
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${parent}`
1923
1887
  );
1924
- if (!exists) {
1925
- this.#stmt(
1926
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1927
- VALUES (?, 'directory', 493, 0, ?)`
1928
- ).run(currentPath, Date.now());
1929
- } else if (exists.type !== "directory") {
1930
- throw new Error(`mkdir: not a directory: ${currentPath}`);
1888
+ if (!parentEntry) {
1889
+ throw new Error(`mkdir: parent does not exist: ${parent}`);
1931
1890
  }
1891
+ if (parentEntry.type !== "directory") {
1892
+ throw new Error(`mkdir: parent is not a directory: ${parent}`);
1893
+ }
1894
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
1895
+ VALUES (${prefixed}, 'directory', 493, 0, ${Date.now()})`;
1932
1896
  }
1933
- } else {
1934
- const parent = this.#dirname(prefixed);
1935
- const parentEntry = typeRow.optional().parse(
1936
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(
1937
- parent
1938
- )
1939
- );
1940
- if (!parentEntry) {
1941
- throw new Error(`mkdir: parent does not exist: ${parent}`);
1942
- }
1943
- if (parentEntry.type !== "directory") {
1944
- throw new Error(`mkdir: parent is not a directory: ${parent}`);
1945
- }
1946
- this.#stmt(
1947
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
1948
- VALUES (?, 'directory', 493, 0, ?)`
1949
- ).run(prefixed, Date.now());
1950
- }
1951
- });
1897
+ },
1898
+ { mode: "deferred" }
1899
+ );
1952
1900
  }
1953
1901
  async readdir(dirPath) {
1954
1902
  const normalized = this.#normalizePath(dirPath);
1955
1903
  const prefixed = this.#prefixPath(normalized);
1956
1904
  const resolved = this.#resolveSymlink(prefixed);
1957
1905
  const entry = typeRow.optional().parse(
1958
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(resolved)
1906
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${resolved}`
1959
1907
  );
1960
1908
  if (!entry) {
1961
1909
  throw new Error(`ENOENT: no such file or directory: ${dirPath}`);
@@ -1965,12 +1913,10 @@ var SqliteFs = class {
1965
1913
  }
1966
1914
  const prefix = resolved === "/" ? "/" : resolved + "/";
1967
1915
  const rows = z6.array(pathRow).parse(
1968
- this.#stmt(
1969
- `SELECT path FROM fs_entries
1970
- WHERE path LIKE ? || '%'
1971
- AND path != ?
1972
- AND path NOT LIKE ? || '%/%'`
1973
- ).all(prefix, resolved, prefix)
1916
+ this.#sql.all`SELECT path FROM fs_entries
1917
+ WHERE path LIKE ${prefix} || '%'
1918
+ AND path != ${resolved}
1919
+ AND path NOT LIKE ${prefix} || '%/%'`
1974
1920
  );
1975
1921
  return rows.map((row) => path2.posix.basename(row.path));
1976
1922
  }
@@ -1979,7 +1925,7 @@ var SqliteFs = class {
1979
1925
  const prefixed = this.#prefixPath(normalized);
1980
1926
  const resolved = this.#resolveSymlink(prefixed);
1981
1927
  const entry = typeRow.optional().parse(
1982
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(resolved)
1928
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${resolved}`
1983
1929
  );
1984
1930
  if (!entry) {
1985
1931
  throw new Error(`ENOENT: no such file or directory: ${dirPath}`);
@@ -1989,12 +1935,10 @@ var SqliteFs = class {
1989
1935
  }
1990
1936
  const prefix = resolved === "/" ? "/" : resolved + "/";
1991
1937
  const rows = z6.array(pathTypeRow).parse(
1992
- this.#stmt(
1993
- `SELECT path, type FROM fs_entries
1994
- WHERE path LIKE ? || '%'
1995
- AND path != ?
1996
- AND path NOT LIKE ? || '%/%'`
1997
- ).all(prefix, resolved, prefix)
1938
+ this.#sql.all`SELECT path, type FROM fs_entries
1939
+ WHERE path LIKE ${prefix} || '%'
1940
+ AND path != ${resolved}
1941
+ AND path NOT LIKE ${prefix} || '%/%'`
1998
1942
  );
1999
1943
  return rows.map((row) => ({
2000
1944
  name: path2.posix.basename(row.path),
@@ -2007,7 +1951,7 @@ var SqliteFs = class {
2007
1951
  const normalized = this.#normalizePath(filePath);
2008
1952
  const prefixed = this.#prefixPath(normalized);
2009
1953
  const entry = typeRow.optional().parse(
2010
- this.#stmt("SELECT type FROM fs_entries WHERE path = ?").get(prefixed)
1954
+ this.#sql.get`SELECT type FROM fs_entries WHERE path = ${prefixed}`
2011
1955
  );
2012
1956
  if (!entry) {
2013
1957
  if (options?.force) {
@@ -2015,21 +1959,21 @@ var SqliteFs = class {
2015
1959
  }
2016
1960
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
2017
1961
  }
2018
- this.#useTransaction(() => {
2019
- if (entry.type === "directory") {
2020
- const children = this.#stmt(
2021
- `SELECT 1 FROM fs_entries WHERE path LIKE ? || '/%' LIMIT 1`
2022
- ).get(prefixed);
2023
- if (children && !options?.recursive) {
2024
- throw new Error(`ENOTEMPTY: directory not empty: ${filePath}`);
1962
+ transaction(
1963
+ this.#db,
1964
+ () => {
1965
+ if (entry.type === "directory") {
1966
+ const children = this.#sql.get`SELECT 1 FROM fs_entries WHERE path LIKE ${prefixed} || '/%' LIMIT 1`;
1967
+ if (children && !options?.recursive) {
1968
+ throw new Error(`ENOTEMPTY: directory not empty: ${filePath}`);
1969
+ }
1970
+ this.#sql.run`DELETE FROM fs_entries WHERE path = ${prefixed} OR path LIKE ${prefixed} || '/%'`;
1971
+ } else {
1972
+ this.#sql.run`DELETE FROM fs_entries WHERE path = ${prefixed}`;
2025
1973
  }
2026
- this.#stmt(
2027
- `DELETE FROM fs_entries WHERE path = ? OR path LIKE ? || '/%'`
2028
- ).run(prefixed, prefixed);
2029
- } else {
2030
- this.#stmt("DELETE FROM fs_entries WHERE path = ?").run(prefixed);
2031
- }
2032
- });
1974
+ },
1975
+ { mode: "deferred" }
1976
+ );
2033
1977
  }
2034
1978
  async cp(src, dest, options) {
2035
1979
  const srcNormalized = this.#normalizePath(src);
@@ -2037,7 +1981,7 @@ var SqliteFs = class {
2037
1981
  const srcPrefixed = this.#prefixPath(srcNormalized);
2038
1982
  const destPrefixed = this.#prefixPath(destNormalized);
2039
1983
  const srcEntry = entryRow.optional().parse(
2040
- this.#stmt("SELECT * FROM fs_entries WHERE path = ?").get(srcPrefixed)
1984
+ this.#sql.get`SELECT * FROM fs_entries WHERE path = ${srcPrefixed}`
2041
1985
  );
2042
1986
  if (!srcEntry) {
2043
1987
  throw new Error(`ENOENT: no such file or directory: ${src}`);
@@ -2045,60 +1989,40 @@ var SqliteFs = class {
2045
1989
  if (srcEntry.type === "directory" && !options?.recursive) {
2046
1990
  throw new Error(`cp: -r not specified; omitting directory: ${src}`);
2047
1991
  }
2048
- this.#useTransaction(() => {
2049
- this.#ensureParentExists(destPrefixed);
2050
- if (srcEntry.type === "directory") {
2051
- const allEntries = z6.array(entryRow).parse(
2052
- this.#stmt(
2053
- `SELECT * FROM fs_entries WHERE path = ? OR path LIKE ? || '/%'`
2054
- ).all(srcPrefixed, srcPrefixed)
2055
- );
2056
- for (const entry of allEntries) {
2057
- const relativePath = path2.posix.relative(srcPrefixed, entry.path);
2058
- const newPath = path2.posix.join(destPrefixed, relativePath);
2059
- this.#stmt(
2060
- `INSERT OR REPLACE INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2061
- VALUES (?, ?, ?, ?, ?, ?)`
2062
- ).run(
2063
- newPath,
2064
- entry.type,
2065
- entry.mode,
2066
- entry.size,
2067
- Date.now(),
2068
- entry.symlinkTarget
1992
+ transaction(
1993
+ this.#db,
1994
+ () => {
1995
+ this.#ensureParentExists(destPrefixed);
1996
+ if (srcEntry.type === "directory") {
1997
+ const allEntries = z6.array(entryRow).parse(
1998
+ this.#sql.all`SELECT * FROM fs_entries WHERE path = ${srcPrefixed} OR path LIKE ${srcPrefixed} || '/%'`
2069
1999
  );
2070
- if (entry.type === "file") {
2071
- const chunks = this.#chunks(entry.path);
2072
- for (const chunk of chunks) {
2073
- this.#stmt(
2074
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
2075
- ).run(newPath, chunk.chunkIndex, chunk.data);
2000
+ for (const entry of allEntries) {
2001
+ const relativePath = path2.posix.relative(srcPrefixed, entry.path);
2002
+ const newPath = path2.posix.join(destPrefixed, relativePath);
2003
+ this.#sql.run`INSERT OR REPLACE INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2004
+ VALUES (${newPath}, ${entry.type}, ${entry.mode}, ${entry.size}, ${Date.now()}, ${entry.symlinkTarget})`;
2005
+ if (entry.type === "file") {
2006
+ const chunks = this.#chunks(entry.path);
2007
+ for (const chunk of chunks) {
2008
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${newPath}, ${chunk.chunkIndex}, ${chunk.data})`;
2009
+ }
2076
2010
  }
2077
2011
  }
2078
- }
2079
- } else {
2080
- this.#stmt(
2081
- `INSERT OR REPLACE INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2082
- VALUES (?, ?, ?, ?, ?, ?)`
2083
- ).run(
2084
- destPrefixed,
2085
- srcEntry.type,
2086
- srcEntry.mode,
2087
- srcEntry.size,
2088
- Date.now(),
2089
- srcEntry.symlinkTarget
2090
- );
2091
- if (srcEntry.type === "file") {
2092
- const chunks = this.#chunks(srcPrefixed);
2093
- this.#stmt("DELETE FROM fs_chunks WHERE path = ?").run(destPrefixed);
2094
- for (const chunk of chunks) {
2095
- this.#stmt(
2096
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
2097
- ).run(destPrefixed, chunk.chunkIndex, chunk.data);
2012
+ } else {
2013
+ this.#sql.run`INSERT OR REPLACE INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2014
+ VALUES (${destPrefixed}, ${srcEntry.type}, ${srcEntry.mode}, ${srcEntry.size}, ${Date.now()}, ${srcEntry.symlinkTarget})`;
2015
+ if (srcEntry.type === "file") {
2016
+ const chunks = this.#chunks(srcPrefixed);
2017
+ this.#sql.run`DELETE FROM fs_chunks WHERE path = ${destPrefixed}`;
2018
+ for (const chunk of chunks) {
2019
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${destPrefixed}, ${chunk.chunkIndex}, ${chunk.data})`;
2020
+ }
2098
2021
  }
2099
2022
  }
2100
- }
2101
- });
2023
+ },
2024
+ { mode: "deferred" }
2025
+ );
2102
2026
  }
2103
2027
  async mv(src, dest) {
2104
2028
  const srcNormalized = this.#normalizePath(src);
@@ -2106,83 +2030,59 @@ var SqliteFs = class {
2106
2030
  const srcPrefixed = this.#prefixPath(srcNormalized);
2107
2031
  const destPrefixed = this.#prefixPath(destNormalized);
2108
2032
  const srcEntry = entryRow.optional().parse(
2109
- this.#stmt("SELECT * FROM fs_entries WHERE path = ?").get(srcPrefixed)
2033
+ this.#sql.get`SELECT * FROM fs_entries WHERE path = ${srcPrefixed}`
2110
2034
  );
2111
2035
  if (!srcEntry) {
2112
2036
  throw new Error(`ENOENT: no such file or directory: ${src}`);
2113
2037
  }
2114
- this.#useTransaction(() => {
2115
- this.#ensureParentExists(destPrefixed);
2116
- if (srcEntry.type === "directory") {
2117
- const allEntries = z6.array(entryRow).parse(
2118
- this.#stmt(
2119
- `SELECT * FROM fs_entries WHERE path = ? OR path LIKE ? || '/%' ORDER BY path DESC`
2120
- ).all(srcPrefixed, srcPrefixed)
2121
- );
2122
- for (const entry of [...allEntries].reverse()) {
2123
- const relativePath = path2.posix.relative(srcPrefixed, entry.path);
2124
- const newPath = path2.posix.join(destPrefixed, relativePath);
2125
- this.#stmt(
2126
- `INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2127
- VALUES (?, ?, ?, ?, ?, ?)`
2128
- ).run(
2129
- newPath,
2130
- entry.type,
2131
- entry.mode,
2132
- entry.size,
2133
- Date.now(),
2134
- entry.symlinkTarget
2038
+ transaction(
2039
+ this.#db,
2040
+ () => {
2041
+ this.#ensureParentExists(destPrefixed);
2042
+ if (srcEntry.type === "directory") {
2043
+ const allEntries = z6.array(entryRow).parse(
2044
+ this.#sql.all`SELECT * FROM fs_entries WHERE path = ${srcPrefixed} OR path LIKE ${srcPrefixed} || '/%' ORDER BY path DESC`
2135
2045
  );
2136
- if (entry.type === "file") {
2137
- const chunks = this.#chunks(entry.path);
2138
- for (const chunk of chunks) {
2139
- this.#stmt(
2140
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
2141
- ).run(newPath, chunk.chunkIndex, chunk.data);
2046
+ for (const entry of [...allEntries].reverse()) {
2047
+ const relativePath = path2.posix.relative(srcPrefixed, entry.path);
2048
+ const newPath = path2.posix.join(destPrefixed, relativePath);
2049
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2050
+ VALUES (${newPath}, ${entry.type}, ${entry.mode}, ${entry.size}, ${Date.now()}, ${entry.symlinkTarget})`;
2051
+ if (entry.type === "file") {
2052
+ const chunks = this.#chunks(entry.path);
2053
+ for (const chunk of chunks) {
2054
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${newPath}, ${chunk.chunkIndex}, ${chunk.data})`;
2055
+ }
2142
2056
  }
2143
2057
  }
2144
- }
2145
- this.#stmt(
2146
- `DELETE FROM fs_entries WHERE path = ? OR path LIKE ? || '/%'`
2147
- ).run(srcPrefixed, srcPrefixed);
2148
- } else {
2149
- this.#stmt(
2150
- `INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2151
- VALUES (?, ?, ?, ?, ?, ?)`
2152
- ).run(
2153
- destPrefixed,
2154
- srcEntry.type,
2155
- srcEntry.mode,
2156
- srcEntry.size,
2157
- Date.now(),
2158
- srcEntry.symlinkTarget
2159
- );
2160
- if (srcEntry.type === "file") {
2161
- const chunks = this.#chunks(srcPrefixed);
2162
- for (const chunk of chunks) {
2163
- this.#stmt(
2164
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
2165
- ).run(destPrefixed, chunk.chunkIndex, chunk.data);
2058
+ this.#sql.run`DELETE FROM fs_entries WHERE path = ${srcPrefixed} OR path LIKE ${srcPrefixed} || '/%'`;
2059
+ } else {
2060
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2061
+ VALUES (${destPrefixed}, ${srcEntry.type}, ${srcEntry.mode}, ${srcEntry.size}, ${Date.now()}, ${srcEntry.symlinkTarget})`;
2062
+ if (srcEntry.type === "file") {
2063
+ const chunks = this.#chunks(srcPrefixed);
2064
+ for (const chunk of chunks) {
2065
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${destPrefixed}, ${chunk.chunkIndex}, ${chunk.data})`;
2066
+ }
2166
2067
  }
2068
+ this.#sql.run`DELETE FROM fs_entries WHERE path = ${srcPrefixed}`;
2167
2069
  }
2168
- this.#stmt("DELETE FROM fs_entries WHERE path = ?").run(srcPrefixed);
2169
- }
2170
- });
2070
+ },
2071
+ { mode: "deferred" }
2072
+ );
2171
2073
  }
2172
2074
  resolvePath(base, relativePath) {
2173
2075
  return path2.posix.resolve(base, relativePath);
2174
2076
  }
2175
2077
  getAllPaths() {
2176
- const rows = z6.array(pathRow).parse(this.#stmt("SELECT path FROM fs_entries ORDER BY path").all());
2078
+ const rows = z6.array(pathRow).parse(this.#sql.all`SELECT path FROM fs_entries ORDER BY path`);
2177
2079
  return rows.map((row) => row.path);
2178
2080
  }
2179
2081
  async realpath(filePath) {
2180
2082
  const normalized = this.#normalizePath(filePath);
2181
2083
  const prefixed = this.#prefixPath(normalized);
2182
2084
  const resolved = this.#resolveSymlink(prefixed);
2183
- const exists = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
2184
- resolved
2185
- );
2085
+ const exists = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${resolved}`;
2186
2086
  if (!exists) {
2187
2087
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
2188
2088
  }
@@ -2192,9 +2092,7 @@ var SqliteFs = class {
2192
2092
  const normalized = this.#normalizePath(filePath);
2193
2093
  const prefixed = this.#prefixPath(normalized);
2194
2094
  const resolved = this.#resolveSymlink(prefixed);
2195
- const result = this.#stmt(
2196
- "UPDATE fs_entries SET mtime = ? WHERE path = ?"
2197
- ).run(mtime.getTime(), resolved);
2095
+ const result = this.#sql.run`UPDATE fs_entries SET mtime = ${mtime.getTime()} WHERE path = ${resolved}`;
2198
2096
  if (result.changes === 0) {
2199
2097
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
2200
2098
  }
@@ -2202,9 +2100,7 @@ var SqliteFs = class {
2202
2100
  async chmod(filePath, mode) {
2203
2101
  const normalized = this.#normalizePath(filePath);
2204
2102
  const prefixed = this.#prefixPath(normalized);
2205
- const result = this.#stmt(
2206
- "UPDATE fs_entries SET mode = ? WHERE path = ?"
2207
- ).run(mode, prefixed);
2103
+ const result = this.#sql.run`UPDATE fs_entries SET mode = ${mode} WHERE path = ${prefixed}`;
2208
2104
  if (result.changes === 0) {
2209
2105
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
2210
2106
  }
@@ -2212,19 +2108,19 @@ var SqliteFs = class {
2212
2108
  async symlink(target, linkPath) {
2213
2109
  const normalized = this.#normalizePath(linkPath);
2214
2110
  const prefixed = this.#prefixPath(normalized);
2215
- const existing = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
2216
- prefixed
2217
- );
2111
+ const existing = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${prefixed}`;
2218
2112
  if (existing) {
2219
2113
  throw new Error(`EEXIST: file already exists: ${linkPath}`);
2220
2114
  }
2221
- this.#useTransaction(() => {
2222
- this.#ensureParentExists(prefixed);
2223
- this.#stmt(
2224
- `INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2225
- VALUES (?, 'symlink', 511, 0, ?, ?)`
2226
- ).run(prefixed, Date.now(), target);
2227
- });
2115
+ transaction(
2116
+ this.#db,
2117
+ () => {
2118
+ this.#ensureParentExists(prefixed);
2119
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2120
+ VALUES (${prefixed}, 'symlink', 511, 0, ${Date.now()}, ${target})`;
2121
+ },
2122
+ { mode: "deferred" }
2123
+ );
2228
2124
  }
2229
2125
  async link(existingPath, newPath) {
2230
2126
  const srcNormalized = this.#normalizePath(existingPath);
@@ -2232,7 +2128,7 @@ var SqliteFs = class {
2232
2128
  const srcPrefixed = this.#prefixPath(srcNormalized);
2233
2129
  const destPrefixed = this.#prefixPath(destNormalized);
2234
2130
  const srcEntry = entryRow.optional().parse(
2235
- this.#stmt("SELECT * FROM fs_entries WHERE path = ?").get(srcPrefixed)
2131
+ this.#sql.get`SELECT * FROM fs_entries WHERE path = ${srcPrefixed}`
2236
2132
  );
2237
2133
  if (!srcEntry) {
2238
2134
  throw new Error(`ENOENT: no such file or directory: ${existingPath}`);
@@ -2240,33 +2136,29 @@ var SqliteFs = class {
2240
2136
  if (srcEntry.type !== "file") {
2241
2137
  throw new Error(`link: not supported for directories: ${existingPath}`);
2242
2138
  }
2243
- const existing = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
2244
- destPrefixed
2245
- );
2139
+ const existing = this.#sql.get`SELECT 1 FROM fs_entries WHERE path = ${destPrefixed}`;
2246
2140
  if (existing) {
2247
2141
  throw new Error(`EEXIST: file already exists: ${newPath}`);
2248
2142
  }
2249
- this.#useTransaction(() => {
2250
- this.#ensureParentExists(destPrefixed);
2251
- this.#stmt(
2252
- `INSERT INTO fs_entries (path, type, mode, size, mtime)
2253
- VALUES (?, 'file', ?, ?, ?)`
2254
- ).run(destPrefixed, srcEntry.mode, srcEntry.size, Date.now());
2255
- const chunks = this.#chunks(srcPrefixed);
2256
- for (const chunk of chunks) {
2257
- this.#stmt(
2258
- "INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (?, ?, ?)"
2259
- ).run(destPrefixed, chunk.chunkIndex, chunk.data);
2260
- }
2261
- });
2143
+ transaction(
2144
+ this.#db,
2145
+ () => {
2146
+ this.#ensureParentExists(destPrefixed);
2147
+ this.#sql.run`INSERT INTO fs_entries (path, type, mode, size, mtime)
2148
+ VALUES (${destPrefixed}, 'file', ${srcEntry.mode}, ${srcEntry.size}, ${Date.now()})`;
2149
+ const chunks = this.#chunks(srcPrefixed);
2150
+ for (const chunk of chunks) {
2151
+ this.#sql.run`INSERT INTO fs_chunks (path, chunkIndex, data) VALUES (${destPrefixed}, ${chunk.chunkIndex}, ${chunk.data})`;
2152
+ }
2153
+ },
2154
+ { mode: "deferred" }
2155
+ );
2262
2156
  }
2263
2157
  async readlink(linkPath) {
2264
2158
  const normalized = this.#normalizePath(linkPath);
2265
2159
  const prefixed = this.#prefixPath(normalized);
2266
2160
  const entry = linkRow.optional().parse(
2267
- this.#stmt(
2268
- "SELECT type, symlinkTarget FROM fs_entries WHERE path = ?"
2269
- ).get(prefixed)
2161
+ this.#sql.get`SELECT type, symlinkTarget FROM fs_entries WHERE path = ${prefixed}`
2270
2162
  );
2271
2163
  if (!entry) {
2272
2164
  throw new Error(`ENOENT: no such file or directory: ${linkPath}`);
@@ -2313,6 +2205,38 @@ GO
2313
2205
  `;
2314
2206
  }
2315
2207
 
2208
+ // packages/text2sql/src/lib/fs/mssql/sqlserver-schema-lock.ts
2209
+ async function withSqlServerSchemaLock(mssql, pool, schema, run) {
2210
+ const holder = new mssql.Transaction(pool);
2211
+ await holder.begin();
2212
+ let result;
2213
+ try {
2214
+ const lock = new mssql.Request(holder);
2215
+ lock.input(
2216
+ "resource",
2217
+ mssql.NVarChar(255),
2218
+ `deepagents:schema-ddl:${schema}`
2219
+ );
2220
+ const { recordset } = await lock.query(`
2221
+ DECLARE @status int;
2222
+ EXEC @status = sp_getapplock @Resource = @resource, @LockMode = 'Exclusive', @LockOwner = 'Transaction', @LockTimeout = -1;
2223
+ SELECT @status AS status;
2224
+ `);
2225
+ if (recordset[0].status < 0) {
2226
+ throw new Error(
2227
+ `Could not lock the DDL of schema "${schema}": sp_getapplock returned ${recordset[0].status}.`
2228
+ );
2229
+ }
2230
+ result = await run();
2231
+ } catch (error) {
2232
+ await holder.rollback().catch(() => {
2233
+ });
2234
+ throw error;
2235
+ }
2236
+ await holder.rollback();
2237
+ return result;
2238
+ }
2239
+
2316
2240
  // packages/text2sql/src/lib/fs/mssql/mssql-fs.ts
2317
2241
  var entryRow2 = z7.object({
2318
2242
  path: z7.string(),
@@ -2393,71 +2317,49 @@ var MssqlFs = class _MssqlFs {
2393
2317
  if (this.#ownsPool) {
2394
2318
  await this.#pool.connect();
2395
2319
  }
2396
- const schemaReq = this.#pool.request();
2397
- schemaReq.input("schema", this.#schema);
2398
- await schemaReq.query(`
2399
- IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = @schema)
2400
- BEGIN
2401
- DECLARE @sql NVARCHAR(MAX) = N'CREATE SCHEMA ' + QUOTENAME(@schema);
2402
- EXEC sp_executesql @sql;
2403
- END
2404
- `);
2405
- const ddl = mssqlFsDDL(this.#schema);
2406
- const batches = ddl.split(/\bGO\b/i).filter((b) => b.trim());
2407
- for (const batch of batches) {
2408
- if (batch.trim()) {
2409
- await this.#pool.request().batch(batch);
2320
+ await withSqlServerSchemaLock(
2321
+ _MssqlFs.#requireMssql(),
2322
+ this.#pool,
2323
+ this.#schema,
2324
+ async () => {
2325
+ const schemaReq = this.#pool.request();
2326
+ schemaReq.input("schema", this.#schema);
2327
+ await schemaReq.query(`
2328
+ IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = @schema)
2329
+ BEGIN
2330
+ DECLARE @sql NVARCHAR(MAX) = N'CREATE SCHEMA ' + QUOTENAME(@schema);
2331
+ EXEC sp_executesql @sql;
2332
+ END
2333
+ `);
2334
+ const ddl = mssqlFsDDL(this.#schema);
2335
+ const batches = ddl.split(/\bGO\b/i).filter((b) => b.trim());
2336
+ for (const batch of batches) {
2337
+ await this.#pool.request().batch(batch);
2338
+ }
2339
+ await this.#ensureDirectory("/");
2340
+ if (this.#root) {
2341
+ await this.#createParentDirs(this.#root);
2342
+ await this.#ensureDirectory(this.#root);
2343
+ }
2410
2344
  }
2411
- }
2412
- const rootSlashExists = rowsOf(
2413
- existsRow,
2414
- await this.#query(
2415
- `SELECT CASE WHEN EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = '/') THEN 1 ELSE 0 END as [exists]`
2416
- )
2417
2345
  );
2418
- if (rootSlashExists[0].exists === 0) {
2419
- await this.#exec(
2420
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES ('/', 'directory', 493, 0, @p0)`,
2421
- [Date.now()]
2422
- );
2423
- }
2424
- if (this.#root) {
2425
- await this.#createParentDirs(this.#root);
2426
- const rootExists = rowsOf(
2427
- existsRow,
2428
- await this.#query(
2429
- `SELECT CASE WHEN EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = @p0) THEN 1 ELSE 0 END as [exists]`,
2430
- [this.#root]
2431
- )
2432
- );
2433
- if (rootExists[0].exists === 0) {
2434
- await this.#exec(
2435
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES (@p0, 'directory', 493, 0, @p1)`,
2436
- [this.#root, Date.now()]
2437
- );
2438
- }
2439
- }
2440
2346
  }
2441
2347
  async #createParentDirs(p) {
2442
2348
  const segments = p.split("/").filter(Boolean);
2443
2349
  let currentPath = "/";
2444
2350
  for (let i = 0; i < segments.length - 1; i++) {
2445
2351
  currentPath = path3.posix.join(currentPath, segments[i]);
2446
- const exists = rowsOf(
2447
- existsRow,
2448
- await this.#query(
2449
- `SELECT CASE WHEN EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = @p0) THEN 1 ELSE 0 END as [exists]`,
2450
- [currentPath]
2451
- )
2452
- );
2453
- if (exists[0].exists === 0) {
2454
- await this.#exec(
2455
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES (@p0, 'directory', 493, 0, @p1)`,
2456
- [currentPath, Date.now()]
2457
- );
2458
- }
2352
+ await this.#ensureDirectory(currentPath);
2459
2353
  }
2460
2354
  }
2355
+ async #ensureDirectory(p) {
2356
+ await this.#exec(
2357
+ `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime)
2358
+ SELECT @p0, 'directory', 493, 0, @p1
2359
+ WHERE NOT EXISTS (SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = @p0)`,
2360
+ [p, Date.now()]
2361
+ );
2362
+ }
2461
2363
  #query(sql, params) {
2462
2364
  const request = this.#pool.request();
2463
2365
  params?.forEach((value, index2) => {
@@ -2475,14 +2377,14 @@ var MssqlFs = class _MssqlFs {
2475
2377
  }
2476
2378
  async #useTransaction(fn) {
2477
2379
  const mssql = _MssqlFs.#requireMssql();
2478
- const transaction = new mssql.Transaction(this.#pool);
2380
+ const transaction2 = new mssql.Transaction(this.#pool);
2479
2381
  try {
2480
- await transaction.begin();
2481
- const result = await fn(transaction);
2482
- await transaction.commit();
2382
+ await transaction2.begin();
2383
+ const result = await fn(transaction2);
2384
+ await transaction2.commit();
2483
2385
  return result;
2484
2386
  } catch (error) {
2485
- await transaction.rollback();
2387
+ await transaction2.rollback();
2486
2388
  throw error;
2487
2389
  }
2488
2390
  }
@@ -2517,11 +2419,11 @@ var MssqlFs = class _MssqlFs {
2517
2419
  const dir = path3.posix.dirname(p);
2518
2420
  return dir === "" ? "/" : dir;
2519
2421
  }
2520
- async #ensureParentExists(filePath, transaction) {
2422
+ async #ensureParentExists(filePath, transaction2) {
2521
2423
  const parent = this.#dirname(filePath);
2522
2424
  const rootPath = this.#root || "/";
2523
2425
  if (parent === rootPath || parent === "/") return;
2524
- const request = transaction.request();
2426
+ const request = transaction2.request();
2525
2427
  request.input("p0", parent);
2526
2428
  const [entry] = rowsOf(
2527
2429
  typeRow2,
@@ -2530,8 +2432,8 @@ var MssqlFs = class _MssqlFs {
2530
2432
  )
2531
2433
  );
2532
2434
  if (!entry) {
2533
- await this.#ensureParentExists(parent, transaction);
2534
- const insertReq = transaction.request();
2435
+ await this.#ensureParentExists(parent, transaction2);
2436
+ const insertReq = transaction2.request();
2535
2437
  insertReq.input("p0", parent);
2536
2438
  insertReq.input("p1", Date.now());
2537
2439
  await insertReq.query(
@@ -2541,8 +2443,8 @@ var MssqlFs = class _MssqlFs {
2541
2443
  throw new Error(`mkdir: parent is not a directory: ${parent}`);
2542
2444
  }
2543
2445
  }
2544
- async #writeChunks(filePath, content, transaction) {
2545
- const deleteReq = transaction.request();
2446
+ async #writeChunks(filePath, content, transaction2) {
2447
+ const deleteReq = transaction2.request();
2546
2448
  deleteReq.input("p0", filePath);
2547
2449
  await deleteReq.query(
2548
2450
  `DELETE FROM ${this.#t("fs_chunks")} WHERE path = @p0`
@@ -2552,7 +2454,7 @@ var MssqlFs = class _MssqlFs {
2552
2454
  i,
2553
2455
  Math.min(i + this.#chunkSize, content.length)
2554
2456
  );
2555
- const insertReq = transaction.request();
2457
+ const insertReq = transaction2.request();
2556
2458
  insertReq.input("p0", filePath);
2557
2459
  insertReq.input("p1", Math.floor(i / this.#chunkSize));
2558
2460
  insertReq.input("p2", Buffer.from(chunk));
@@ -2561,11 +2463,11 @@ var MssqlFs = class _MssqlFs {
2561
2463
  );
2562
2464
  }
2563
2465
  }
2564
- async #readChunks(filePath, transaction) {
2466
+ async #readChunks(filePath, transaction2) {
2565
2467
  const sql = `SELECT data FROM ${this.#t("fs_chunks")} WHERE path = @p0 ORDER BY chunkIndex`;
2566
2468
  const rows = rowsOf(
2567
2469
  dataRow2,
2568
- transaction ? await transaction.request().input("p0", filePath).query(sql) : await this.#query(sql, [filePath])
2470
+ transaction2 ? await transaction2.request().input("p0", filePath).query(sql) : await this.#query(sql, [filePath])
2569
2471
  );
2570
2472
  if (rows.length === 0) {
2571
2473
  return new Uint8Array(0);
@@ -2661,9 +2563,9 @@ var MssqlFs = class _MssqlFs {
2661
2563
  const prefixed = this.#prefixPath(normalized);
2662
2564
  const encoding = typeof options === "string" ? options : options?.encoding;
2663
2565
  const data = this.#toUint8Array(content, encoding);
2664
- await this.#useTransaction(async (transaction) => {
2665
- await this.#ensureParentExists(prefixed, transaction);
2666
- const request = transaction.request();
2566
+ await this.#useTransaction(async (transaction2) => {
2567
+ await this.#ensureParentExists(prefixed, transaction2);
2568
+ const request = transaction2.request();
2667
2569
  request.input("p0", prefixed);
2668
2570
  request.input("p1", data.length);
2669
2571
  request.input("p2", Date.now());
@@ -2677,7 +2579,7 @@ var MssqlFs = class _MssqlFs {
2677
2579
  INSERT (path, type, mode, size, mtime)
2678
2580
  VALUES (@p0, 'file', 420, @p1, @p2);
2679
2581
  `);
2680
- await this.#writeChunks(prefixed, data, transaction);
2582
+ await this.#writeChunks(prefixed, data, transaction2);
2681
2583
  });
2682
2584
  }
2683
2585
  async appendFile(filePath, content, options) {
@@ -2685,9 +2587,9 @@ var MssqlFs = class _MssqlFs {
2685
2587
  const prefixed = this.#prefixPath(normalized);
2686
2588
  const encoding = typeof options === "string" ? options : options?.encoding;
2687
2589
  const newData = this.#toUint8Array(content, encoding);
2688
- await this.#useTransaction(async (transaction) => {
2689
- await this.#ensureParentExists(prefixed, transaction);
2690
- const checkReq = transaction.request();
2590
+ await this.#useTransaction(async (transaction2) => {
2591
+ await this.#ensureParentExists(prefixed, transaction2);
2592
+ const checkReq = transaction2.request();
2691
2593
  checkReq.input("p0", prefixed);
2692
2594
  const [entry] = rowsOf(
2693
2595
  typeRow2,
@@ -2698,11 +2600,11 @@ var MssqlFs = class _MssqlFs {
2698
2600
  if (entry && entry.type !== "file") {
2699
2601
  throw new Error(`appendFile: not a file: ${filePath}`);
2700
2602
  }
2701
- const existing = entry ? await this.#readChunks(prefixed, transaction) : new Uint8Array(0);
2603
+ const existing = entry ? await this.#readChunks(prefixed, transaction2) : new Uint8Array(0);
2702
2604
  const combined = new Uint8Array(existing.length + newData.length);
2703
2605
  combined.set(existing, 0);
2704
2606
  combined.set(newData, existing.length);
2705
- const upsertReq = transaction.request();
2607
+ const upsertReq = transaction2.request();
2706
2608
  upsertReq.input("p0", prefixed);
2707
2609
  upsertReq.input("p1", combined.length);
2708
2610
  upsertReq.input("p2", Date.now());
@@ -2716,7 +2618,7 @@ var MssqlFs = class _MssqlFs {
2716
2618
  INSERT (path, type, mode, size, mtime)
2717
2619
  VALUES (@p0, 'file', 420, @p1, @p2);
2718
2620
  `);
2719
- await this.#writeChunks(prefixed, combined, transaction);
2621
+ await this.#writeChunks(prefixed, combined, transaction2);
2720
2622
  });
2721
2623
  }
2722
2624
  async exists(filePath) {
@@ -2792,7 +2694,7 @@ var MssqlFs = class _MssqlFs {
2792
2694
  }
2793
2695
  throw new Error(`EEXIST: file already exists: ${dirPath}`);
2794
2696
  }
2795
- await this.#useTransaction(async (transaction) => {
2697
+ await this.#useTransaction(async (transaction2) => {
2796
2698
  if (options?.recursive) {
2797
2699
  const rootPath = this.#root || "/";
2798
2700
  const relativePath = path3.posix.relative(rootPath, prefixed);
@@ -2800,7 +2702,7 @@ var MssqlFs = class _MssqlFs {
2800
2702
  let currentPath = rootPath;
2801
2703
  for (const segment of segments) {
2802
2704
  currentPath = path3.posix.join(currentPath, segment);
2803
- const checkReq = transaction.request();
2705
+ const checkReq = transaction2.request();
2804
2706
  checkReq.input("p0", currentPath);
2805
2707
  const [exists] = rowsOf(
2806
2708
  typeRow2,
@@ -2809,7 +2711,7 @@ var MssqlFs = class _MssqlFs {
2809
2711
  )
2810
2712
  );
2811
2713
  if (!exists) {
2812
- const insertReq = transaction.request();
2714
+ const insertReq = transaction2.request();
2813
2715
  insertReq.input("p0", currentPath);
2814
2716
  insertReq.input("p1", Date.now());
2815
2717
  await insertReq.query(
@@ -2821,7 +2723,7 @@ var MssqlFs = class _MssqlFs {
2821
2723
  }
2822
2724
  } else {
2823
2725
  const parent = this.#dirname(prefixed);
2824
- const parentReq = transaction.request();
2726
+ const parentReq = transaction2.request();
2825
2727
  parentReq.input("p0", parent);
2826
2728
  const [parentEntry] = rowsOf(
2827
2729
  typeRow2,
@@ -2835,7 +2737,7 @@ var MssqlFs = class _MssqlFs {
2835
2737
  if (parentEntry.type !== "directory") {
2836
2738
  throw new Error(`mkdir: parent is not a directory: ${parent}`);
2837
2739
  }
2838
- const insertReq = transaction.request();
2740
+ const insertReq = transaction2.request();
2839
2741
  insertReq.input("p0", prefixed);
2840
2742
  insertReq.input("p1", Date.now());
2841
2743
  await insertReq.query(
@@ -2925,9 +2827,9 @@ var MssqlFs = class _MssqlFs {
2925
2827
  }
2926
2828
  throw new Error(`ENOENT: no such file or directory: ${filePath}`);
2927
2829
  }
2928
- await this.#useTransaction(async (transaction) => {
2830
+ await this.#useTransaction(async (transaction2) => {
2929
2831
  if (entry.type === "directory") {
2930
- const childrenReq = transaction.request();
2832
+ const childrenReq = transaction2.request();
2931
2833
  childrenReq.input("p0", prefixed);
2932
2834
  const children = rowsOf(
2933
2835
  existsRow,
@@ -2938,13 +2840,13 @@ var MssqlFs = class _MssqlFs {
2938
2840
  if (children[0].exists === 1 && !options?.recursive) {
2939
2841
  throw new Error(`ENOTEMPTY: directory not empty: ${filePath}`);
2940
2842
  }
2941
- const deleteReq = transaction.request();
2843
+ const deleteReq = transaction2.request();
2942
2844
  deleteReq.input("p0", prefixed);
2943
2845
  await deleteReq.query(
2944
2846
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @p0 OR path LIKE @p0 + '/%'`
2945
2847
  );
2946
2848
  } else {
2947
- const deleteReq = transaction.request();
2849
+ const deleteReq = transaction2.request();
2948
2850
  deleteReq.input("p0", prefixed);
2949
2851
  await deleteReq.query(
2950
2852
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @p0`
@@ -2970,10 +2872,10 @@ var MssqlFs = class _MssqlFs {
2970
2872
  if (srcEntry.type === "directory" && !options?.recursive) {
2971
2873
  throw new Error(`cp: -r not specified; omitting directory: ${src}`);
2972
2874
  }
2973
- await this.#useTransaction(async (transaction) => {
2974
- await this.#ensureParentExists(destPrefixed, transaction);
2875
+ await this.#useTransaction(async (transaction2) => {
2876
+ await this.#ensureParentExists(destPrefixed, transaction2);
2975
2877
  if (srcEntry.type === "directory") {
2976
- const allEntriesReq = transaction.request();
2878
+ const allEntriesReq = transaction2.request();
2977
2879
  allEntriesReq.input("p0", srcPrefixed);
2978
2880
  const allEntries = rowsOf(
2979
2881
  entryRow2,
@@ -2984,7 +2886,7 @@ var MssqlFs = class _MssqlFs {
2984
2886
  for (const entry of allEntries) {
2985
2887
  const relativePath = path3.posix.relative(srcPrefixed, entry.path);
2986
2888
  const newPath = path3.posix.join(destPrefixed, relativePath);
2987
- const insertReq = transaction.request();
2889
+ const insertReq = transaction2.request();
2988
2890
  insertReq.input("p0", newPath);
2989
2891
  insertReq.input("p1", entry.type);
2990
2892
  insertReq.input("p2", entry.mode);
@@ -3002,12 +2904,12 @@ var MssqlFs = class _MssqlFs {
3002
2904
  VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
3003
2905
  `);
3004
2906
  if (entry.type === "file") {
3005
- const deleteChunksReq = transaction.request();
2907
+ const deleteChunksReq = transaction2.request();
3006
2908
  deleteChunksReq.input("p0", newPath);
3007
2909
  await deleteChunksReq.query(
3008
2910
  `DELETE FROM ${this.#t("fs_chunks")} WHERE path = @p0`
3009
2911
  );
3010
- const chunksReq = transaction.request();
2912
+ const chunksReq = transaction2.request();
3011
2913
  chunksReq.input("p0", entry.path);
3012
2914
  const chunks = rowsOf(
3013
2915
  chunkRow2,
@@ -3016,7 +2918,7 @@ var MssqlFs = class _MssqlFs {
3016
2918
  )
3017
2919
  );
3018
2920
  for (const chunk of chunks) {
3019
- const chunkInsertReq = transaction.request();
2921
+ const chunkInsertReq = transaction2.request();
3020
2922
  chunkInsertReq.input("p0", newPath);
3021
2923
  chunkInsertReq.input("p1", chunk.chunkIndex);
3022
2924
  chunkInsertReq.input("p2", chunk.data);
@@ -3027,7 +2929,7 @@ var MssqlFs = class _MssqlFs {
3027
2929
  }
3028
2930
  }
3029
2931
  } else {
3030
- const insertReq = transaction.request();
2932
+ const insertReq = transaction2.request();
3031
2933
  insertReq.input("p0", destPrefixed);
3032
2934
  insertReq.input("p1", srcEntry.type);
3033
2935
  insertReq.input("p2", srcEntry.mode);
@@ -3045,7 +2947,7 @@ var MssqlFs = class _MssqlFs {
3045
2947
  VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
3046
2948
  `);
3047
2949
  if (srcEntry.type === "file") {
3048
- const chunksReq = transaction.request();
2950
+ const chunksReq = transaction2.request();
3049
2951
  chunksReq.input("p0", srcPrefixed);
3050
2952
  const chunks = rowsOf(
3051
2953
  chunkRow2,
@@ -3053,13 +2955,13 @@ var MssqlFs = class _MssqlFs {
3053
2955
  `SELECT chunkIndex, data FROM ${this.#t("fs_chunks")} WHERE path = @p0`
3054
2956
  )
3055
2957
  );
3056
- const deleteChunksReq = transaction.request();
2958
+ const deleteChunksReq = transaction2.request();
3057
2959
  deleteChunksReq.input("p0", destPrefixed);
3058
2960
  await deleteChunksReq.query(
3059
2961
  `DELETE FROM ${this.#t("fs_chunks")} WHERE path = @p0`
3060
2962
  );
3061
2963
  for (const chunk of chunks) {
3062
- const chunkInsertReq = transaction.request();
2964
+ const chunkInsertReq = transaction2.request();
3063
2965
  chunkInsertReq.input("p0", destPrefixed);
3064
2966
  chunkInsertReq.input("p1", chunk.chunkIndex);
3065
2967
  chunkInsertReq.input("p2", chunk.data);
@@ -3086,10 +2988,10 @@ var MssqlFs = class _MssqlFs {
3086
2988
  if (!srcEntry) {
3087
2989
  throw new Error(`ENOENT: no such file or directory: ${src}`);
3088
2990
  }
3089
- await this.#useTransaction(async (transaction) => {
3090
- await this.#ensureParentExists(destPrefixed, transaction);
2991
+ await this.#useTransaction(async (transaction2) => {
2992
+ await this.#ensureParentExists(destPrefixed, transaction2);
3091
2993
  if (srcEntry.type === "directory") {
3092
- const allEntriesReq = transaction.request();
2994
+ const allEntriesReq = transaction2.request();
3093
2995
  allEntriesReq.input("p0", srcPrefixed);
3094
2996
  const allEntries = rowsOf(
3095
2997
  entryRow2,
@@ -3097,7 +2999,7 @@ var MssqlFs = class _MssqlFs {
3097
2999
  `SELECT * FROM ${this.#t("fs_entries")} WHERE path = @p0 OR path LIKE @p0 + '/%' ORDER BY path DESC`
3098
3000
  )
3099
3001
  );
3100
- const destDeleteReq = transaction.request();
3002
+ const destDeleteReq = transaction2.request();
3101
3003
  destDeleteReq.input("dp0", destPrefixed);
3102
3004
  await destDeleteReq.query(
3103
3005
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @dp0 OR path LIKE @dp0 + '/%'`
@@ -3105,7 +3007,7 @@ var MssqlFs = class _MssqlFs {
3105
3007
  for (const entry of [...allEntries].reverse()) {
3106
3008
  const relativePath = path3.posix.relative(srcPrefixed, entry.path);
3107
3009
  const newPath = path3.posix.join(destPrefixed, relativePath);
3108
- const insertReq = transaction.request();
3010
+ const insertReq = transaction2.request();
3109
3011
  insertReq.input("p0", newPath);
3110
3012
  insertReq.input("p1", entry.type);
3111
3013
  insertReq.input("p2", entry.mode);
@@ -3123,12 +3025,12 @@ var MssqlFs = class _MssqlFs {
3123
3025
  VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
3124
3026
  `);
3125
3027
  if (entry.type === "file") {
3126
- const deleteChunksReq = transaction.request();
3028
+ const deleteChunksReq = transaction2.request();
3127
3029
  deleteChunksReq.input("p0", newPath);
3128
3030
  await deleteChunksReq.query(
3129
3031
  `DELETE FROM ${this.#t("fs_chunks")} WHERE path = @p0`
3130
3032
  );
3131
- const chunksReq = transaction.request();
3033
+ const chunksReq = transaction2.request();
3132
3034
  chunksReq.input("p0", entry.path);
3133
3035
  const chunks = rowsOf(
3134
3036
  chunkRow2,
@@ -3137,7 +3039,7 @@ var MssqlFs = class _MssqlFs {
3137
3039
  )
3138
3040
  );
3139
3041
  for (const chunk of chunks) {
3140
- const chunkInsertReq = transaction.request();
3042
+ const chunkInsertReq = transaction2.request();
3141
3043
  chunkInsertReq.input("p0", newPath);
3142
3044
  chunkInsertReq.input("p1", chunk.chunkIndex);
3143
3045
  chunkInsertReq.input("p2", chunk.data);
@@ -3147,13 +3049,13 @@ var MssqlFs = class _MssqlFs {
3147
3049
  }
3148
3050
  }
3149
3051
  }
3150
- const deleteReq = transaction.request();
3052
+ const deleteReq = transaction2.request();
3151
3053
  deleteReq.input("p0", srcPrefixed);
3152
3054
  await deleteReq.query(
3153
3055
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @p0 OR path LIKE @p0 + '/%'`
3154
3056
  );
3155
3057
  } else {
3156
- const insertReq = transaction.request();
3058
+ const insertReq = transaction2.request();
3157
3059
  insertReq.input("p0", destPrefixed);
3158
3060
  insertReq.input("p1", srcEntry.type);
3159
3061
  insertReq.input("p2", srcEntry.mode);
@@ -3171,12 +3073,12 @@ var MssqlFs = class _MssqlFs {
3171
3073
  VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
3172
3074
  `);
3173
3075
  if (srcEntry.type === "file") {
3174
- const deleteChunksReq = transaction.request();
3076
+ const deleteChunksReq = transaction2.request();
3175
3077
  deleteChunksReq.input("p0", destPrefixed);
3176
3078
  await deleteChunksReq.query(
3177
3079
  `DELETE FROM ${this.#t("fs_chunks")} WHERE path = @p0`
3178
3080
  );
3179
- const chunksReq = transaction.request();
3081
+ const chunksReq = transaction2.request();
3180
3082
  chunksReq.input("p0", srcPrefixed);
3181
3083
  const chunks = rowsOf(
3182
3084
  chunkRow2,
@@ -3185,7 +3087,7 @@ var MssqlFs = class _MssqlFs {
3185
3087
  )
3186
3088
  );
3187
3089
  for (const chunk of chunks) {
3188
- const chunkInsertReq = transaction.request();
3090
+ const chunkInsertReq = transaction2.request();
3189
3091
  chunkInsertReq.input("p0", destPrefixed);
3190
3092
  chunkInsertReq.input("p1", chunk.chunkIndex);
3191
3093
  chunkInsertReq.input("p2", chunk.data);
@@ -3194,7 +3096,7 @@ var MssqlFs = class _MssqlFs {
3194
3096
  );
3195
3097
  }
3196
3098
  }
3197
- const deleteReq = transaction.request();
3099
+ const deleteReq = transaction2.request();
3198
3100
  deleteReq.input("p0", srcPrefixed);
3199
3101
  await deleteReq.query(
3200
3102
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @p0`
@@ -3271,9 +3173,9 @@ var MssqlFs = class _MssqlFs {
3271
3173
  if (existingRows[0].exists === 1) {
3272
3174
  throw new Error(`EEXIST: file already exists: ${linkPath}`);
3273
3175
  }
3274
- await this.#useTransaction(async (transaction) => {
3275
- await this.#ensureParentExists(prefixed, transaction);
3276
- const insertReq = transaction.request();
3176
+ await this.#useTransaction(async (transaction2) => {
3177
+ await this.#ensureParentExists(prefixed, transaction2);
3178
+ const insertReq = transaction2.request();
3277
3179
  insertReq.input("p0", prefixed);
3278
3180
  insertReq.input("p1", Date.now());
3279
3181
  insertReq.input("p2", target);
@@ -3311,9 +3213,9 @@ var MssqlFs = class _MssqlFs {
3311
3213
  if (existingRows[0].exists === 1) {
3312
3214
  throw new Error(`EEXIST: file already exists: ${newPath}`);
3313
3215
  }
3314
- await this.#useTransaction(async (transaction) => {
3315
- await this.#ensureParentExists(destPrefixed, transaction);
3316
- const insertReq = transaction.request();
3216
+ await this.#useTransaction(async (transaction2) => {
3217
+ await this.#ensureParentExists(destPrefixed, transaction2);
3218
+ const insertReq = transaction2.request();
3317
3219
  insertReq.input("p0", destPrefixed);
3318
3220
  insertReq.input("p1", srcEntry.mode);
3319
3221
  insertReq.input("p2", srcEntry.size);
@@ -3322,7 +3224,7 @@ var MssqlFs = class _MssqlFs {
3322
3224
  `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime)
3323
3225
  VALUES (@p0, 'file', @p1, @p2, @p3)`
3324
3226
  );
3325
- const chunksReq = transaction.request();
3227
+ const chunksReq = transaction2.request();
3326
3228
  chunksReq.input("p0", srcPrefixed);
3327
3229
  const chunks = rowsOf(
3328
3230
  chunkRow2,
@@ -3331,7 +3233,7 @@ var MssqlFs = class _MssqlFs {
3331
3233
  )
3332
3234
  );
3333
3235
  for (const chunk of chunks) {
3334
- const chunkInsertReq = transaction.request();
3236
+ const chunkInsertReq = transaction2.request();
3335
3237
  chunkInsertReq.input("p0", destPrefixed);
3336
3238
  chunkInsertReq.input("p1", chunk.chunkIndex);
3337
3239
  chunkInsertReq.input("p2", chunk.data);
@@ -3365,6 +3267,7 @@ var MssqlFs = class _MssqlFs {
3365
3267
  import { createRequire as createRequire2 } from "node:module";
3366
3268
  import * as path4 from "node:path";
3367
3269
  import z8 from "zod";
3270
+ import { lockSchemaDDL } from "@deepagents/context";
3368
3271
 
3369
3272
  // packages/text2sql/src/lib/fs/postgres/ddl.postgres-fs.ts
3370
3273
  function postgresFsDDL(schema) {
@@ -3468,58 +3371,34 @@ var PostgresFs = class _PostgresFs {
3468
3371
  }
3469
3372
  return fs;
3470
3373
  }
3374
+ // The schema lock is held until this transaction commits, so concurrent
3375
+ // openers also create the root directories one at a time.
3471
3376
  async #initialize() {
3472
- const ddl = postgresFsDDL(this.#schema);
3473
- await this.#pool.query(ddl);
3474
- const rootSlashExists = rowsOf2(
3475
- existsRow2,
3476
- await this.#query(
3477
- `SELECT EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = '/') AS exists`
3478
- )
3479
- );
3480
- if (!rootSlashExists[0].exists) {
3481
- await this.#exec(
3482
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES ('/', 'directory', 493, 0, $1)`,
3483
- [Date.now()]
3484
- );
3485
- }
3486
- if (this.#root) {
3487
- await this.#createParentDirs(this.#root);
3488
- const rootExists = rowsOf2(
3489
- existsRow2,
3490
- await this.#query(
3491
- `SELECT EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = $1) AS exists`,
3492
- [this.#root]
3493
- )
3377
+ await this.#useTransaction(async (client) => {
3378
+ await client.query(
3379
+ lockSchemaDDL(postgresFsDDL(this.#schema), this.#schema)
3494
3380
  );
3495
- if (!rootExists[0].exists) {
3496
- await this.#exec(
3497
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES ($1, 'directory', 493, 0, $2)`,
3498
- [this.#root, Date.now()]
3499
- );
3381
+ await this.#ensureDirectory(client, "/");
3382
+ if (this.#root) {
3383
+ await this.#createParentDirs(client, this.#root);
3384
+ await this.#ensureDirectory(client, this.#root);
3500
3385
  }
3501
- }
3386
+ });
3502
3387
  }
3503
- async #createParentDirs(p) {
3388
+ async #createParentDirs(client, p) {
3504
3389
  const segments = p.split("/").filter(Boolean);
3505
3390
  let currentPath = "/";
3506
3391
  for (let i = 0; i < segments.length - 1; i++) {
3507
3392
  currentPath = path4.posix.join(currentPath, segments[i]);
3508
- const exists = rowsOf2(
3509
- existsRow2,
3510
- await this.#query(
3511
- `SELECT EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = $1) AS exists`,
3512
- [currentPath]
3513
- )
3514
- );
3515
- if (!exists[0].exists) {
3516
- await this.#exec(
3517
- `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES ($1, 'directory', 493, 0, $2)`,
3518
- [currentPath, Date.now()]
3519
- );
3520
- }
3393
+ await this.#ensureDirectory(client, currentPath);
3521
3394
  }
3522
3395
  }
3396
+ async #ensureDirectory(client, p) {
3397
+ await client.query(
3398
+ `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime) VALUES ($1, 'directory', 493, 0, $2) ON CONFLICT (path) DO NOTHING`,
3399
+ [p, Date.now()]
3400
+ );
3401
+ }
3523
3402
  #query(sql, params) {
3524
3403
  return this.#pool.query(sql, params);
3525
3404
  }