@resourcexjs/registry 1.6.0 → 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.
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ // src/types.ts
2
+ function isRemoteConfig(config) {
3
+ return config !== undefined && "endpoint" in config;
4
+ }
1
5
  // ../core/dist/index.js
2
6
  import { gzip, gunzip } from "node:zlib";
3
7
  import { promisify } from "node:util";
@@ -156,8 +160,10 @@ class RegistryError extends ResourceXError {
156
160
  this.name = "RegistryError";
157
161
  }
158
162
  }
159
- // src/ARPRegistry.ts
163
+ // src/LocalRegistry.ts
160
164
  import { homedir } from "node:os";
165
+ import { join } from "node:path";
166
+ import { readFile, writeFile, mkdir, rm, stat, readdir } from "node:fs/promises";
161
167
 
162
168
  // ../type/dist/index.js
163
169
  import { gzip as gzip2, gunzip as gunzip2 } from "node:zlib";
@@ -1459,487 +1465,13 @@ class TypeHandlerChain {
1459
1465
  }
1460
1466
  }
1461
1467
 
1462
- // ../arp/dist/index.js
1463
- import { readFile, writeFile, readdir, mkdir, rm, access, stat } from "node:fs/promises";
1464
- import { resolve, dirname, join } from "node:path";
1465
-
1466
- class ARPError extends Error {
1467
- constructor(message, options) {
1468
- super(message, options);
1469
- this.name = "ARPError";
1470
- }
1471
- }
1472
-
1473
- class ParseError extends ARPError {
1474
- url;
1475
- constructor(message, url) {
1476
- super(message);
1477
- this.url = url;
1478
- this.name = "ParseError";
1479
- }
1480
- }
1481
-
1482
- class TransportError extends ARPError {
1483
- transport;
1484
- constructor(message, transport, options) {
1485
- super(message, options);
1486
- this.transport = transport;
1487
- this.name = "TransportError";
1488
- }
1489
- }
1490
-
1491
- class SemanticError extends ARPError {
1492
- semantic;
1493
- constructor(message, semantic, options) {
1494
- super(message, options);
1495
- this.semantic = semantic;
1496
- this.name = "SemanticError";
1497
- }
1498
- }
1499
-
1500
- class ARL {
1501
- semantic;
1502
- transport;
1503
- location;
1504
- resolver;
1505
- constructor(semantic, transport, location, resolver) {
1506
- this.semantic = semantic;
1507
- this.transport = transport;
1508
- this.location = location;
1509
- this.resolver = resolver;
1510
- }
1511
- createContext(params) {
1512
- return {
1513
- url: this.toString(),
1514
- semantic: this.semantic,
1515
- transport: this.transport,
1516
- location: this.location,
1517
- timestamp: new Date,
1518
- params
1519
- };
1520
- }
1521
- async resolve(params) {
1522
- const transport = this.resolver.getTransportHandler(this.transport);
1523
- const semantic = this.resolver.getSemanticHandler(this.semantic);
1524
- const context = this.createContext(params);
1525
- return semantic.resolve(transport, this.location, context);
1526
- }
1527
- async deposit(data, params) {
1528
- const transport = this.resolver.getTransportHandler(this.transport);
1529
- const semantic = this.resolver.getSemanticHandler(this.semantic);
1530
- const context = this.createContext(params);
1531
- if (!semantic.deposit) {
1532
- throw new SemanticError(`Semantic "${semantic.name}" does not support deposit operation`, this.semantic);
1533
- }
1534
- await semantic.deposit(transport, this.location, data, context);
1535
- }
1536
- async exists() {
1537
- const transport = this.resolver.getTransportHandler(this.transport);
1538
- const semantic = this.resolver.getSemanticHandler(this.semantic);
1539
- const context = this.createContext();
1540
- if (semantic.exists) {
1541
- return semantic.exists(transport, this.location, context);
1542
- }
1543
- return transport.exists(this.location);
1544
- }
1545
- async delete() {
1546
- const transport = this.resolver.getTransportHandler(this.transport);
1547
- const semantic = this.resolver.getSemanticHandler(this.semantic);
1548
- const context = this.createContext();
1549
- if (semantic.delete) {
1550
- return semantic.delete(transport, this.location, context);
1551
- }
1552
- await transport.delete(this.location);
1553
- }
1554
- toString() {
1555
- return `arp:${this.semantic}:${this.transport}://${this.location}`;
1556
- }
1557
- }
1558
-
1559
- class FileTransportHandler {
1560
- name = "file";
1561
- resolvePath(location) {
1562
- return resolve(process.cwd(), location);
1563
- }
1564
- async get(location, params) {
1565
- const filePath = this.resolvePath(location);
1566
- try {
1567
- const stats = await stat(filePath);
1568
- if (stats.isDirectory()) {
1569
- return this.getDirectory(filePath, stats, params);
1570
- } else {
1571
- return this.getFile(filePath, stats);
1572
- }
1573
- } catch (error) {
1574
- const err = error;
1575
- throw new TransportError(`File get error: ${err.code} - ${filePath}`, this.name, {
1576
- cause: err
1577
- });
1578
- }
1579
- }
1580
- async getFile(filePath, stats) {
1581
- const content = await readFile(filePath);
1582
- return {
1583
- content,
1584
- metadata: {
1585
- type: "file",
1586
- size: Number(stats.size),
1587
- modifiedAt: stats.mtime
1588
- }
1589
- };
1590
- }
1591
- async getDirectory(dirPath, stats, params) {
1592
- const recursive = params?.recursive === "true";
1593
- const pattern = params?.pattern;
1594
- let entries;
1595
- if (recursive) {
1596
- entries = await this.listRecursive(dirPath, dirPath);
1597
- } else {
1598
- entries = await readdir(dirPath);
1599
- }
1600
- if (pattern) {
1601
- entries = this.filterByPattern(entries, pattern);
1602
- }
1603
- const content = Buffer.from(JSON.stringify(entries));
1604
- return {
1605
- content,
1606
- metadata: {
1607
- type: "directory",
1608
- modifiedAt: stats.mtime
1609
- }
1610
- };
1611
- }
1612
- async listRecursive(basePath, currentPath) {
1613
- const entries = await readdir(currentPath, { withFileTypes: true });
1614
- const results = [];
1615
- for (const entry of entries) {
1616
- const fullPath = join(currentPath, entry.name);
1617
- const relativePath = fullPath.substring(basePath.length + 1);
1618
- if (entry.isDirectory()) {
1619
- const subEntries = await this.listRecursive(basePath, fullPath);
1620
- results.push(...subEntries);
1621
- } else {
1622
- results.push(relativePath);
1623
- }
1624
- }
1625
- return results;
1626
- }
1627
- filterByPattern(entries, pattern) {
1628
- const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
1629
- const regex = new RegExp(`^${regexPattern}$`);
1630
- return entries.filter((entry) => {
1631
- const filename = entry.split("/").pop() || entry;
1632
- return regex.test(filename);
1633
- });
1634
- }
1635
- async set(location, content, _params) {
1636
- const filePath = this.resolvePath(location);
1637
- try {
1638
- await mkdir(dirname(filePath), { recursive: true });
1639
- await writeFile(filePath, content);
1640
- } catch (error) {
1641
- const err = error;
1642
- throw new TransportError(`File set error: ${err.code} - ${filePath}`, this.name, {
1643
- cause: err
1644
- });
1645
- }
1646
- }
1647
- async exists(location) {
1648
- const filePath = this.resolvePath(location);
1649
- try {
1650
- await access(filePath);
1651
- return true;
1652
- } catch {
1653
- return false;
1654
- }
1655
- }
1656
- async delete(location) {
1657
- const filePath = this.resolvePath(location);
1658
- try {
1659
- await rm(filePath, { recursive: true });
1660
- } catch (error) {
1661
- const err = error;
1662
- if (err.code === "ENOENT") {
1663
- return;
1664
- }
1665
- throw new TransportError(`File delete error: ${err.code} - ${filePath}`, this.name, {
1666
- cause: err
1667
- });
1668
- }
1669
- }
1670
- }
1671
- var fileTransport = new FileTransportHandler;
1672
-
1673
- class HttpTransportHandler {
1674
- name;
1675
- protocol;
1676
- constructor(protocol = "https") {
1677
- this.protocol = protocol;
1678
- this.name = protocol;
1679
- }
1680
- async get(location, params) {
1681
- const url = this.buildUrl(location, params);
1682
- try {
1683
- const response = await fetch(url);
1684
- if (!response.ok) {
1685
- throw new TransportError(`HTTP ${response.status}: ${response.statusText} - ${url}`, this.name);
1686
- }
1687
- const arrayBuffer = await response.arrayBuffer();
1688
- const content = Buffer.from(arrayBuffer);
1689
- const contentType = response.headers.get("content-type");
1690
- const contentLength = response.headers.get("content-length");
1691
- const lastModified = response.headers.get("last-modified");
1692
- return {
1693
- content,
1694
- metadata: {
1695
- type: "file",
1696
- size: contentLength ? parseInt(contentLength, 10) : content.length,
1697
- modifiedAt: lastModified ? new Date(lastModified) : undefined,
1698
- contentType
1699
- }
1700
- };
1701
- } catch (error) {
1702
- if (error instanceof TransportError) {
1703
- throw error;
1704
- }
1705
- throw new TransportError(`Network error: ${url}`, this.name, {
1706
- cause: error
1707
- });
1708
- }
1709
- }
1710
- buildUrl(location, params) {
1711
- const url = new URL(`${this.protocol}://${location}`);
1712
- if (params) {
1713
- for (const [key, value] of Object.entries(params)) {
1714
- url.searchParams.set(key, value);
1715
- }
1716
- }
1717
- return url.toString();
1718
- }
1719
- async set(_location, _content, _params) {
1720
- throw new TransportError("HTTP transport is read-only, set not supported", this.name);
1721
- }
1722
- async exists(location) {
1723
- const url = `${this.protocol}://${location}`;
1724
- try {
1725
- const response = await fetch(url, { method: "HEAD" });
1726
- return response.ok;
1727
- } catch {
1728
- return false;
1729
- }
1730
- }
1731
- async delete(_location) {
1732
- throw new TransportError("HTTP transport is read-only, delete not supported", this.name);
1733
- }
1734
- }
1735
- var httpsTransport = new HttpTransportHandler("https");
1736
- var httpTransport = new HttpTransportHandler("http");
1737
-
1738
- class TextSemanticHandler {
1739
- name = "text";
1740
- async resolve(transport, location, context) {
1741
- const result = await transport.get(location, context.params);
1742
- if (result.metadata?.type === "directory") {
1743
- const meta2 = {
1744
- url: context.url,
1745
- semantic: context.semantic,
1746
- transport: context.transport,
1747
- location: context.location,
1748
- size: result.content.length,
1749
- encoding: "utf-8",
1750
- mimeType: "application/json",
1751
- resolvedAt: context.timestamp.toISOString(),
1752
- type: "directory"
1753
- };
1754
- return {
1755
- type: "text",
1756
- content: result.content.toString("utf-8"),
1757
- meta: meta2
1758
- };
1759
- }
1760
- const text = result.content.toString("utf-8");
1761
- const meta = {
1762
- url: context.url,
1763
- semantic: context.semantic,
1764
- transport: context.transport,
1765
- location: context.location,
1766
- size: result.metadata?.size ?? result.content.length,
1767
- encoding: "utf-8",
1768
- mimeType: "text/plain",
1769
- resolvedAt: context.timestamp.toISOString(),
1770
- type: "file"
1771
- };
1772
- return {
1773
- type: "text",
1774
- content: text,
1775
- meta
1776
- };
1777
- }
1778
- async deposit(transport, location, data, context) {
1779
- const buffer = Buffer.from(data, "utf-8");
1780
- try {
1781
- await transport.set(location, buffer, context.params);
1782
- } catch (error) {
1783
- throw new SemanticError(`Failed to deposit text to "${location}": ${error.message}`, this.name, { cause: error });
1784
- }
1785
- }
1786
- async exists(transport, location, _context) {
1787
- return transport.exists(location);
1788
- }
1789
- async delete(transport, location, _context) {
1790
- try {
1791
- await transport.delete(location);
1792
- } catch (error) {
1793
- throw new SemanticError(`Failed to delete "${location}": ${error.message}`, this.name, { cause: error });
1794
- }
1795
- }
1796
- }
1797
- var textSemantic = new TextSemanticHandler;
1798
- function toBuffer(data) {
1799
- if (Buffer.isBuffer(data)) {
1800
- return data;
1801
- }
1802
- if (data instanceof Uint8Array) {
1803
- return Buffer.from(data);
1804
- }
1805
- if (data instanceof ArrayBuffer) {
1806
- return Buffer.from(data);
1807
- }
1808
- if (Array.isArray(data)) {
1809
- return Buffer.from(data);
1810
- }
1811
- throw new SemanticError(`Unsupported binary input type`, "binary");
1812
- }
1813
-
1814
- class BinarySemanticHandler {
1815
- name = "binary";
1816
- async resolve(transport, location, context) {
1817
- const result = await transport.get(location, context.params);
1818
- const meta = {
1819
- url: context.url,
1820
- semantic: context.semantic,
1821
- transport: context.transport,
1822
- location: context.location,
1823
- size: result.metadata?.size ?? result.content.length,
1824
- resolvedAt: context.timestamp.toISOString(),
1825
- type: result.metadata?.type
1826
- };
1827
- return {
1828
- type: "binary",
1829
- content: result.content,
1830
- meta
1831
- };
1832
- }
1833
- async deposit(transport, location, data, context) {
1834
- const buffer = toBuffer(data);
1835
- try {
1836
- await transport.set(location, buffer, context.params);
1837
- } catch (error) {
1838
- throw new SemanticError(`Failed to deposit binary to "${location}": ${error.message}`, this.name, { cause: error });
1839
- }
1840
- }
1841
- async exists(transport, location, _context) {
1842
- return transport.exists(location);
1843
- }
1844
- async delete(transport, location, _context) {
1845
- try {
1846
- await transport.delete(location);
1847
- } catch (error) {
1848
- throw new SemanticError(`Failed to delete "${location}": ${error.message}`, this.name, { cause: error });
1849
- }
1850
- }
1851
- }
1852
- var binarySemantic = new BinarySemanticHandler;
1853
-
1854
- class ARP {
1855
- transports;
1856
- semantics;
1857
- constructor(config = {}) {
1858
- this.transports = new Map;
1859
- this.semantics = new Map;
1860
- const defaultTransports = [fileTransport, httpTransport, httpsTransport];
1861
- const defaultSemantics = [textSemantic, binarySemantic];
1862
- for (const handler of defaultTransports) {
1863
- this.transports.set(handler.name, handler);
1864
- }
1865
- for (const handler of defaultSemantics) {
1866
- this.semantics.set(handler.name, handler);
1867
- }
1868
- if (config.transports) {
1869
- for (const handler of config.transports) {
1870
- this.transports.set(handler.name, handler);
1871
- }
1872
- }
1873
- if (config.semantics) {
1874
- for (const handler of config.semantics) {
1875
- this.semantics.set(handler.name, handler);
1876
- }
1877
- }
1878
- }
1879
- registerTransport(handler) {
1880
- this.transports.set(handler.name, handler);
1881
- }
1882
- registerSemantic(handler) {
1883
- this.semantics.set(handler.name, handler);
1884
- }
1885
- getTransportHandler(name) {
1886
- const handler = this.transports.get(name);
1887
- if (!handler) {
1888
- throw new TransportError(`Unsupported transport type: ${name}`, name);
1889
- }
1890
- return handler;
1891
- }
1892
- getSemanticHandler(name) {
1893
- const handler = this.semantics.get(name);
1894
- if (!handler) {
1895
- throw new SemanticError(`Unsupported semantic type: ${name}`, name);
1896
- }
1897
- return handler;
1898
- }
1899
- parse(url) {
1900
- if (!url.startsWith("arp:")) {
1901
- throw new ParseError(`Invalid ARP URL: must start with "arp:"`, url);
1902
- }
1903
- const content = url.substring(4);
1904
- const separatorIndex = content.indexOf("://");
1905
- if (separatorIndex === -1) {
1906
- throw new ParseError(`Invalid ARP URL: missing "://"`, url);
1907
- }
1908
- const typePart = content.substring(0, separatorIndex);
1909
- const location = content.substring(separatorIndex + 3);
1910
- const colonIndex = typePart.indexOf(":");
1911
- if (colonIndex === -1) {
1912
- throw new ParseError(`Invalid ARP URL: must have exactly 2 types (semantic:transport)`, url);
1913
- }
1914
- const semantic = typePart.substring(0, colonIndex);
1915
- const transport = typePart.substring(colonIndex + 1);
1916
- if (!semantic) {
1917
- throw new ParseError(`Invalid ARP URL: semantic type cannot be empty`, url);
1918
- }
1919
- if (!transport) {
1920
- throw new ParseError(`Invalid ARP URL: transport type cannot be empty`, url);
1921
- }
1922
- if (!location) {
1923
- throw new ParseError(`Invalid ARP URL: location cannot be empty`, url);
1924
- }
1925
- this.getTransportHandler(transport);
1926
- this.getSemanticHandler(semantic);
1927
- return new ARL(semantic, transport, location, this);
1928
- }
1929
- }
1930
- function createARP(config) {
1931
- return new ARP(config);
1932
- }
1933
-
1934
- // src/ARPRegistry.ts
1468
+ // src/LocalRegistry.ts
1935
1469
  var DEFAULT_PATH = `${homedir()}/.resourcex`;
