@resourcexjs/registry 1.5.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,78 +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
- let path = `${this.basePath}/${domain}`;
1489
+ const version = rxl.version ?? "latest";
1490
+ let path = join(this.basePath, domain);
1958
1491
  if (rxl.path) {
1959
- path += `/${rxl.path}`;
1492
+ path = join(path, rxl.path);
1960
1493
  }
1961
- const resourceDir = rxl.type ? `${rxl.name}.${rxl.type}@${rxl.version ?? "latest"}` : `${rxl.name}@${rxl.version ?? "latest"}`;
1962
- return `arp:text:file://${path}/${resourceDir}/${filename}`;
1494
+ const resourceName = rxl.type ? `${rxl.name}.${rxl.type}` : rxl.name;
1495
+ return join(path, resourceName, version);
1963
1496
  }
1964
1497
  async publish(_resource) {
1965
1498
  throw new RegistryError("Remote publish not implemented yet");
1966
1499
  }
1967
1500
  async link(resource) {
1968
1501
  const locator = resource.manifest.toLocator();
1969
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1970
- const manifestArl = this.arp.parse(manifestUrl);
1971
- await manifestArl.deposit(JSON.stringify(resource.manifest.toJSON(), null, 2));
1972
- const contentUrl = this.buildUrl(locator, "content").replace("arp:text:", "arp:binary:");
1973
- 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");
1974
1507
  const serialized = await this.typeHandler.serialize(resource);
1975
- await contentArl.deposit(serialized);
1508
+ await writeFile(contentPath, serialized);
1976
1509
  }
1977
- async resolve(locator) {
1510
+ async get(locator) {
1978
1511
  if (!await this.exists(locator)) {
1979
1512
  throw new RegistryError(`Resource not found: ${locator}`);
1980
1513
  }
1981
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1982
- const manifestArl = this.arp.parse(manifestUrl);
1983
- const manifestResult = await manifestArl.resolve();
1984
- 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);
1985
1518
  const manifest = createRXM(manifestData);
1986
- const contentUrl = this.buildUrl(locator, "content").replace("arp:text:", "arp:binary:");
1987
- const contentArl = this.arp.parse(contentUrl);
1988
- const contentResult = await contentArl.resolve();
1989
- const data = contentResult.content;
1990
- 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);
1991
1525
  return this.typeHandler.resolve(rxr);
1992
1526
  }
1993
1527
  async exists(locator) {
1994
- const manifestUrl = this.buildUrl(locator, "manifest.json");
1995
- const manifestArl = this.arp.parse(manifestUrl);
1996
- 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
+ }
1997
1536
  }
1998
1537
  async delete(locator) {
1999
1538
  if (!await this.exists(locator)) {
2000
1539
  return;
2001
1540
  }
2002
- const manifestUrl = this.buildUrl(locator, "manifest.json");
2003
- const manifestArl = this.arp.parse(manifestUrl);
2004
- await manifestArl.delete();
2005
- const contentUrl = this.buildUrl(locator, "content").replace("arp:text:", "arp:binary:");
2006
- const contentArl = this.arp.parse(contentUrl);
2007
- await contentArl.delete();
1541
+ const resourcePath = this.buildPath(locator);
1542
+ await rm(resourcePath, { recursive: true, force: true });
2008
1543
  }
2009
1544
  async search(options) {
2010
1545
  const { query, limit, offset = 0 } = options ?? {};
2011
- const baseUrl = `arp:text:file://${this.basePath}`;
2012
- const baseArl = this.arp.parse(baseUrl);
2013
1546
  let entries;
2014
1547
  try {
2015
- const result2 = await baseArl.resolve({ recursive: "true" });
2016
- entries = JSON.parse(result2.content);
1548
+ entries = await this.listRecursive(this.basePath);
2017
1549
  } catch {
2018
1550
  return [];
2019
1551
  }
2020
1552
  const locators = [];
2021
1553
  for (const entry of entries) {
2022
- if (!entry.endsWith("/manifest.json")) {
1554
+ if (!entry.endsWith("manifest.json")) {
2023
1555
  continue;
2024
1556
  }
2025
- const rxl = this.parseEntryToRXL(entry);
1557
+ const relativePath = entry.slice(this.basePath.length + 1);
1558
+ const rxl = this.parseEntryToRXL(relativePath);
2026
1559
  if (rxl) {
2027
1560
  locators.push(rxl);
2028
1561
  }
@@ -2041,21 +1574,32 @@ class ARPRegistry {
2041
1574
  }
2042
1575
  return result;
2043
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
+ }
2044
1593
  parseEntryToRXL(entry) {
2045
- const dirPath = entry.replace(/\/manifest\.json$/, "");
2046
- const parts = dirPath.split("/");
2047
- if (parts.length < 2) {
1594
+ const dirPath = entry.replace(/[/\\]manifest\.json$/, "");
1595
+ const parts = dirPath.split(/[/\\]/);
1596
+ if (parts.length < 3) {
2048
1597
  return null;
2049
1598
  }
2050
- const resourceDir = parts.pop();
1599
+ const version = parts.pop();
1600
+ const nameTypePart = parts.pop();
2051
1601
  const domain = parts.shift();
2052
1602
  const path = parts.length > 0 ? parts.join("/") : undefined;
2053
- const atIndex = resourceDir.lastIndexOf("@");
2054
- if (atIndex === -1) {
2055
- return null;
2056
- }
2057
- const nameTypePart = resourceDir.substring(0, atIndex);
2058
- const version = resourceDir.substring(atIndex + 1);
2059
1603
  const dotIndex = nameTypePart.lastIndexOf(".");
2060
1604
  let name;
2061
1605
  let type;
@@ -2082,14 +1626,105 @@ class ARPRegistry {
2082
1626
  }
2083
1627
  }
2084
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
+ }
2085
1714
  // src/createRegistry.ts
2086
1715
  function createRegistry(config) {
2087
- return new ARPRegistry(config);
1716
+ if (isRemoteConfig(config)) {
1717
+ return new RemoteRegistry(config);
1718
+ }
1719
+ return new LocalRegistry(config);
2088
1720
  }
2089
1721
  export {
1722
+ isRemoteConfig,
1723
+ discoverRegistry,
2090
1724
  createRegistry,
1725
+ RemoteRegistry,
2091
1726
  RegistryError,
2092
- ARPRegistry
1727
+ LocalRegistry
2093
1728
  };
2094
1729
 
2095
- //# debugId=5D28792DAFF87E5D64756E2164756E21
1730
+ //# debugId=E606A28A0E6E3E5464756E2164756E21