@resourcexjs/core 2.5.4 → 2.5.6

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
@@ -35,7 +35,7 @@ class DefinitionError extends ResourceXError {
35
35
  this.name = "DefinitionError";
36
36
  }
37
37
  }
38
- // src/primitives/define.ts
38
+ // src/model/define.ts
39
39
  function define(input) {
40
40
  if (input === null || typeof input !== "object") {
41
41
  throw new DefinitionError("definition must be an object");
@@ -66,7 +66,7 @@ function define(input) {
66
66
  };
67
67
  return rxd;
68
68
  }
69
- // src/primitives/manifest.ts
69
+ // src/model/manifest.ts
70
70
  function manifest(rxd) {
71
71
  return {
72
72
  registry: rxd.registry,
@@ -76,7 +76,7 @@ function manifest(rxd) {
76
76
  tag: rxd.tag ?? "latest"
77
77
  };
78
78
  }
79
- // src/primitives/archive.ts
79
+ // src/model/archive.ts
80
80
  import { gzip } from "node:zlib";
81
81
  import { promisify } from "node:util";
82
82
 
@@ -1057,7 +1057,7 @@ async function unpackTar(archive, options = {}) {
1057
1057
  return results;
1058
1058
  }
1059
1059
 
1060
- // src/primitives/archive.ts
1060
+ // src/model/archive.ts
1061
1061
  var gzipAsync = promisify(gzip);
1062
1062
 
1063
1063
  class RXAImpl {
@@ -1089,7 +1089,7 @@ async function archive(files) {
1089
1089
  const gzipBuffer = await gzipAsync(Buffer.from(tarBuffer));
1090
1090
  return new RXAImpl(gzipBuffer);
1091
1091
  }
1092
- // src/primitives/locate.ts
1092
+ // src/model/locate.ts
1093
1093
  function locate(rxm) {
1094
1094
  return {
1095
1095
  registry: rxm.registry,
@@ -1098,7 +1098,7 @@ function locate(rxm) {
1098
1098
  tag: rxm.tag
1099
1099
  };
1100
1100
  }
1101
- // src/primitives/resource.ts
1101
+ // src/model/resource.ts
1102
1102
  function resource(rxm, rxa) {
1103
1103
  const rxl = locate(rxm);
1104
1104
  return {
@@ -1107,7 +1107,7 @@ function resource(rxm, rxa) {
1107
1107
  archive: rxa
1108
1108
  };
1109
1109
  }
1110
- // src/primitives/extract.ts
1110
+ // src/model/extract.ts
1111
1111
  import { gunzip } from "node:zlib";
1112
1112
  import { promisify as promisify2 } from "node:util";
1113
1113
  var gunzipAsync = promisify2(gunzip);
@@ -1123,7 +1123,7 @@ async function extract(rxa) {
1123
1123
  }
1124
1124
  return files;
1125
1125
  }
1126
- // src/primitives/format.ts
1126
+ // src/model/format.ts
1127
1127
  function format(rxl) {
1128
1128
  let result = "";
1129
1129
  if (rxl.registry) {
@@ -1138,7 +1138,7 @@ function format(rxl) {
1138
1138
  }
1139
1139
  return result;
1140
1140
  }
1141
- // src/primitives/parse.ts
1141
+ // src/model/parse.ts
1142
1142
  function looksLikeRegistry(str) {
1143
1143
  if (str.includes(":") && !str.includes("/")) {
1144
1144
  return true;
@@ -1207,7 +1207,7 @@ function parse(locator) {
1207
1207
  tag
1208
1208
  };
1209
1209
  }
1210
- // src/primitives/wrap.ts
1210
+ // src/model/wrap.ts
1211
1211
  class RXAImpl2 {
1212
1212
  _buffer;
1213
1213
  constructor(buffer) {
@@ -1229,21 +1229,689 @@ class RXAImpl2 {
1229
1229
  function wrap(buffer) {
1230
1230
  return new RXAImpl2(buffer);
1231
1231
  }
1232
+ // src/type/bundler.ts
1233
+ import { readFile } from "node:fs/promises";
1234
+ import { resolve, isAbsolute } from "node:path";
1235
+ async function bundleResourceType(sourcePath, basePath) {
1236
+ const fullPath = isAbsolute(sourcePath) ? sourcePath : resolve(basePath ?? process.cwd(), sourcePath);
1237
+ const source = await readFile(fullPath, "utf-8");
1238
+ const result = await Bun.build({
1239
+ stdin: {
1240
+ contents: source,
1241
+ resolveDir: resolve(fullPath, ".."),
1242
+ loader: "ts"
1243
+ },
1244
+ target: "bun",
1245
+ format: "esm",
1246
+ minify: false
1247
+ });
1248
+ if (!result.success) {
1249
+ const errors = result.logs.map((log) => log.message).join(`
1250
+ `);
1251
+ throw new Error(`Failed to bundle ${sourcePath}: ${errors}`);
1252
+ }
1253
+ const bundledCode = await result.outputs[0].text();
1254
+ const tempModule = await import(fullPath);
1255
+ const typeSource = tempModule.default;
1256
+ if (!typeSource.name) {
1257
+ throw new Error(`Resource type at ${sourcePath} must have a name`);
1258
+ }
1259
+ if (typeof typeSource.resolve !== "function") {
1260
+ throw new Error(`Resource type at ${sourcePath} must have a resolve function`);
1261
+ }
1262
+ return {
1263
+ name: typeSource.name,
1264
+ aliases: typeSource.aliases,
1265
+ description: typeSource.description ?? "",
1266
+ schema: typeSource.schema,
1267
+ code: bundledCode
1268
+ };
1269
+ }
1270
+ // src/type/errors.ts
1271
+ class ResourceTypeError extends ResourceXError {
1272
+ constructor(message) {
1273
+ super(message);
1274
+ this.name = "ResourceTypeError";
1275
+ }
1276
+ }
1277
+ // src/type/builtinTypes.ts
1278
+ var textType = {
1279
+ name: "text",
1280
+ aliases: ["txt", "plaintext"],
1281
+ description: "Plain text content",
1282
+ code: `// @resolver: text_type_default
1283
+ // src/builtins/text.type.ts
1284
+ var text_type_default = {
1285
+ name: "text",
1286
+ aliases: ["txt", "plaintext"],
1287
+ description: "Plain text content",
1288
+ async resolve(ctx) {
1289
+ const content = ctx.files["content"];
1290
+ return new TextDecoder().decode(content);
1291
+ }
1292
+ };`
1293
+ };
1294
+ var jsonType = {
1295
+ name: "json",
1296
+ aliases: ["config", "manifest"],
1297
+ description: "JSON content",
1298
+ code: `// @resolver: json_type_default
1299
+ // src/builtins/json.type.ts
1300
+ var json_type_default = {
1301
+ name: "json",
1302
+ aliases: ["config", "manifest"],
1303
+ description: "JSON content",
1304
+ async resolve(ctx) {
1305
+ const content = ctx.files["content"];
1306
+ return JSON.parse(new TextDecoder().decode(content));
1307
+ }
1308
+ };`
1309
+ };
1310
+ var binaryType = {
1311
+ name: "binary",
1312
+ aliases: ["bin", "blob", "raw"],
1313
+ description: "Binary content",
1314
+ code: `// @resolver: binary_type_default
1315
+ // src/builtins/binary.type.ts
1316
+ var binary_type_default = {
1317
+ name: "binary",
1318
+ aliases: ["bin", "blob", "raw"],
1319
+ description: "Binary content",
1320
+ async resolve(ctx) {
1321
+ return ctx.files["content"];
1322
+ }
1323
+ };`
1324
+ };
1325
+ var builtinTypes = [textType, jsonType, binaryType];
1326
+
1327
+ // src/type/TypeHandlerChain.ts
1328
+ class TypeHandlerChain {
1329
+ handlers = new Map;
1330
+ constructor() {
1331
+ for (const type of builtinTypes) {
1332
+ this.registerInternal(type);
1333
+ }
1334
+ }
1335
+ static create() {
1336
+ return new TypeHandlerChain;
1337
+ }
1338
+ registerInternal(type) {
1339
+ this.handlers.set(type.name, type);
1340
+ if (type.aliases) {
1341
+ for (const alias of type.aliases) {
1342
+ this.handlers.set(alias, type);
1343
+ }
1344
+ }
1345
+ }
1346
+ register(type) {
1347
+ if (this.handlers.has(type.name)) {
1348
+ throw new ResourceTypeError(`Type '${type.name}' is already registered`);
1349
+ }
1350
+ this.handlers.set(type.name, type);
1351
+ if (type.aliases) {
1352
+ for (const alias of type.aliases) {
1353
+ if (this.handlers.has(alias)) {
1354
+ throw new ResourceTypeError(`Alias '${alias}' conflicts with existing type or alias`);
1355
+ }
1356
+ this.handlers.set(alias, type);
1357
+ }
1358
+ }
1359
+ }
1360
+ canHandle(typeName) {
1361
+ return this.handlers.has(typeName);
1362
+ }
1363
+ getHandler(typeName) {
1364
+ const handler = this.handlers.get(typeName);
1365
+ if (!handler) {
1366
+ throw new ResourceTypeError(`Unsupported resource type: ${typeName}`);
1367
+ }
1368
+ return handler;
1369
+ }
1370
+ getHandlerOrUndefined(typeName) {
1371
+ return this.handlers.get(typeName);
1372
+ }
1373
+ getSupportedTypes() {
1374
+ return Array.from(this.handlers.keys());
1375
+ }
1376
+ clear() {
1377
+ this.handlers.clear();
1378
+ }
1379
+ }
1380
+ // src/loader/FolderLoader.ts
1381
+ import { join, relative } from "node:path";
1382
+ import { stat, readFile as readFile2, readdir } from "node:fs/promises";
1383
+ class FolderLoader {
1384
+ async canLoad(source) {
1385
+ try {
1386
+ const stats = await stat(source);
1387
+ if (!stats.isDirectory()) {
1388
+ return false;
1389
+ }
1390
+ const manifestPath = join(source, "resource.json");
1391
+ const manifestStats = await stat(manifestPath);
1392
+ return manifestStats.isFile();
1393
+ } catch {
1394
+ return false;
1395
+ }
1396
+ }
1397
+ async load(folderPath) {
1398
+ const resourceJsonPath = join(folderPath, "resource.json");
1399
+ let resourceJson;
1400
+ try {
1401
+ resourceJson = await readFile2(resourceJsonPath, "utf-8");
1402
+ } catch (error) {
1403
+ throw new ResourceXError(`Failed to read resource.json: ${error instanceof Error ? error.message : String(error)}`);
1404
+ }
1405
+ let json;
1406
+ try {
1407
+ json = JSON.parse(resourceJson);
1408
+ } catch (error) {
1409
+ throw new ResourceXError(`Invalid JSON in resource.json: ${error instanceof Error ? error.message : String(error)}`);
1410
+ }
1411
+ const rxd = define(json);
1412
+ const files = await this.readFolderFiles(folderPath);
1413
+ if (Object.keys(files).length === 0) {
1414
+ throw new ResourceXError("No content files found in resource folder");
1415
+ }
1416
+ const rxm = manifest(rxd);
1417
+ const rxa = await archive(files);
1418
+ return resource(rxm, rxa);
1419
+ }
1420
+ async readFolderFiles(folderPath, basePath = folderPath) {
1421
+ const files = {};
1422
+ const entries = await readdir(folderPath, { withFileTypes: true });
1423
+ for (const entry of entries) {
1424
+ const fullPath = join(folderPath, entry.name);
1425
+ const relativePath = relative(basePath, fullPath);
1426
+ if (relativePath === "resource.json") {
1427
+ continue;
1428
+ }
1429
+ if (entry.isFile()) {
1430
+ files[relativePath] = await readFile2(fullPath);
1431
+ } else if (entry.isDirectory()) {
1432
+ const subFiles = await this.readFolderFiles(fullPath, basePath);
1433
+ Object.assign(files, subFiles);
1434
+ }
1435
+ }
1436
+ return files;
1437
+ }
1438
+ }
1439
+ // src/loader/loadResource.ts
1440
+ async function loadResource(source, config) {
1441
+ const loader = config?.loader ?? new FolderLoader;
1442
+ const canLoad = await loader.canLoad(source);
1443
+ if (!canLoad) {
1444
+ throw new ResourceXError(`Cannot load resource from: ${source}`);
1445
+ }
1446
+ return loader.load(source);
1447
+ }
1448
+ // src/registry/errors.ts
1449
+ class RegistryError extends ResourceXError {
1450
+ constructor(message, options) {
1451
+ super(message, options);
1452
+ this.name = "RegistryError";
1453
+ }
1454
+ }
1455
+
1456
+ // src/registry/registries/CASRegistry.ts
1457
+ class CASRegistry {
1458
+ rxaStore;
1459
+ rxmStore;
1460
+ constructor(rxaStore, rxmStore) {
1461
+ this.rxaStore = rxaStore;
1462
+ this.rxmStore = rxmStore;
1463
+ }
1464
+ async get(rxl) {
1465
+ const tag = rxl.tag ?? "latest";
1466
+ const storedRxm = await this.rxmStore.get(rxl.name, tag, rxl.registry);
1467
+ if (!storedRxm) {
1468
+ throw new RegistryError(`Resource not found: ${format(rxl)}`);
1469
+ }
1470
+ const files = {};
1471
+ for (const [filename, digest] of Object.entries(storedRxm.files)) {
1472
+ files[filename] = await this.rxaStore.get(digest);
1473
+ }
1474
+ const rxm = {
1475
+ registry: storedRxm.registry,
1476
+ path: storedRxm.path,
1477
+ name: storedRxm.name,
1478
+ type: storedRxm.type,
1479
+ tag: storedRxm.tag,
1480
+ files: Object.keys(storedRxm.files)
1481
+ };
1482
+ const rxa = await archive(files);
1483
+ return resource(rxm, rxa);
1484
+ }
1485
+ async put(rxr) {
1486
+ const files = await extract(rxr.archive);
1487
+ const fileDigests = {};
1488
+ for (const [filename, content] of Object.entries(files)) {
1489
+ const digest = await this.rxaStore.put(content);
1490
+ fileDigests[filename] = digest;
1491
+ }
1492
+ const storedRxm = {
1493
+ registry: rxr.manifest.registry,
1494
+ path: rxr.manifest.path,
1495
+ name: rxr.manifest.name,
1496
+ type: rxr.manifest.type,
1497
+ tag: rxr.manifest.tag,
1498
+ files: fileDigests,
1499
+ createdAt: new Date,
1500
+ updatedAt: new Date
1501
+ };
1502
+ await this.rxmStore.put(storedRxm);
1503
+ }
1504
+ async has(rxl) {
1505
+ const tag = rxl.tag ?? "latest";
1506
+ return this.rxmStore.has(rxl.name, tag, rxl.registry);
1507
+ }
1508
+ async remove(rxl) {
1509
+ const tag = rxl.tag ?? "latest";
1510
+ await this.rxmStore.delete(rxl.name, tag, rxl.registry);
1511
+ }
1512
+ async list(options) {
1513
+ const { query, limit, offset = 0 } = options ?? {};
1514
+ const manifests = await this.rxmStore.search({
1515
+ query,
1516
+ limit,
1517
+ offset
1518
+ });
1519
+ return manifests.map((m) => ({
1520
+ registry: m.registry,
1521
+ path: m.path,
1522
+ name: m.name,
1523
+ tag: m.tag
1524
+ }));
1525
+ }
1526
+ async clearCache(registry) {
1527
+ if (registry) {
1528
+ await this.rxmStore.deleteByRegistry(registry);
1529
+ } else {
1530
+ const cached = await this.rxmStore.search({ registry: undefined });
1531
+ for (const m of cached) {
1532
+ if (m.registry) {
1533
+ await this.rxmStore.delete(m.name, m.tag, m.registry);
1534
+ }
1535
+ }
1536
+ }
1537
+ }
1538
+ async gc() {
1539
+ const referenced = new Set;
1540
+ const allManifests = await this.rxmStore.search({});
1541
+ for (const m of allManifests) {
1542
+ for (const digest of Object.values(m.files)) {
1543
+ referenced.add(digest);
1544
+ }
1545
+ }
1546
+ let deleted = 0;
1547
+ const allDigests = await this.rxaStore.list();
1548
+ for (const digest of allDigests) {
1549
+ if (!referenced.has(digest)) {
1550
+ await this.rxaStore.delete(digest);
1551
+ deleted++;
1552
+ }
1553
+ }
1554
+ return deleted;
1555
+ }
1556
+ async hasBlob(digest) {
1557
+ return this.rxaStore.has(digest);
1558
+ }
1559
+ async getBlob(digest) {
1560
+ return this.rxaStore.get(digest);
1561
+ }
1562
+ async putBlob(data) {
1563
+ return this.rxaStore.put(data);
1564
+ }
1565
+ }
1566
+ // src/registry/registries/LinkedRegistry.ts
1567
+ import { join as join2, resolve as resolvePath } from "node:path";
1568
+ import { symlink, lstat, readlink, rm, mkdir, readdir as readdir2 } from "node:fs/promises";
1569
+ class LinkedRegistry {
1570
+ basePath;
1571
+ constructor(basePath) {
1572
+ this.basePath = basePath;
1573
+ }
1574
+ buildLinkPath(rxl) {
1575
+ const registry = rxl.registry ?? "localhost";
1576
+ const tag = rxl.tag ?? "latest";
1577
+ let linkPath = join2(this.basePath, registry);
1578
+ if (rxl.path) {
1579
+ linkPath = join2(linkPath, rxl.path);
1580
+ }
1581
+ return join2(linkPath, rxl.name, tag);
1582
+ }
1583
+ async isSymlink(path) {
1584
+ try {
1585
+ const stats = await lstat(path);
1586
+ return stats.isSymbolicLink();
1587
+ } catch {
1588
+ return false;
1589
+ }
1590
+ }
1591
+ async get(rxl) {
1592
+ const linkPath = this.buildLinkPath(rxl);
1593
+ if (!await this.isSymlink(linkPath)) {
1594
+ throw new RegistryError(`Linked resource not found: ${format(rxl)}`);
1595
+ }
1596
+ const targetPath = await readlink(linkPath);
1597
+ return loadResource(targetPath);
1598
+ }
1599
+ async put(_rxr) {
1600
+ throw new RegistryError("LinkedRegistry does not support put(). Use link() instead.");
1601
+ }
1602
+ async has(rxl) {
1603
+ const linkPath = this.buildLinkPath(rxl);
1604
+ return this.isSymlink(linkPath);
1605
+ }
1606
+ async remove(rxl) {
1607
+ const linkPath = this.buildLinkPath(rxl);
1608
+ if (await this.isSymlink(linkPath)) {
1609
+ await rm(linkPath);
1610
+ }
1611
+ }
1612
+ async list(options) {
1613
+ const { query, limit, offset = 0 } = options ?? {};
1614
+ const locators = [];
1615
+ try {
1616
+ await this.scanSymlinks(this.basePath, "", locators);
1617
+ } catch {
1618
+ return [];
1619
+ }
1620
+ let filtered = locators;
1621
+ if (query) {
1622
+ const lowerQuery = query.toLowerCase();
1623
+ filtered = locators.filter((rxl) => {
1624
+ const searchText = `${rxl.registry ?? ""} ${rxl.path ?? ""} ${rxl.name}`.toLowerCase();
1625
+ return searchText.includes(lowerQuery);
1626
+ });
1627
+ }
1628
+ let result = filtered.slice(offset);
1629
+ if (limit !== undefined) {
1630
+ result = result.slice(0, limit);
1631
+ }
1632
+ return result;
1633
+ }
1634
+ async link(devPath) {
1635
+ const rxr = await loadResource(devPath);
1636
+ const linkPath = this.buildLinkPath(rxr.locator);
1637
+ try {
1638
+ const stats = await lstat(linkPath);
1639
+ if (stats.isSymbolicLink() || stats.isDirectory()) {
1640
+ await rm(linkPath, { recursive: true });
1641
+ }
1642
+ } catch {}
1643
+ const parentPath = join2(linkPath, "..");
1644
+ await mkdir(parentPath, { recursive: true });
1645
+ const absolutePath = resolvePath(devPath);
1646
+ await symlink(absolutePath, linkPath);
1647
+ return rxr.locator;
1648
+ }
1649
+ async unlink(rxl) {
1650
+ return this.remove(rxl);
1651
+ }
1652
+ async scanSymlinks(dirPath, relativePath, locators) {
1653
+ let entries;
1654
+ try {
1655
+ entries = await readdir2(dirPath);
1656
+ } catch {
1657
+ return;
1658
+ }
1659
+ for (const entry of entries) {
1660
+ const fullPath = join2(dirPath, entry);
1661
+ const relPath = relativePath ? `${relativePath}/${entry}` : entry;
1662
+ try {
1663
+ const stats = await lstat(fullPath);
1664
+ if (stats.isSymbolicLink()) {
1665
+ const rxl = this.parsePathToRXL(relPath);
1666
+ if (rxl) {
1667
+ locators.push(rxl);
1668
+ }
1669
+ } else if (stats.isDirectory()) {
1670
+ await this.scanSymlinks(fullPath, relPath, locators);
1671
+ }
1672
+ } catch {}
1673
+ }
1674
+ }
1675
+ parsePathToRXL(relPath) {
1676
+ const parts = relPath.split("/");
1677
+ if (parts.length < 3) {
1678
+ return null;
1679
+ }
1680
+ const tag = parts.pop();
1681
+ const name = parts.pop();
1682
+ const registry = parts.shift();
1683
+ const path = parts.length > 0 ? parts.join("/") : undefined;
1684
+ let locatorStr = registry;
1685
+ if (path)
1686
+ locatorStr += `/${path}`;
1687
+ locatorStr += `/${name}`;
1688
+ if (tag !== "latest")
1689
+ locatorStr += `:${tag}`;
1690
+ try {
1691
+ return parse(locatorStr);
1692
+ } catch {
1693
+ return null;
1694
+ }
1695
+ }
1696
+ }
1697
+ // src/registry/store/digest.ts
1698
+ import { createHash } from "node:crypto";
1699
+ function computeDigest(data) {
1700
+ const hash = createHash("sha256").update(data).digest("hex");
1701
+ return `sha256:${hash}`;
1702
+ }
1703
+ function isValidDigest(digest) {
1704
+ return /^sha256:[a-f0-9]{64}$/.test(digest);
1705
+ }
1706
+ // src/registry/store/MemoryRXAStore.ts
1707
+ class MemoryRXAStore {
1708
+ blobs = new Map;
1709
+ async get(digest) {
1710
+ const blob = this.blobs.get(digest);
1711
+ if (!blob) {
1712
+ throw new RegistryError(`Blob not found: ${digest}`);
1713
+ }
1714
+ return blob;
1715
+ }
1716
+ async put(data) {
1717
+ const digest = computeDigest(data);
1718
+ if (!this.blobs.has(digest)) {
1719
+ this.blobs.set(digest, data);
1720
+ }
1721
+ return digest;
1722
+ }
1723
+ async has(digest) {
1724
+ return this.blobs.has(digest);
1725
+ }
1726
+ async delete(digest) {
1727
+ this.blobs.delete(digest);
1728
+ }
1729
+ async list() {
1730
+ return Array.from(this.blobs.keys());
1731
+ }
1732
+ clear() {
1733
+ this.blobs.clear();
1734
+ }
1735
+ }
1736
+ // src/registry/store/MemoryRXMStore.ts
1737
+ class MemoryRXMStore {
1738
+ manifests = new Map;
1739
+ buildKey(name, tag, registry) {
1740
+ return registry ? `${registry}/${name}:${tag}` : `${name}:${tag}`;
1741
+ }
1742
+ async get(name, tag, registry) {
1743
+ const key = this.buildKey(name, tag, registry);
1744
+ return this.manifests.get(key) ?? null;
1745
+ }
1746
+ async put(manifest2) {
1747
+ const key = this.buildKey(manifest2.name, manifest2.tag, manifest2.registry);
1748
+ this.manifests.set(key, {
1749
+ ...manifest2,
1750
+ updatedAt: new Date
1751
+ });
1752
+ }
1753
+ async has(name, tag, registry) {
1754
+ const key = this.buildKey(name, tag, registry);
1755
+ return this.manifests.has(key);
1756
+ }
1757
+ async delete(name, tag, registry) {
1758
+ const key = this.buildKey(name, tag, registry);
1759
+ this.manifests.delete(key);
1760
+ }
1761
+ async listTags(name, registry) {
1762
+ const tags = [];
1763
+ for (const m of this.manifests.values()) {
1764
+ if (m.name === name && m.registry === registry) {
1765
+ tags.push(m.tag);
1766
+ }
1767
+ }
1768
+ return tags;
1769
+ }
1770
+ async listNames(registry, query) {
1771
+ const names = new Set;
1772
+ for (const m of this.manifests.values()) {
1773
+ if (registry !== undefined && m.registry !== registry)
1774
+ continue;
1775
+ if (query && !m.name.toLowerCase().includes(query.toLowerCase()))
1776
+ continue;
1777
+ names.add(m.name);
1778
+ }
1779
+ return Array.from(names);
1780
+ }
1781
+ async search(options) {
1782
+ const { registry, query, limit, offset = 0 } = options ?? {};
1783
+ let results = Array.from(this.manifests.values());
1784
+ if (registry !== undefined) {
1785
+ if (registry === null) {
1786
+ results = results.filter((m) => !m.registry);
1787
+ } else {
1788
+ results = results.filter((m) => m.registry === registry);
1789
+ }
1790
+ }
1791
+ if (query) {
1792
+ const lowerQuery = query.toLowerCase();
1793
+ results = results.filter((m) => m.name.toLowerCase().includes(lowerQuery));
1794
+ }
1795
+ results = results.slice(offset);
1796
+ if (limit !== undefined) {
1797
+ results = results.slice(0, limit);
1798
+ }
1799
+ return results;
1800
+ }
1801
+ async deleteByRegistry(registry) {
1802
+ for (const [key, m] of this.manifests.entries()) {
1803
+ if (m.registry === registry) {
1804
+ this.manifests.delete(key);
1805
+ }
1806
+ }
1807
+ }
1808
+ clear() {
1809
+ this.manifests.clear();
1810
+ }
1811
+ }
1812
+ // src/registry/discovery.ts
1813
+ async function discoverRegistry(domain) {
1814
+ const wellKnownUrl = `https://${domain}/.well-known/resourcex`;
1815
+ try {
1816
+ const response = await fetch(wellKnownUrl);
1817
+ if (!response.ok) {
1818
+ throw new RegistryError(`Well-known discovery failed for ${domain}: ${response.statusText}`);
1819
+ }
1820
+ const data = await response.json();
1821
+ if (!data.registries || !Array.isArray(data.registries) || data.registries.length === 0) {
1822
+ throw new RegistryError(`Invalid well-known response for ${domain}: missing or empty registries`);
1823
+ }
1824
+ return {
1825
+ domain,
1826
+ registries: data.registries
1827
+ };
1828
+ } catch (error) {
1829
+ if (error instanceof RegistryError) {
1830
+ throw error;
1831
+ }
1832
+ throw new RegistryError(`Failed to discover registry for ${domain}: ${error.message}`);
1833
+ }
1834
+ }
1835
+ // src/registry/middleware/RegistryMiddleware.ts
1836
+ class RegistryMiddleware {
1837
+ inner;
1838
+ constructor(inner) {
1839
+ this.inner = inner;
1840
+ }
1841
+ get(rxl) {
1842
+ return this.inner.get(rxl);
1843
+ }
1844
+ put(rxr) {
1845
+ return this.inner.put(rxr);
1846
+ }
1847
+ has(rxl) {
1848
+ return this.inner.has(rxl);
1849
+ }
1850
+ remove(rxl) {
1851
+ return this.inner.remove(rxl);
1852
+ }
1853
+ list(options) {
1854
+ return this.inner.list(options);
1855
+ }
1856
+ }
1857
+ // src/registry/middleware/DomainValidation.ts
1858
+ class RegistryValidation extends RegistryMiddleware {
1859
+ trustedRegistry;
1860
+ constructor(inner, trustedRegistry) {
1861
+ super(inner);
1862
+ this.trustedRegistry = trustedRegistry;
1863
+ }
1864
+ validateRegistry(rxr) {
1865
+ if (rxr.manifest.registry !== this.trustedRegistry) {
1866
+ throw new RegistryError(`Untrusted registry: resource claims "${rxr.manifest.registry}" but registry only trusts "${this.trustedRegistry}"`);
1867
+ }
1868
+ }
1869
+ async get(rxl) {
1870
+ const rxr = await this.inner.get(rxl);
1871
+ this.validateRegistry(rxr);
1872
+ return rxr;
1873
+ }
1874
+ }
1875
+ function withRegistryValidation(registry, trustedRegistry) {
1876
+ return new RegistryValidation(registry, trustedRegistry);
1877
+ }
1878
+ var DomainValidation = RegistryValidation;
1879
+ var withDomainValidation = withRegistryValidation;
1232
1880
  export {
1233
1881
  wrap,
1882
+ withDomainValidation,
1883
+ textType,
1234
1884
  resource,
1235
1885
  parse,
1236
1886
  manifest,
1237
1887
  locate,
1888
+ loadResource,
1889
+ jsonType,
1890
+ isValidDigest,
1238
1891
  format,
1239
1892
  extract,
1893
+ discoverRegistry,
1240
1894
  define,
1895
+ computeDigest,
1896
+ bundleResourceType,
1897
+ builtinTypes,
1898
+ binaryType,
1241
1899
  archive,
1900
+ TypeHandlerChain,
1242
1901
  ResourceXError,
1902
+ ResourceTypeError,
1903
+ RegistryMiddleware,
1904
+ RegistryError,
1905
+ MemoryRXMStore,
1906
+ MemoryRXAStore,
1243
1907
  ManifestError,
1244
1908
  LocatorError,
1909
+ LinkedRegistry,
1910
+ FolderLoader,
1911
+ DomainValidation,
1245
1912
  DefinitionError,
1246
- ContentError
1913
+ ContentError,
1914
+ CASRegistry
1247
1915
  };
1248
1916
 
1249
- //# debugId=E36D0778C816F02964756E2164756E21
1917
+ //# debugId=E62BE3673C4E081E64756E2164756E21