1936
1470
 
1937
- class ARPRegistry {
1938
- arp;
1471
+ class LocalRegistry {
1939
1472
  basePath;
1940
1473
  typeHandler;
1941
1474
  constructor(config) {
1942
- this.arp = createARP();
1943
1475
  this.basePath = config?.path ?? DEFAULT_PATH;
1944
1476
  this.typeHandler = TypeHandlerChain.create();
1945
1477
  if (config?.types) {
@@ -1951,79 +1483,79 @@ class ARPRegistry {
1951
1483
  supportType(type) {
1952
1484
  this.typeHandler.register(type);
1953
1485
  }
1954
- buildUrl(locator, filename) {
1486
+ buildPath(locator) {
1955
1487
  const rxl = typeof locator === "string" ? parseRXL(locator) : locator;
1956
1488
  const domain = rxl.domain ?? "localhost";
1957
1489
  const version = rxl.version ?? "latest";
1958
- let path = `${this.basePath}/${domain}`;
1490
+ let path = join(this.basePath, domain);
1959
1491
  if (rxl.path) {
1960
- path += `/${rxl.path}`;
1492
+ path = join(path, rxl.path);
1961
1493
  }
1962
1494
  const resourceName = rxl.type ? `${rxl.name}.${rxl.type}` : rxl.name;
1963
- return `arp:text:file://${path}/${resourceName}/${version}/${filename}`;
1495
+ return join(path, resourceName, version);
1964
1496
  }
1965
1497
  async publish(_resource) {
1966
1498
  throw new RegistryError("Remote publish not implemented yet");
1967
1499
  }
1968
1500
  async link(resource) {
1969
1501
  const locator = resource.manifest.toLocator();
1970
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1971
- const manifestArl = this.arp.parse(manifestUrl);
1972
- await manifestArl.deposit(JSON.stringify(resource.manifest.toJSON(), null, 2));
1973
- const contentUrl = this.buildUrl(locator, "content.tar.gz").replace("arp:text:", "arp:binary:");
1974
- const contentArl = this.arp.parse(contentUrl);
1502
+ const resourcePath = this.buildPath(locator);
1503
+ await mkdir(resourcePath, { recursive: true });
1504
+ const manifestPath = join(resourcePath, "manifest.json");
1505
+ await writeFile(manifestPath, JSON.stringify(resource.manifest.toJSON(), null, 2), "utf-8");
1506
+ const contentPath = join(resourcePath, "content.tar.gz");
1975
1507
  const serialized = await this.typeHandler.serialize(resource);
1976
- await contentArl.deposit(serialized);
1508
+ await writeFile(contentPath, serialized);
1977
1509
  }
1978
- async resolve(locator) {
1510
+ async get(locator) {
1979
1511
  if (!await this.exists(locator)) {
1980
1512
  throw new RegistryError(`Resource not found: ${locator}`);
1981
1513
  }
1982
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1983
- const manifestArl = this.arp.parse(manifestUrl);
1984
- const manifestResult = await manifestArl.resolve();
1985
- const manifestData = JSON.parse(manifestResult.content);
1514
+ const resourcePath = this.buildPath(locator);
1515
+ const manifestPath = join(resourcePath, "manifest.json");
1516
+ const manifestContent = await readFile(manifestPath, "utf-8");
1517
+ const manifestData = JSON.parse(manifestContent);
1986
1518
  const manifest = createRXM(manifestData);
1987
- const contentUrl = this.buildUrl(locator, "content.tar.gz").replace("arp:text:", "arp:binary:");
1988
- const contentArl = this.arp.parse(contentUrl);
1989
- const contentResult = await contentArl.resolve();
1990
- const data = contentResult.content;
1991
- const rxr = await this.typeHandler.deserialize(data, manifest);
1519
+ const contentPath = join(resourcePath, "content.tar.gz");
1520
+ const data = await readFile(contentPath);
1521
+ return this.typeHandler.deserialize(data, manifest);
1522
+ }
1523
+ async resolve(locator) {
1524
+ const rxr = await this.get(locator);
1992
1525
  return this.typeHandler.resolve(rxr);
1993
1526
  }
1994
1527
  async exists(locator) {
1995
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1996
- const manifestArl = this.arp.parse(manifestUrl);
1997
- return manifestArl.exists();
1528
+ const resourcePath = this.buildPath(locator);
1529
+ const manifestPath = join(resourcePath, "manifest.json");
1530
+ try {
1531
+ await stat(manifestPath);
1532
+ return true;
1533
+ } catch {
1534
+ return false;
1535
+ }
1998
1536
  }
1999
1537
  async delete(locator) {
2000
1538
  if (!await this.exists(locator)) {
2001
1539
  return;
2002
1540
  }
2003
- const manifestUrl = this.buildUrl(locator, "manifest.json");
2004
- const manifestArl = this.arp.parse(manifestUrl);
2005
- await manifestArl.delete();
2006
- const contentUrl = this.buildUrl(locator, "content.tar.gz").replace("arp:text:", "arp:binary:");
2007
- const contentArl = this.arp.parse(contentUrl);
2008
- await contentArl.delete();
1541
+ const resourcePath = this.buildPath(locator);
1542
+ await rm(resourcePath, { recursive: true, force: true });
2009
1543
  }
2010
1544
  async search(options) {
2011
1545
  const { query, limit, offset = 0 } = options ?? {};
2012
- const baseUrl = `arp:text:file://${this.basePath}`;
2013
- const baseArl = this.arp.parse(baseUrl);
2014
1546
  let entries;
2015
1547
  try {
2016
- const result2 = await baseArl.resolve({ recursive: "true" });
2017
- entries = JSON.parse(result2.content);
1548
+ entries = await this.listRecursive(this.basePath);
2018
1549
  } catch {
2019
1550
  return [];
2020
1551
  }
2021
1552
  const locators = [];
2022
1553
  for (const entry of entries) {
2023
- if (!entry.endsWith("/manifest.json")) {
1554
+ if (!entry.endsWith("manifest.json")) {
2024
1555
  continue;
2025
1556
  }
2026
- const rxl = this.parseEntryToRXL(entry);
1557
+ const relativePath = entry.slice(this.basePath.length + 1);
1558
+ const rxl = this.parseEntryToRXL(relativePath);
2027
1559
  if (rxl) {
2028
1560
  locators.push(rxl);
2029
1561
  }
@@ -2042,9 +1574,25 @@ class ARPRegistry {
2042
1574
  }
2043
1575
  return result;
2044
1576
  }
1577
+ async listRecursive(dir) {
1578
+ const results = [];
1579
+ try {
1580
+ const entries = await readdir(dir, { withFileTypes: true });
1581
+ for (const entry of entries) {
1582
+ const fullPath = join(dir, entry.name);
1583
+ if (entry.isDirectory()) {
1584
+ const subEntries = await this.listRecursive(fullPath);
1585
+ results.push(...subEntries);
1586
+ } else {
1587
+ results.push(fullPath);
1588
+ }
1589
+ }
1590
+ } catch {}
1591
+ return results;
1592
+ }
2045
1593
  parseEntryToRXL(entry) {
2046
- const dirPath = entry.replace(/\/manifest\.json$/, "");
2047
- const parts = dirPath.split("/");
1594
+ const dirPath = entry.replace(/[/\\]manifest\.json$/, "");
1595
+ const parts = dirPath.split(/[/\\]/);
2048
1596
  if (parts.length < 3) {
2049
1597
  return null;
2050
1598
  }
@@ -2078,14 +1626,105 @@ class ARPRegistry {
2078
1626
  }
2079
1627
  }
2080
1628
  }
1629
+ // src/RemoteRegistry.ts
1630
+ class RemoteRegistry {
1631
+ endpoint;
1632
+ typeHandler;
1633
+ constructor(config) {
1634
+ this.endpoint = config.endpoint.replace(/\/$/, "");
1635
+ this.typeHandler = TypeHandlerChain.create();
1636
+ }
1637
+ supportType(type) {
1638
+ this.typeHandler.register(type);
1639
+ }
1640
+ async publish(_resource) {
1641
+ throw new RegistryError("Remote registry publish not implemented yet");
1642
+ }
1643
+ async link(_resource) {
1644
+ throw new RegistryError("Cannot link to remote registry - use local registry for linking");
1645
+ }
1646
+ async get(locator) {
1647
+ const manifestUrl = `${this.endpoint}/resource?locator=${encodeURIComponent(locator)}`;
1648
+ const manifestResponse = await fetch(manifestUrl);
1649
+ if (!manifestResponse.ok) {
1650
+ if (manifestResponse.status === 404) {
1651
+ throw new RegistryError(`Resource not found: ${locator}`);
1652
+ }
1653
+ throw new RegistryError(`Failed to fetch resource: ${manifestResponse.statusText}`);
1654
+ }
1655
+ const manifestData = await manifestResponse.json();
1656
+ const manifest = createRXM(manifestData);
1657
+ const contentUrl = `${this.endpoint}/content?locator=${encodeURIComponent(locator)}`;
1658
+ const contentResponse = await fetch(contentUrl);
1659
+ if (!contentResponse.ok) {
1660
+ throw new RegistryError(`Failed to fetch content: ${contentResponse.statusText}`);
1661
+ }
1662
+ const contentBuffer = Buffer.from(await contentResponse.arrayBuffer());
1663
+ return this.typeHandler.deserialize(contentBuffer, manifest);
1664
+ }
1665
+ async resolve(locator) {
1666
+ const rxr = await this.get(locator);
1667
+ return this.typeHandler.resolve(rxr);
1668
+ }
1669
+ async exists(locator) {
1670
+ const url = `${this.endpoint}/exists?locator=${encodeURIComponent(locator)}`;
1671
+ const response = await fetch(url);
1672
+ if (!response.ok) {
1673
+ return false;
1674
+ }
1675
+ const data = await response.json();
1676
+ return data.exists === true;
1677
+ }
1678
+ async delete(_locator) {
1679
+ throw new RegistryError("Cannot delete from remote registry - use local registry for deletion");
1680
+ }
1681
+ async search(options) {
1682
+ const params = new URLSearchParams;
1683
+ if (options?.query)
1684
+ params.set("query", options.query);
1685
+ if (options?.limit !== undefined)
1686
+ params.set("limit", String(options.limit));
1687
+ if (options?.offset !== undefined)
1688
+ params.set("offset", String(options.offset));
1689
+ const url = `${this.endpoint}/search?${params.toString()}`;
1690
+ const response = await fetch(url);
1691
+ if (!response.ok) {
1692
+ throw new RegistryError(`Search failed: ${response.statusText}`);
1693
+ }
1694
+ const data = await response.json();
1695
+ return (data.results || []).map((locator) => parseRXL(locator));
1696
+ }
1697
+ }
1698
+ async function discoverRegistry(domain) {
1699
+ const wellKnownUrl = `https://${domain}/.well-known/resourcex`;
1700
+ try {
1701
+ const response = await fetch(wellKnownUrl);
1702
+ if (!response.ok) {
1703
+ throw new RegistryError(`Well-known discovery failed for ${domain}: ${response.statusText}`);
1704
+ }
1705
+ const data = await response.json();
1706
+ return data.registry;
1707
+ } catch (error) {
1708
+ if (error instanceof RegistryError) {
1709
+ throw error;
1710
+ }
1711
+ throw new RegistryError(`Failed to discover registry for ${domain}: ${error.message}`);
1712
+ }
1713
+ }
2081
1714
  // src/createRegistry.ts
2082
1715
  function createRegistry(config) {
2083
- return new ARPRegistry(config);
1716
+ if (isRemoteConfig(config)) {
1717
+ return new RemoteRegistry(config);
1718
+ }
1719
+ return new LocalRegistry(config);
2084
1720
  }
2085
1721
  export {
1722
+ isRemoteConfig,
1723
+ discoverRegistry,
2086
1724
  createRegistry,
1725
+ RemoteRegistry,
2087
1726
  RegistryError,
2088
- ARPRegistry
1727
+ LocalRegistry
2089
1728
  };
2090
1729
 
2091
- //# debugId=36E7744ADCB7821664756E2164756E21
1730
+ //# debugId=E606A28A0E6E3E5464756E2164756E21