@resourcexjs/arp 1.7.0 → 2.0.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/README.md CHANGED
@@ -19,7 +19,7 @@ arp:{semantic}:{transport}://{location}
19
19
  ```
20
20
 
21
21
  - **semantic**: Content interpretation (text, binary)
22
- - **transport**: Storage backend (file, http, https, agentvm)
22
+ - **transport**: Storage backend (file, http, https, rxr)
23
23
  - **location**: Resource location (path, URL)
24
24
 
25
25
  ### Examples
@@ -27,9 +27,24 @@ arp:{semantic}:{transport}://{location}
27
27
  ```
28
28
  arp:text:file://~/data.txt
29
29
  arp:binary:https://example.com/image.png
30
- arp:text:agentvm://sandbox/config.json
30
+ arp:text:rxr://localhost/my-prompt.text@1.0.0/content
31
31
  ```
32
32
 
33
+ ### Built-in Handlers
34
+
35
+ **createARP()** auto-registers all built-in handlers:
36
+
37
+ **Transports:**
38
+
39
+ - `file` - Local filesystem (read-write)
40
+ - `http`, `https` - Network resources (read-only)
41
+ - `rxr` - Files inside resources (read-only, auto-creates Registry)
42
+
43
+ **Semantics:**
44
+
45
+ - `text` - UTF-8 text → string
46
+ - `binary` - Raw bytes → Buffer
47
+
33
48
  ## Usage
34
49
 
35
50
  ### Basic Operations
@@ -289,21 +304,48 @@ const result = await arl.resolve({ lang: "en" });
289
304
  // Fetches: https://api.example.com/data?format=json&lang=en
290
305
  ```
291
306
 
292
- ### AgentVM Transport (`agentvm`)
307
+ ### RXR Transport (`rxr`)
293
308
 
294
- AgentVM sandbox storage (`~/.agentvm/`).
309
+ Access files inside ResourceX resources (read-only).
295
310
 
296
311
  ```typescript
297
- arp.parse("arp:text:agentvm://sandbox/config.json");
298
- // Maps to: ~/.agentvm/sandbox/config.json
312
+ // Format: arp:{semantic}:rxr://{rxl}/{internal-path}
313
+ arp.parse("arp:text:rxr://localhost/my-prompt.text@1.0.0/content");
314
+ arp.parse("arp:text:rxr://deepractice.ai/nuwa.text@1.0.0/thought/first-principles.md");
299
315
  ```
300
316
 
301
317
  **Operations:**
302
318
 
303
- - ✅ get (read)
304
- - set (write)
305
- - ✅ exists
306
- - delete
319
+ - ✅ get (read file from resource)
320
+ - set (read-only, throws error)
321
+ - ✅ exists (check if file exists in resource)
322
+ - delete (read-only, throws error)
323
+
324
+ **Auto-creates Registry:**
325
+
326
+ - `localhost` domain → LocalRegistry (filesystem)
327
+ - Other domains → RemoteRegistry (via well-known discovery)
328
+
329
+ ```typescript
330
+ // No manual setup needed - works out of the box!
331
+ const arp = createARP();
332
+ const arl = arp.parse("arp:text:rxr://localhost/hello.text@1.0.0/content");
333
+ const { content } = await arl.resolve();
334
+ // RxrTransport automatically creates LocalRegistry for localhost
335
+ ```
336
+
337
+ **Manual Registry injection (optional):**
338
+
339
+ ```typescript
340
+ import { createRegistry } from "@resourcexjs/registry";
341
+ import { createARP, RxrTransport } from "@resourcexjs/arp";
342
+
343
+ const registry = createRegistry({ path: "./custom-path" });
344
+ const rxrTransport = new RxrTransport(registry);
345
+
346
+ const arp = createARP();
347
+ arp.registerTransport(rxrTransport); // Override default rxr transport
348
+ ```
307
349
 
308
350
  ## Error Handling
309
351
 
package/dist/index.d.ts CHANGED
@@ -455,10 +455,14 @@ declare class RxrTransport implements TransportHandler {
455
455
  * Get or create a registry for the given domain.
456
456
  * - If a registry was provided in constructor, use it
457
457
  * - localhost: create LocalRegistry
458
- * - Other domains: discover endpoint via well-known and create RemoteRegistry
458
+ * - Other domains: discover endpoint via well-known and create appropriate registry
459
459
  */
460
460
  private getRegistry;
461
461
  /**
462
+ * Check if URL is a git repository URL.
463
+ */
464
+ private isGitUrl;
465
+ /**
462
466
  * Parse location into domain, RXL and internal path.
463
467
  * Format: {domain}/{path}/{name}.{type}@{version}/{internal-path}
464
468
  * Example: deepractice.ai/nuwa.role@1.0.0/thought/first-principles.md
package/dist/index.js CHANGED
@@ -282,9 +282,16 @@ import { join as join2 } from "node:path";
282
282
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rm as rm2, stat as stat2, readdir as readdir2 } from "node:fs/promises";
283
283
  import { gzip as gzip2, gunzip as gunzip2 } from "node:zlib";
284
284
  import { promisify as promisify2 } from "node:util";
285
+ import { homedir as homedir2 } from "node:os";
286
+ import { join as join22 } from "node:path";
287
+ import { readFile as readFile22, stat as stat22, readdir as readdir22, mkdir as mkdir22 } from "node:fs/promises";
288
+ import { execSync } from "node:child_process";
285
289
  function isRemoteConfig(config) {
286
290
  return config !== undefined && "endpoint" in config;
287
291
  }
292
+ function isGitConfig(config) {
293
+ return config !== undefined && "type" in config && config.type === "git";
294
+ }
288
295
 
289
296
  class ResourceXError extends Error {
290
297
  constructor(message, options) {
@@ -1754,23 +1761,63 @@ class LocalRegistry {
1754
1761
  supportType(type) {
1755
1762
  this.typeHandler.register(type);
1756
1763
  }
1757
- buildPath(locator) {
1764
+ buildPath(locator, area) {
1758
1765
  const rxl = typeof locator === "string" ? parseRXL(locator) : locator;
1759
- const domain = rxl.domain ?? "localhost";
1766
+ const resourceName = rxl.type ? `${rxl.name}.${rxl.type}` : rxl.name;
1760
1767
  const version = rxl.version ?? "latest";
1761
- let path = join2(this.basePath, domain);
1762
- if (rxl.path) {
1763
- path = join2(path, rxl.path);
1768
+ if (area === "local") {
1769
+ return join2(this.basePath, "local", resourceName, version);
1770
+ } else {
1771
+ const domain = rxl.domain ?? "localhost";
1772
+ let path = join2(this.basePath, "cache", domain);
1773
+ if (rxl.path) {
1774
+ path = join2(path, rxl.path);
1775
+ }
1776
+ return join2(path, resourceName, version);
1764
1777
  }
1765
- const resourceName = rxl.type ? `${rxl.name}.${rxl.type}` : rxl.name;
1766
- return join2(path, resourceName, version);
1767
1778
  }
1768
- async publish(_resource) {
1769
- throw new RegistryError("Remote publish not implemented yet");
1779
+ isLocalOnlyLocator(locator) {
1780
+ const rxl = typeof locator === "string" ? parseRXL(locator) : locator;
1781
+ return !rxl.domain || rxl.domain === "localhost";
1782
+ }
1783
+ async existsAt(resourcePath) {
1784
+ const manifestPath = join2(resourcePath, "manifest.json");
1785
+ try {
1786
+ await stat2(manifestPath);
1787
+ return true;
1788
+ } catch {
1789
+ return false;
1790
+ }
1791
+ }
1792
+ async findArea(locator) {
1793
+ const localPath = this.buildPath(locator, "local");
1794
+ if (await this.existsAt(localPath)) {
1795
+ return "local";
1796
+ }
1797
+ const cachePath = this.buildPath(locator, "cache");
1798
+ if (await this.existsAt(cachePath)) {
1799
+ return "cache";
1800
+ }
1801
+ return null;
1802
+ }
1803
+ async loadFrom(resourcePath) {
1804
+ const manifestPath = join2(resourcePath, "manifest.json");
1805
+ const manifestContent = await readFile2(manifestPath, "utf-8");
1806
+ const manifestData = JSON.parse(manifestContent);
1807
+ const manifest = createRXM(manifestData);
1808
+ const contentPath = join2(resourcePath, "content.tar.gz");
1809
+ const data = await readFile2(contentPath);
1810
+ return this.typeHandler.deserialize(data, manifest);
1811
+ }
1812
+ async pull(_locator, _options) {
1813
+ throw new RegistryError("Pull not implemented yet - see issue #018");
1814
+ }
1815
+ async publish(_resource, _options) {
1816
+ throw new RegistryError("Publish not implemented yet - see issue #018");
1770
1817
  }
1771
1818
  async link(resource) {
1772
1819
  const locator = resource.manifest.toLocator();
1773
- const resourcePath = this.buildPath(locator);
1820
+ const resourcePath = this.buildPath(locator, "local");
1774
1821
  await mkdir2(resourcePath, { recursive: true });
1775
1822
  const manifestPath = join2(resourcePath, "manifest.json");
1776
1823
  await writeFile2(manifestPath, JSON.stringify(resource.manifest.toJSON(), null, 2), "utf-8");
@@ -1779,58 +1826,62 @@ class LocalRegistry {
1779
1826
  await writeFile2(contentPath, serialized);
1780
1827
  }
1781
1828
  async get(locator) {
1782
- if (!await this.exists(locator)) {
1829
+ const area = await this.findArea(locator);
1830
+ if (!area) {
1783
1831
  throw new RegistryError(`Resource not found: ${locator}`);
1784
1832
  }
1785
- const resourcePath = this.buildPath(locator);
1786
- const manifestPath = join2(resourcePath, "manifest.json");
1787
- const manifestContent = await readFile2(manifestPath, "utf-8");
1788
- const manifestData = JSON.parse(manifestContent);
1789
- const manifest = createRXM(manifestData);
1790
- const contentPath = join2(resourcePath, "content.tar.gz");
1791
- const data = await readFile2(contentPath);
1792
- return this.typeHandler.deserialize(data, manifest);
1833
+ const resourcePath = this.buildPath(locator, area);
1834
+ return this.loadFrom(resourcePath);
1793
1835
  }
1794
1836
  async resolve(locator) {
1795
1837
  const rxr = await this.get(locator);
1796
1838
  return this.typeHandler.resolve(rxr);
1797
1839
  }
1798
1840
  async exists(locator) {
1799
- const resourcePath = this.buildPath(locator);
1800
- const manifestPath = join2(resourcePath, "manifest.json");
1801
- try {
1802
- await stat2(manifestPath);
1803
- return true;
1804
- } catch {
1805
- return false;
1806
- }
1841
+ const area = await this.findArea(locator);
1842
+ return area !== null;
1807
1843
  }
1808
1844
  async delete(locator) {
1809
- if (!await this.exists(locator)) {
1810
- return;
1845
+ const isLocal = this.isLocalOnlyLocator(locator);
1846
+ if (isLocal) {
1847
+ const localPath = this.buildPath(locator, "local");
1848
+ if (await this.existsAt(localPath)) {
1849
+ await rm2(localPath, { recursive: true, force: true });
1850
+ }
1851
+ } else {
1852
+ const cachePath = this.buildPath(locator, "cache");
1853
+ if (await this.existsAt(cachePath)) {
1854
+ await rm2(cachePath, { recursive: true, force: true });
1855
+ }
1811
1856
  }
1812
- const resourcePath = this.buildPath(locator);
1813
- await rm2(resourcePath, { recursive: true, force: true });
1814
1857
  }
1815
1858
  async search(options) {
1816
1859
  const { query, limit, offset = 0 } = options ?? {};
1817
- let entries;
1818
- try {
1819
- entries = await this.listRecursive(this.basePath);
1820
- } catch {
1821
- return [];
1822
- }
1823
1860
  const locators = [];
1824
- for (const entry of entries) {
1825
- if (!entry.endsWith("manifest.json")) {
1826
- continue;
1861
+ const localDir = join2(this.basePath, "local");
1862
+ try {
1863
+ const localEntries = await this.listRecursive(localDir);
1864
+ for (const entry of localEntries) {
1865
+ if (!entry.endsWith("manifest.json"))
1866
+ continue;
1867
+ const relativePath = entry.slice(localDir.length + 1);
1868
+ const rxl = this.parseLocalEntry(relativePath);
1869
+ if (rxl)
1870
+ locators.push(rxl);
1827
1871
  }
1828
- const relativePath = entry.slice(this.basePath.length + 1);
1829
- const rxl = this.parseEntryToRXL(relativePath);
1830
- if (rxl) {
1831
- locators.push(rxl);
1872
+ } catch {}
1873
+ const cacheDir = join2(this.basePath, "cache");
1874
+ try {
1875
+ const cacheEntries = await this.listRecursive(cacheDir);
1876
+ for (const entry of cacheEntries) {
1877
+ if (!entry.endsWith("manifest.json"))
1878
+ continue;
1879
+ const relativePath = entry.slice(cacheDir.length + 1);
1880
+ const rxl = this.parseCacheEntry(relativePath);
1881
+ if (rxl)
1882
+ locators.push(rxl);
1832
1883
  }
1833
- }
1884
+ } catch {}
1834
1885
  let filtered = locators;
1835
1886
  if (query) {
1836
1887
  const lowerQuery = query.toLowerCase();
@@ -1861,7 +1912,27 @@ class LocalRegistry {
1861
1912
  } catch {}
1862
1913
  return results;
1863
1914
  }
1864
- parseEntryToRXL(entry) {
1915
+ parseLocalEntry(entry) {
1916
+ const dirPath = entry.replace(/[/\\]manifest\.json$/, "");
1917
+ const parts = dirPath.split(/[/\\]/);
1918
+ if (parts.length < 2) {
1919
+ return null;
1920
+ }
1921
+ const version = parts.pop();
1922
+ const nameTypePart = parts.shift();
1923
+ const { name, type } = this.parseNameType(nameTypePart);
1924
+ let locatorStr = name;
1925
+ if (type) {
1926
+ locatorStr += `.${type}`;
1927
+ }
1928
+ locatorStr += `@${version}`;
1929
+ try {
1930
+ return parseRXL(locatorStr);
1931
+ } catch {
1932
+ return null;
1933
+ }
1934
+ }
1935
+ parseCacheEntry(entry) {
1865
1936
  const dirPath = entry.replace(/[/\\]manifest\.json$/, "");
1866
1937
  const parts = dirPath.split(/[/\\]/);
1867
1938
  if (parts.length < 3) {
@@ -1871,16 +1942,7 @@ class LocalRegistry {
1871
1942
  const nameTypePart = parts.pop();
1872
1943
  const domain = parts.shift();
1873
1944
  const path = parts.length > 0 ? parts.join("/") : undefined;
1874
- const dotIndex = nameTypePart.lastIndexOf(".");
1875
- let name;
1876
- let type;
1877
- if (dotIndex !== -1) {
1878
- name = nameTypePart.substring(0, dotIndex);
1879
- type = nameTypePart.substring(dotIndex + 1);
1880
- } else {
1881
- name = nameTypePart;
1882
- type = undefined;
1883
- }
1945
+ const { name, type } = this.parseNameType(nameTypePart);
1884
1946
  let locatorStr = domain;
1885
1947
  if (path) {
1886
1948
  locatorStr += `/${path}`;
@@ -1896,6 +1958,17 @@ class LocalRegistry {
1896
1958
  return null;
1897
1959
  }
1898
1960
  }
1961
+ parseNameType(nameTypePart) {
1962
+ const dotIndex = nameTypePart.lastIndexOf(".");
1963
+ if (dotIndex !== -1) {
1964
+ return {
1965
+ name: nameTypePart.substring(0, dotIndex),
1966
+ type: nameTypePart.substring(dotIndex + 1)
1967
+ };
1968
+ } else {
1969
+ return { name: nameTypePart, type: undefined };
1970
+ }
1971
+ }
1899
1972
  }
1900
1973
 
1901
1974
  class RemoteRegistry {
@@ -1908,7 +1981,10 @@ class RemoteRegistry {
1908
1981
  supportType(type) {
1909
1982
  this.typeHandler.register(type);
1910
1983
  }
1911
- async publish(_resource) {
1984
+ async pull(_locator, _options) {
1985
+ throw new RegistryError("Cannot pull to remote registry - use local registry for pulling");
1986
+ }
1987
+ async publish(_resource, _options) {
1912
1988
  throw new RegistryError("Remote registry publish not implemented yet");
1913
1989
  }
1914
1990
  async link(_resource) {
@@ -1974,7 +2050,13 @@ async function discoverRegistry(domain) {
1974
2050
  throw new RegistryError(`Well-known discovery failed for ${domain}: ${response.statusText}`);
1975
2051
  }
1976
2052
  const data = await response.json();
1977
- return data.registry;
2053
+ if (!data.registries || !Array.isArray(data.registries) || data.registries.length === 0) {
2054
+ throw new RegistryError(`Invalid well-known response for ${domain}: missing or empty registries`);
2055
+ }
2056
+ return {
2057
+ domain,
2058
+ registries: data.registries
2059
+ };
1978
2060
  } catch (error) {
1979
2061
  if (error instanceof RegistryError) {
1980
2062
  throw error;
@@ -1982,10 +2064,210 @@ async function discoverRegistry(domain) {
1982
2064
  throw new RegistryError(`Failed to discover registry for ${domain}: ${error.message}`);
1983
2065
  }
1984
2066
  }
2067
+ var DEFAULT_GIT_CACHE = `${homedir2()}/.resourcex/.git-cache`;
2068
+
2069
+ class GitRegistry {
2070
+ url;
2071
+ ref;
2072
+ basePath;
2073
+ cacheDir;
2074
+ typeHandler;
2075
+ trustedDomain;
2076
+ constructor(config) {
2077
+ this.url = config.url;
2078
+ this.ref = config.ref ?? "main";
2079
+ this.basePath = config.basePath ?? ".resourcex";
2080
+ this.typeHandler = TypeHandlerChain.create();
2081
+ this.trustedDomain = config.domain;
2082
+ if (this.isRemoteUrl(config.url) && !config.domain) {
2083
+ throw new RegistryError(`Remote git registry requires a trusted domain.
2084
+
2085
+ ` + `Either:
2086
+ ` + `1. Use discoverRegistry("your-domain.com") to auto-bind domain
2087
+ ` + `2. Explicitly set domain: createRegistry({ type: "git", url: "...", domain: "your-domain.com" })
2088
+
2089
+ ` + `This ensures resources from untrusted sources cannot impersonate your domain.`);
2090
+ }
2091
+ this.cacheDir = this.buildCacheDir(config.url);
2092
+ }
2093
+ isRemoteUrl(url) {
2094
+ return url.startsWith("git@") || url.startsWith("https://") || url.startsWith("http://");
2095
+ }
2096
+ buildCacheDir(url) {
2097
+ let normalized = url;
2098
+ if (url.startsWith("git@")) {
2099
+ normalized = url.slice(4).replace(":", "/");
2100
+ }
2101
+ if (normalized.endsWith(".git")) {
2102
+ normalized = normalized.slice(0, -4);
2103
+ }
2104
+ const dirName = normalized.replace(/\//g, "-");
2105
+ return join22(DEFAULT_GIT_CACHE, dirName);
2106
+ }
2107
+ supportType(type) {
2108
+ this.typeHandler.register(type);
2109
+ }
2110
+ async ensureCloned() {
2111
+ const gitDir = join22(this.cacheDir, ".git");
2112
+ try {
2113
+ await stat22(gitDir);
2114
+ this.gitExec(`fetch origin ${this.ref}`);
2115
+ this.gitExec(`checkout FETCH_HEAD`);
2116
+ } catch {
2117
+ await mkdir22(DEFAULT_GIT_CACHE, { recursive: true });
2118
+ execSync(`git clone --depth 1 --branch ${this.ref} ${this.url} ${this.cacheDir}`, {
2119
+ stdio: "pipe"
2120
+ });
2121
+ }
2122
+ }
2123
+ gitExec(command) {
2124
+ execSync(`git -C ${this.cacheDir} ${command}`, { stdio: "pipe" });
2125
+ }
2126
+ buildResourcePath(locator) {
2127
+ const rxl = parseRXL(locator);
2128
+ const domain = rxl.domain ?? "localhost";
2129
+ const version = rxl.version ?? "latest";
2130
+ let path = join22(this.cacheDir, this.basePath, domain);
2131
+ if (rxl.path) {
2132
+ path = join22(path, rxl.path);
2133
+ }
2134
+ const resourceName = rxl.type ? `${rxl.name}.${rxl.type}` : rxl.name;
2135
+ return join22(path, resourceName, version);
2136
+ }
2137
+ async get(locator) {
2138
+ await this.ensureCloned();
2139
+ const resourcePath = this.buildResourcePath(locator);
2140
+ const manifestPath = join22(resourcePath, "manifest.json");
2141
+ try {
2142
+ await stat22(manifestPath);
2143
+ } catch {
2144
+ throw new RegistryError(`Resource not found: ${locator}`);
2145
+ }
2146
+ const manifestContent = await readFile22(manifestPath, "utf-8");
2147
+ const manifestData = JSON.parse(manifestContent);
2148
+ const manifest = createRXM(manifestData);
2149
+ if (this.trustedDomain && manifest.domain !== this.trustedDomain) {
2150
+ throw new RegistryError(`Untrusted domain: resource claims "${manifest.domain}" but registry only trusts "${this.trustedDomain}"`);
2151
+ }
2152
+ const contentPath = join22(resourcePath, "content.tar.gz");
2153
+ const data = await readFile22(contentPath);
2154
+ return this.typeHandler.deserialize(data, manifest);
2155
+ }
2156
+ async resolve(locator) {
2157
+ const rxr = await this.get(locator);
2158
+ return this.typeHandler.resolve(rxr);
2159
+ }
2160
+ async exists(locator) {
2161
+ try {
2162
+ await this.ensureCloned();
2163
+ const resourcePath = this.buildResourcePath(locator);
2164
+ const manifestPath = join22(resourcePath, "manifest.json");
2165
+ await stat22(manifestPath);
2166
+ return true;
2167
+ } catch {
2168
+ return false;
2169
+ }
2170
+ }
2171
+ async search(options) {
2172
+ await this.ensureCloned();
2173
+ const { query, limit, offset = 0 } = options ?? {};
2174
+ const locators = [];
2175
+ const baseDir = join22(this.cacheDir, this.basePath);
2176
+ try {
2177
+ const entries = await this.listRecursive(baseDir);
2178
+ for (const entry of entries) {
2179
+ if (!entry.endsWith("manifest.json"))
2180
+ continue;
2181
+ const relativePath = entry.slice(baseDir.length + 1);
2182
+ const rxl = this.parseEntryToRXL(relativePath);
2183
+ if (rxl)
2184
+ locators.push(rxl);
2185
+ }
2186
+ } catch {
2187
+ return [];
2188
+ }
2189
+ let filtered = locators;
2190
+ if (query) {
2191
+ const lowerQuery = query.toLowerCase();
2192
+ filtered = locators.filter((rxl) => {
2193
+ const searchText = `${rxl.domain ?? ""} ${rxl.path ?? ""} ${rxl.name} ${rxl.type ?? ""}`.toLowerCase();
2194
+ return searchText.includes(lowerQuery);
2195
+ });
2196
+ }
2197
+ let result = filtered.slice(offset);
2198
+ if (limit !== undefined) {
2199
+ result = result.slice(0, limit);
2200
+ }
2201
+ return result;
2202
+ }
2203
+ async listRecursive(dir) {
2204
+ const results = [];
2205
+ try {
2206
+ const entries = await readdir22(dir, { withFileTypes: true });
2207
+ for (const entry of entries) {
2208
+ const fullPath = join22(dir, entry.name);
2209
+ if (entry.isDirectory()) {
2210
+ const subEntries = await this.listRecursive(fullPath);
2211
+ results.push(...subEntries);
2212
+ } else {
2213
+ results.push(fullPath);
2214
+ }
2215
+ }
2216
+ } catch {}
2217
+ return results;
2218
+ }
2219
+ parseEntryToRXL(entry) {
2220
+ const dirPath = entry.replace(/[/\\]manifest\.json$/, "");
2221
+ const parts = dirPath.split(/[/\\]/);
2222
+ if (parts.length < 3)
2223
+ return null;
2224
+ const version = parts.pop();
2225
+ const nameTypePart = parts.pop();
2226
+ const domain = parts.shift();
2227
+ const path = parts.length > 0 ? parts.join("/") : undefined;
2228
+ const dotIndex = nameTypePart.lastIndexOf(".");
2229
+ let name;
2230
+ let type;
2231
+ if (dotIndex !== -1) {
2232
+ name = nameTypePart.substring(0, dotIndex);
2233
+ type = nameTypePart.substring(dotIndex + 1);
2234
+ } else {
2235
+ name = nameTypePart;
2236
+ type = undefined;
2237
+ }
2238
+ let locatorStr = domain;
2239
+ if (path)
2240
+ locatorStr += `/${path}`;
2241
+ locatorStr += `/${name}`;
2242
+ if (type)
2243
+ locatorStr += `.${type}`;
2244
+ locatorStr += `@${version}`;
2245
+ try {
2246
+ return parseRXL(locatorStr);
2247
+ } catch {
2248
+ return null;
2249
+ }
2250
+ }
2251
+ async pull(_locator, _options) {
2252
+ throw new RegistryError("GitRegistry is read-only - use LocalRegistry.pull()");
2253
+ }
2254
+ async publish(_resource, _options) {
2255
+ throw new RegistryError("GitRegistry is read-only - use LocalRegistry.publish()");
2256
+ }
2257
+ async link(_resource) {
2258
+ throw new RegistryError("GitRegistry is read-only - use LocalRegistry.link()");
2259
+ }
2260
+ async delete(_locator) {
2261
+ throw new RegistryError("GitRegistry is read-only - use LocalRegistry.delete()");
2262
+ }
2263
+ }
1985
2264
  function createRegistry(config) {
1986
2265
  if (isRemoteConfig(config)) {
1987
2266
  return new RemoteRegistry(config);
1988
2267
  }
2268
+ if (isGitConfig(config)) {
2269
+ return new GitRegistry(config);
2270
+ }
1989
2271
  return new LocalRegistry(config);
1990
2272
  }
1991
2273
 
@@ -2041,8 +2323,17 @@ class RxrTransport {
2041
2323
  registry = createRegistry();
2042
2324
  } else {
2043
2325
  try {
2044
- const endpoint = await discoverRegistry(domain);
2045
- registry = createRegistry({ endpoint });
2326
+ const discovery = await discoverRegistry(domain);
2327
+ const registryUrl = discovery.registries[0];
2328
+ if (this.isGitUrl(registryUrl)) {
2329
+ registry = createRegistry({
2330
+ type: "git",
2331
+ url: registryUrl,
2332
+ domain: discovery.domain
2333
+ });
2334
+ } else {
2335
+ registry = createRegistry({ endpoint: registryUrl });
2336
+ }
2046
2337
  } catch (error) {
2047
2338
  throw new TransportError(`Failed to discover registry for domain ${domain}: ${error.message}`, this.name);
2048
2339
  }
@@ -2050,6 +2341,9 @@ class RxrTransport {
2050
2341
  registryCache.set(domain, registry);
2051
2342
  return registry;
2052
2343
  }
2344
+ isGitUrl(url) {
2345
+ return url.startsWith("git@") || url.endsWith(".git");
2346
+ }
2053
2347
  parseLocation(location) {
2054
2348
  const atIndex = location.indexOf("@");
2055
2349
  if (atIndex === -1) {
@@ -2270,7 +2564,7 @@ function createARP(config) {
2270
2564
  }
2271
2565
 
2272
2566
  // src/index.ts
2273
- var VERSION = "1.7.0";
2567
+ var VERSION = "2.0.0";
2274
2568
  export {
2275
2569
  textSemantic,
2276
2570
  httpsTransport,
@@ -2292,4 +2586,4 @@ export {
2292
2586
  ARP
2293
2587
  };
2294
2588
 
2295
- //# debugId=A454D6FE1CE0DCC764756E2164756E21
2589
+ //# debugId=1847C08CED2B25BC64756E2164756E21